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