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