• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  //===--- CommentCommandTraits.cpp - Comment command properties --*- C++ -*-===//
2  //
3  //                     The LLVM Compiler Infrastructure
4  //
5  // This file is distributed under the University of Illinois Open Source
6  // License. See LICENSE.TXT for details.
7  //
8  //===----------------------------------------------------------------------===//
9  
10  #include "clang/AST/CommentCommandTraits.h"
11  #include "llvm/ADT/STLExtras.h"
12  
13  namespace clang {
14  namespace comments {
15  
16  #include "clang/AST/CommentCommandInfo.inc"
17  
CommandTraits(llvm::BumpPtrAllocator & Allocator,const CommentOptions & CommentOptions)18  CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
19                               const CommentOptions &CommentOptions) :
20      NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
21    registerCommentOptions(CommentOptions);
22  }
23  
registerCommentOptions(const CommentOptions & CommentOptions)24  void CommandTraits::registerCommentOptions(
25      const CommentOptions &CommentOptions) {
26    for (CommentOptions::BlockCommandNamesTy::const_iterator
27             I = CommentOptions.BlockCommandNames.begin(),
28             E = CommentOptions.BlockCommandNames.end();
29         I != E; I++) {
30      registerBlockCommand(*I);
31    }
32  }
33  
getCommandInfoOrNULL(StringRef Name) const34  const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
35    if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
36      return Info;
37    return getRegisteredCommandInfo(Name);
38  }
39  
getCommandInfo(unsigned CommandID) const40  const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
41    if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID))
42      return Info;
43    return getRegisteredCommandInfo(CommandID);
44  }
45  
46  const CommandInfo *
getTypoCorrectCommandInfo(StringRef Typo) const47  CommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {
48    // Single-character command impostures, such as \t or \n, should not go
49    // through the fixit logic.
50    if (Typo.size() <= 1)
51      return nullptr;
52  
53    // The maximum edit distance we're prepared to accept.
54    const unsigned MaxEditDistance = 1;
55  
56    unsigned BestEditDistance = MaxEditDistance;
57    SmallVector<const CommandInfo *, 2> BestCommand;
58  
59    auto ConsiderCorrection = [&](const CommandInfo *Command) {
60      StringRef Name = Command->Name;
61  
62      unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
63      if (MinPossibleEditDistance <= BestEditDistance) {
64        unsigned EditDistance = Typo.edit_distance(Name, true, BestEditDistance);
65        if (EditDistance < BestEditDistance) {
66          BestEditDistance = EditDistance;
67          BestCommand.clear();
68        }
69        if (EditDistance == BestEditDistance)
70          BestCommand.push_back(Command);
71      }
72    };
73  
74    for (const auto &Command : Commands)
75      ConsiderCorrection(&Command);
76  
77    for (const auto *Command : RegisteredCommands)
78      if (!Command->IsUnknownCommand)
79        ConsiderCorrection(Command);
80  
81    return BestCommand.size() == 1 ? BestCommand[0] : nullptr;
82  }
83  
createCommandInfoWithName(StringRef CommandName)84  CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
85    char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
86    memcpy(Name, CommandName.data(), CommandName.size());
87    Name[CommandName.size()] = '\0';
88  
89    // Value-initialize (=zero-initialize in this case) a new CommandInfo.
90    CommandInfo *Info = new (Allocator) CommandInfo();
91    Info->Name = Name;
92    // We only have a limited number of bits to encode command IDs in the
93    // CommandInfo structure, so the ID numbers can potentially wrap around.
94    assert((NextID < (1 << CommandInfo::NumCommandIDBits))
95           && "Too many commands. We have limited bits for the command ID.");
96    Info->ID = NextID++;
97  
98    RegisteredCommands.push_back(Info);
99  
100    return Info;
101  }
102  
registerUnknownCommand(StringRef CommandName)103  const CommandInfo *CommandTraits::registerUnknownCommand(
104                                                    StringRef CommandName) {
105    CommandInfo *Info = createCommandInfoWithName(CommandName);
106    Info->IsUnknownCommand = true;
107    return Info;
108  }
109  
registerBlockCommand(StringRef CommandName)110  const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
111    CommandInfo *Info = createCommandInfoWithName(CommandName);
112    Info->IsBlockCommand = true;
113    return Info;
114  }
115  
getBuiltinCommandInfo(unsigned CommandID)116  const CommandInfo *CommandTraits::getBuiltinCommandInfo(
117                                                    unsigned CommandID) {
118    if (CommandID < llvm::array_lengthof(Commands))
119      return &Commands[CommandID];
120    return nullptr;
121  }
122  
getRegisteredCommandInfo(StringRef Name) const123  const CommandInfo *CommandTraits::getRegisteredCommandInfo(
124                                                    StringRef Name) const {
125    for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) {
126      if (RegisteredCommands[i]->Name == Name)
127        return RegisteredCommands[i];
128    }
129    return nullptr;
130  }
131  
getRegisteredCommandInfo(unsigned CommandID) const132  const CommandInfo *CommandTraits::getRegisteredCommandInfo(
133                                                    unsigned CommandID) const {
134    return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)];
135  }
136  
137  } // end namespace comments
138  } // end namespace clang
139  
140