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