1aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko//===--- CommentCommandTraits.cpp - Comment command properties --*- C++ -*-===//
2aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko//
3aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko//                     The LLVM Compiler Infrastructure
4aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko//
5aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko// This file is distributed under the University of Illinois Open Source
6aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko// License. See LICENSE.TXT for details.
7aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko//
8aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko//===----------------------------------------------------------------------===//
9aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
10aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko#include "clang/AST/CommentCommandTraits.h"
11e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko#include "llvm/ADT/STLExtras.h"
12aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
13aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenkonamespace clang {
14aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenkonamespace comments {
15aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
16e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko#include "clang/AST/CommentCommandInfo.inc"
17aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
186ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri GribenkoCommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
196ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko                             const CommentOptions &CommentOptions) :
206ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko    NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
216ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  registerCommentOptions(CommentOptions);
226ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko}
236ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko
246ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenkovoid CommandTraits::registerCommentOptions(
256ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko    const CommentOptions &CommentOptions) {
266ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  for (CommentOptions::BlockCommandNamesTy::const_iterator
276ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko           I = CommentOptions.BlockCommandNames.begin(),
286ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko           E = CommentOptions.BlockCommandNames.end();
296ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko       I != E; I++) {
306ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko    registerBlockCommand(*I);
316ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  }
326ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko}
33aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
34e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenkoconst CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
35e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
36e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko    return Info;
37e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  return getRegisteredCommandInfo(Name);
38aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko}
39aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
40e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenkoconst CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
41e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID))
42e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko    return Info;
43e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  return getRegisteredCommandInfo(CommandID);
44e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko}
45aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
46ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanianstatic void
47ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz JahanianHelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand,
48ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian                             StringRef Typo, const CommandInfo *Command) {
490089bc4ddee6bb309ad25f4c7ad4b7ffe5df4512Fariborz Jahanian  const unsigned MaxEditDistance = 1;
500089bc4ddee6bb309ad25f4c7ad4b7ffe5df4512Fariborz Jahanian  unsigned BestEditDistance = MaxEditDistance + 1;
51ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  StringRef Name = Command->Name;
52ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian
53ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
54ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  if (MinPossibleEditDistance > 0 &&
55ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian      Typo.size() / MinPossibleEditDistance < 1)
56ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian    return;
57ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
58ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  if (EditDistance > MaxEditDistance)
59ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian    return;
60ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  if (EditDistance == BestEditDistance)
61ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian    BestCommand.push_back(Command);
62ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  else if (EditDistance < BestEditDistance) {
63ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian    BestCommand.clear();
64ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian    BestCommand.push_back(Command);
65ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian    BestEditDistance = EditDistance;
66ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  }
67ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian}
68ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian
69ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanianconst CommandInfo *
70ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz JahanianCommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {
71f4030ae4638d1831a2a031f1e33b86de8c5fef28Fariborz Jahanian  // single character command impostures, such as \t or \n must not go
72f4030ae4638d1831a2a031f1e33b86de8c5fef28Fariborz Jahanian  // through the fixit logic.
73f4030ae4638d1831a2a031f1e33b86de8c5fef28Fariborz Jahanian  if (Typo.size() <= 1)
74f4030ae4638d1831a2a031f1e33b86de8c5fef28Fariborz Jahanian    return NULL;
75f4030ae4638d1831a2a031f1e33b86de8c5fef28Fariborz Jahanian
760089bc4ddee6bb309ad25f4c7ad4b7ffe5df4512Fariborz Jahanian  SmallVector<const CommandInfo *, 2> BestCommand;
770089bc4ddee6bb309ad25f4c7ad4b7ffe5df4512Fariborz Jahanian
78b960232518a1cd79c5f64ab5ef54c88e34660191Craig Topper  const int NumOfCommands = llvm::array_lengthof(Commands);
79ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  for (int i = 0; i < NumOfCommands; i++)
80ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian    HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]);
81ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian
82ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian  for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i)
83ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian    if (!RegisteredCommands[i]->IsUnknownCommand)
84ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian      HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]);
85ad91e5431f2f2d0a32ccdff8c55e7fa921af42bdFariborz Jahanian
860089bc4ddee6bb309ad25f4c7ad4b7ffe5df4512Fariborz Jahanian  return (BestCommand.size() != 1) ? NULL : BestCommand[0];
870089bc4ddee6bb309ad25f4c7ad4b7ffe5df4512Fariborz Jahanian}
880089bc4ddee6bb309ad25f4c7ad4b7ffe5df4512Fariborz Jahanian
896ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri GribenkoCommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
90116bb09882bc1c9281cd84dd07496201feb18d18Eli Friedman  char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
91e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  memcpy(Name, CommandName.data(), CommandName.size());
92116bb09882bc1c9281cd84dd07496201feb18d18Eli Friedman  Name[CommandName.size()] = '\0';
93aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
94e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  // Value-initialize (=zero-initialize in this case) a new CommandInfo.
95e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  CommandInfo *Info = new (Allocator) CommandInfo();
96e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  Info->Name = Name;
97e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  Info->ID = NextID++;
98aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
99e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  RegisteredCommands.push_back(Info);
100aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
101e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  return Info;
102aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko}
103aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
1046ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenkoconst CommandInfo *CommandTraits::registerUnknownCommand(
1056ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko                                                  StringRef CommandName) {
1066ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  CommandInfo *Info = createCommandInfoWithName(CommandName);
1076ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  Info->IsUnknownCommand = true;
1086ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  return Info;
1096ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko}
1106ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko
1116ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenkoconst CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
1126ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  CommandInfo *Info = createCommandInfoWithName(CommandName);
1136ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  Info->IsBlockCommand = true;
1146ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko  return Info;
1156ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko}
1166ebf09130479bc7605aa09a3e6c4dc2ba3513495Dmitri Gribenko
117e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenkoconst CommandInfo *CommandTraits::getBuiltinCommandInfo(
118e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko                                                  unsigned CommandID) {
119e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  if (CommandID < llvm::array_lengthof(Commands))
120e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko    return &Commands[CommandID];
121e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  return NULL;
12262290ae569016345b79d4e11dd93abc300e5a681Dmitri Gribenko}
12362290ae569016345b79d4e11dd93abc300e5a681Dmitri Gribenko
124e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenkoconst CommandInfo *CommandTraits::getRegisteredCommandInfo(
125e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko                                                  StringRef Name) const {
126e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) {
127e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko    if (RegisteredCommands[i]->Name == Name)
128e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko      return RegisteredCommands[i];
129e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  }
130e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  return NULL;
131aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko}
132aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
133e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenkoconst CommandInfo *CommandTraits::getRegisteredCommandInfo(
134e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko                                                  unsigned CommandID) const {
135e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko  return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)];
136aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko}
137aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
138aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko} // end namespace comments
139aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko} // end namespace clang
140aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
141