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 13namespace clang { 14namespace comments { 15 16#include "clang/AST/CommentCommandInfo.inc" 17 18CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator, 19 const CommentOptions &CommentOptions) : 20 NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) { 21 registerCommentOptions(CommentOptions); 22} 23 24void 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 34const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const { 35 if (const CommandInfo *Info = getBuiltinCommandInfo(Name)) 36 return Info; 37 return getRegisteredCommandInfo(Name); 38} 39 40const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const { 41 if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID)) 42 return Info; 43 return getRegisteredCommandInfo(CommandID); 44} 45 46const CommandInfo * 47CommandTraits::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 84CommandInfo *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 Info->ID = NextID++; 93 94 RegisteredCommands.push_back(Info); 95 96 return Info; 97} 98 99const CommandInfo *CommandTraits::registerUnknownCommand( 100 StringRef CommandName) { 101 CommandInfo *Info = createCommandInfoWithName(CommandName); 102 Info->IsUnknownCommand = true; 103 return Info; 104} 105 106const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) { 107 CommandInfo *Info = createCommandInfoWithName(CommandName); 108 Info->IsBlockCommand = true; 109 return Info; 110} 111 112const CommandInfo *CommandTraits::getBuiltinCommandInfo( 113 unsigned CommandID) { 114 if (CommandID < llvm::array_lengthof(Commands)) 115 return &Commands[CommandID]; 116 return nullptr; 117} 118 119const CommandInfo *CommandTraits::getRegisteredCommandInfo( 120 StringRef Name) const { 121 for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) { 122 if (RegisteredCommands[i]->Name == Name) 123 return RegisteredCommands[i]; 124 } 125 return nullptr; 126} 127 128const CommandInfo *CommandTraits::getRegisteredCommandInfo( 129 unsigned CommandID) const { 130 return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)]; 131} 132 133} // end namespace comments 134} // end namespace clang 135 136