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 : NextID(std::size(Commands)), Allocator(Allocator) { 21 registerCommentOptions(CommentOptions); 22 } 23 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 34 const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const { 35 if (const CommandInfo *Info = getBuiltinCommandInfo(Name)) 36 return Info; 37 return getRegisteredCommandInfo(Name); 38 } 39 40 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 * 47 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 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 103 const CommandInfo *CommandTraits::registerUnknownCommand( 104 StringRef CommandName) { 105 CommandInfo *Info = createCommandInfoWithName(CommandName); 106 Info->IsUnknownCommand = true; 107 return Info; 108 } 109 110 const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) { 111 CommandInfo *Info = createCommandInfoWithName(CommandName); 112 Info->IsBlockCommand = true; 113 return Info; 114 } 115 116 const CommandInfo *CommandTraits::getBuiltinCommandInfo( 117 unsigned CommandID) { 118 if (CommandID < std::size(Commands)) 119 return &Commands[CommandID]; 120 return nullptr; 121 } 122 123 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 132 const CommandInfo *CommandTraits::getRegisteredCommandInfo( 133 unsigned CommandID) const { 134 return RegisteredCommands[CommandID - std::size(Commands)]; 135 } 136 137 } // end namespace comments 138 } // end namespace clang 139 140