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"
11245431Sdim#include "llvm/ADT/STLExtras.h"
12239313Sdim
13239313Sdimnamespace clang {
14239313Sdimnamespace comments {
15239313Sdim
16245431Sdim#include "clang/AST/CommentCommandInfo.inc"
17239313Sdim
18252723SdimCommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
19252723Sdim                             const CommentOptions &CommentOptions) :
20252723Sdim    NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
21252723Sdim  registerCommentOptions(CommentOptions);
22252723Sdim}
23239313Sdim
24252723Sdimvoid CommandTraits::registerCommentOptions(
25252723Sdim    const CommentOptions &CommentOptions) {
26252723Sdim  for (CommentOptions::BlockCommandNamesTy::const_iterator
27252723Sdim           I = CommentOptions.BlockCommandNames.begin(),
28252723Sdim           E = CommentOptions.BlockCommandNames.end();
29252723Sdim       I != E; I++) {
30252723Sdim    registerBlockCommand(*I);
31252723Sdim  }
32252723Sdim}
33252723Sdim
34245431Sdimconst CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
35245431Sdim  if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
36245431Sdim    return Info;
37245431Sdim  return getRegisteredCommandInfo(Name);
38245431Sdim}
39239313Sdim
40245431Sdimconst CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
41245431Sdim  if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID))
42245431Sdim    return Info;
43245431Sdim  return getRegisteredCommandInfo(CommandID);
44239313Sdim}
45239313Sdim
46263509Sdimstatic void
47263509SdimHelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand,
48263509Sdim                             StringRef Typo, const CommandInfo *Command) {
49263509Sdim  const unsigned MaxEditDistance = 1;
50263509Sdim  unsigned BestEditDistance = MaxEditDistance + 1;
51263509Sdim  StringRef Name = Command->Name;
52263509Sdim
53263509Sdim  unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
54263509Sdim  if (MinPossibleEditDistance > 0 &&
55263509Sdim      Typo.size() / MinPossibleEditDistance < 1)
56263509Sdim    return;
57263509Sdim  unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
58263509Sdim  if (EditDistance > MaxEditDistance)
59263509Sdim    return;
60263509Sdim  if (EditDistance == BestEditDistance)
61263509Sdim    BestCommand.push_back(Command);
62263509Sdim  else if (EditDistance < BestEditDistance) {
63263509Sdim    BestCommand.clear();
64263509Sdim    BestCommand.push_back(Command);
65263509Sdim    BestEditDistance = EditDistance;
66263509Sdim  }
67263509Sdim}
68263509Sdim
69263509Sdimconst CommandInfo *
70263509SdimCommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {
71263509Sdim  // single character command impostures, such as \t or \n must not go
72263509Sdim  // through the fixit logic.
73263509Sdim  if (Typo.size() <= 1)
74263509Sdim    return NULL;
75263509Sdim
76263509Sdim  SmallVector<const CommandInfo *, 2> BestCommand;
77263509Sdim
78263509Sdim  const int NumOfCommands = llvm::array_lengthof(Commands);
79263509Sdim  for (int i = 0; i < NumOfCommands; i++)
80263509Sdim    HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]);
81263509Sdim
82263509Sdim  for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i)
83263509Sdim    if (!RegisteredCommands[i]->IsUnknownCommand)
84263509Sdim      HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]);
85263509Sdim
86263509Sdim  return (BestCommand.size() != 1) ? NULL : BestCommand[0];
87263509Sdim}
88263509Sdim
89252723SdimCommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
90245431Sdim  char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
91245431Sdim  memcpy(Name, CommandName.data(), CommandName.size());
92245431Sdim  Name[CommandName.size()] = '\0';
93239313Sdim
94245431Sdim  // Value-initialize (=zero-initialize in this case) a new CommandInfo.
95245431Sdim  CommandInfo *Info = new (Allocator) CommandInfo();
96245431Sdim  Info->Name = Name;
97245431Sdim  Info->ID = NextID++;
98239313Sdim
99245431Sdim  RegisteredCommands.push_back(Info);
100239313Sdim
101245431Sdim  return Info;
102239313Sdim}
103239313Sdim
104252723Sdimconst CommandInfo *CommandTraits::registerUnknownCommand(
105252723Sdim                                                  StringRef CommandName) {
106252723Sdim  CommandInfo *Info = createCommandInfoWithName(CommandName);
107252723Sdim  Info->IsUnknownCommand = true;
108252723Sdim  return Info;
109252723Sdim}
110252723Sdim
111252723Sdimconst CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
112252723Sdim  CommandInfo *Info = createCommandInfoWithName(CommandName);
113252723Sdim  Info->IsBlockCommand = true;
114252723Sdim  return Info;
115252723Sdim}
116252723Sdim
117245431Sdimconst CommandInfo *CommandTraits::getBuiltinCommandInfo(
118245431Sdim                                                  unsigned CommandID) {
119245431Sdim  if (CommandID < llvm::array_lengthof(Commands))
120245431Sdim    return &Commands[CommandID];
121245431Sdim  return NULL;
122239313Sdim}
123239313Sdim
124245431Sdimconst CommandInfo *CommandTraits::getRegisteredCommandInfo(
125245431Sdim                                                  StringRef Name) const {
126245431Sdim  for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) {
127245431Sdim    if (RegisteredCommands[i]->Name == Name)
128245431Sdim      return RegisteredCommands[i];
129245431Sdim  }
130245431Sdim  return NULL;
131239313Sdim}
132239313Sdim
133245431Sdimconst CommandInfo *CommandTraits::getRegisteredCommandInfo(
134245431Sdim                                                  unsigned CommandID) const {
135245431Sdim  return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)];
136239313Sdim}
137239313Sdim
138239313Sdim} // end namespace comments
139239313Sdim} // end namespace clang
140239313Sdim
141