1239313Sdim//===--- CommentCommandTraits.cpp - Comment command properties --*- C++ -*-===// 2239313Sdim// 3239313Sdim// The LLVM Compiler Infrastructure 4239313Sdim// 5239313Sdim// This file is distributed under the University of Illinois Open Source 6239313Sdim// License. See LICENSE.TXT for details. 7239313Sdim// 8239313Sdim//===----------------------------------------------------------------------===// 9239313Sdim 10239313Sdim#include "clang/AST/CommentCommandTraits.h" 11243830Sdim#include "llvm/ADT/STLExtras.h" 12239313Sdim 13239313Sdimnamespace clang { 14239313Sdimnamespace comments { 15239313Sdim 16243830Sdim#include "clang/AST/CommentCommandInfo.inc" 17239313Sdim 18249423SdimCommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator, 19249423Sdim const CommentOptions &CommentOptions) : 20249423Sdim NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) { 21249423Sdim registerCommentOptions(CommentOptions); 22249423Sdim} 23239313Sdim 24249423Sdimvoid CommandTraits::registerCommentOptions( 25249423Sdim const CommentOptions &CommentOptions) { 26249423Sdim for (CommentOptions::BlockCommandNamesTy::const_iterator 27249423Sdim I = CommentOptions.BlockCommandNames.begin(), 28249423Sdim E = CommentOptions.BlockCommandNames.end(); 29249423Sdim I != E; I++) { 30249423Sdim registerBlockCommand(*I); 31249423Sdim } 32249423Sdim} 33249423Sdim 34243830Sdimconst CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const { 35243830Sdim if (const CommandInfo *Info = getBuiltinCommandInfo(Name)) 36243830Sdim return Info; 37243830Sdim return getRegisteredCommandInfo(Name); 38243830Sdim} 39239313Sdim 40243830Sdimconst CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const { 41243830Sdim if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID)) 42243830Sdim return Info; 43243830Sdim return getRegisteredCommandInfo(CommandID); 44239313Sdim} 45239313Sdim 46263508Sdimstatic void 47263508SdimHelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand, 48263508Sdim StringRef Typo, const CommandInfo *Command) { 49263508Sdim const unsigned MaxEditDistance = 1; 50263508Sdim unsigned BestEditDistance = MaxEditDistance + 1; 51263508Sdim StringRef Name = Command->Name; 52263508Sdim 53263508Sdim unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size()); 54263508Sdim if (MinPossibleEditDistance > 0 && 55263508Sdim Typo.size() / MinPossibleEditDistance < 1) 56263508Sdim return; 57263508Sdim unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance); 58263508Sdim if (EditDistance > MaxEditDistance) 59263508Sdim return; 60263508Sdim if (EditDistance == BestEditDistance) 61263508Sdim BestCommand.push_back(Command); 62263508Sdim else if (EditDistance < BestEditDistance) { 63263508Sdim BestCommand.clear(); 64263508Sdim BestCommand.push_back(Command); 65263508Sdim BestEditDistance = EditDistance; 66263508Sdim } 67263508Sdim} 68263508Sdim 69263508Sdimconst CommandInfo * 70263508SdimCommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const { 71263508Sdim // single character command impostures, such as \t or \n must not go 72263508Sdim // through the fixit logic. 73263508Sdim if (Typo.size() <= 1) 74263508Sdim return NULL; 75263508Sdim 76263508Sdim SmallVector<const CommandInfo *, 2> BestCommand; 77263508Sdim 78263508Sdim const int NumOfCommands = llvm::array_lengthof(Commands); 79263508Sdim for (int i = 0; i < NumOfCommands; i++) 80263508Sdim HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]); 81263508Sdim 82263508Sdim for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) 83263508Sdim if (!RegisteredCommands[i]->IsUnknownCommand) 84263508Sdim HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]); 85263508Sdim 86263508Sdim return (BestCommand.size() != 1) ? NULL : BestCommand[0]; 87263508Sdim} 88263508Sdim 89249423SdimCommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) { 90243830Sdim char *Name = Allocator.Allocate<char>(CommandName.size() + 1); 91243830Sdim memcpy(Name, CommandName.data(), CommandName.size()); 92243830Sdim Name[CommandName.size()] = '\0'; 93239313Sdim 94243830Sdim // Value-initialize (=zero-initialize in this case) a new CommandInfo. 95243830Sdim CommandInfo *Info = new (Allocator) CommandInfo(); 96243830Sdim Info->Name = Name; 97243830Sdim Info->ID = NextID++; 98239313Sdim 99243830Sdim RegisteredCommands.push_back(Info); 100239313Sdim 101243830Sdim return Info; 102239313Sdim} 103239313Sdim 104249423Sdimconst CommandInfo *CommandTraits::registerUnknownCommand( 105249423Sdim StringRef CommandName) { 106249423Sdim CommandInfo *Info = createCommandInfoWithName(CommandName); 107249423Sdim Info->IsUnknownCommand = true; 108249423Sdim return Info; 109249423Sdim} 110249423Sdim 111249423Sdimconst CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) { 112249423Sdim CommandInfo *Info = createCommandInfoWithName(CommandName); 113249423Sdim Info->IsBlockCommand = true; 114249423Sdim return Info; 115249423Sdim} 116249423Sdim 117243830Sdimconst CommandInfo *CommandTraits::getBuiltinCommandInfo( 118243830Sdim unsigned CommandID) { 119243830Sdim if (CommandID < llvm::array_lengthof(Commands)) 120243830Sdim return &Commands[CommandID]; 121243830Sdim return NULL; 122239313Sdim} 123239313Sdim 124243830Sdimconst CommandInfo *CommandTraits::getRegisteredCommandInfo( 125243830Sdim StringRef Name) const { 126243830Sdim for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) { 127243830Sdim if (RegisteredCommands[i]->Name == Name) 128243830Sdim return RegisteredCommands[i]; 129243830Sdim } 130243830Sdim return NULL; 131239313Sdim} 132239313Sdim 133243830Sdimconst CommandInfo *CommandTraits::getRegisteredCommandInfo( 134243830Sdim unsigned CommandID) const { 135243830Sdim return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)]; 136239313Sdim} 137239313Sdim 138239313Sdim} // end namespace comments 139239313Sdim} // end namespace clang 140239313Sdim 141