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