1f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross//===--- CommentCommandTraits.cpp - Comment command properties --*- C++ -*-===//
2f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross//
3f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross//                     The LLVM Compiler Infrastructure
4f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross//
5f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross// This file is distributed under the University of Illinois Open Source
6f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross// License. See LICENSE.TXT for details.
7f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross//
8f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross//===----------------------------------------------------------------------===//
9f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
10f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross#include "clang/AST/CommentCommandTraits.h"
11f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross#include "llvm/ADT/STLExtras.h"
12f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
13f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crossnamespace clang {
14f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crossnamespace comments {
15f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
16f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross#include "clang/AST/CommentCommandInfo.inc"
172db0f5f31c015b5a89b619f8c95a9bf95c09c75bArve Hjønnevåg
18f45fa6b2853cc32385375a0b63ee39ad6a968869Colin CrossCommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
19f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                             const CommentOptions &CommentOptions) :
20ad5f6c475934ac6a658a203069a9f055540946e7Felipe Leme    NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
21f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross  registerCommentOptions(CommentOptions);
226e01fa6f95fb20a2faab33561056d2e74cc097cbFelipe Leme}
23ad5f6c475934ac6a658a203069a9f055540946e7Felipe Leme
24635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Lemevoid CommandTraits::registerCommentOptions(
258f37aa5011bf5d8c0a67126b92e3b435ffd4dca0Mark Salyzyn    const CommentOptions &CommentOptions) {
26f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross  for (CommentOptions::BlockCommandNamesTy::const_iterator
27f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross           I = CommentOptions.BlockCommandNames.begin(),
286e01fa6f95fb20a2faab33561056d2e74cc097cbFelipe Leme           E = CommentOptions.BlockCommandNames.end();
29f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross       I != E; I++) {
307dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris    registerBlockCommand(*I);
31f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross  }
32f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross}
33f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
34f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crossconst CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
35f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross  if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
36f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    return Info;
379dc117c415d0df0a3acd900709d05deabe975704Elliott Hughes  return getRegisteredCommandInfo(Name);
38f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross}
39f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
40f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crossconst CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
41f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross  if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID))
42f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    return Info;
43656a6b9e3645bfe2cf073b69cbb9d02832f62c26Alex Ray  return getRegisteredCommandInfo(CommandID);
44f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross}
45f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
466e01fa6f95fb20a2faab33561056d2e74cc097cbFelipe Lemeconst CommandInfo *
476e01fa6f95fb20a2faab33561056d2e74cc097cbFelipe LemeCommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {
486e01fa6f95fb20a2faab33561056d2e74cc097cbFelipe Leme  // Single-character command impostures, such as \t or \n, should not go
494db754fd7c13993d81d98157f10e8015422d1e3aMichal Karpinski  // through the fixit logic.
504db754fd7c13993d81d98157f10e8015422d1e3aMichal Karpinski  if (Typo.size() <= 1)
516e01fa6f95fb20a2faab33561056d2e74cc097cbFelipe Leme    return nullptr;
52f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
53f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross  // The maximum edit distance we're prepared to accept.
54f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross  const unsigned MaxEditDistance = 1;
55f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
56f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross  unsigned BestEditDistance = MaxEditDistance;
57e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme  SmallVector<const CommandInfo *, 2> BestCommand;
588fecfdda012928bc2fe6d0e66fd4a4c912946254Felipe Leme
5978f2c86235d5882a8dc84c85a1c1864062e5f3afFelipe Leme  auto ConsiderCorrection = [&](const CommandInfo *Command) {
60e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme    StringRef Name = Command->Name;
61e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme
62635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme    unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
63635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme    if (MinPossibleEditDistance <= BestEditDistance) {
642628e9e939fda323fa44c5cb743f4a77b12a312aFelipe Leme      unsigned EditDistance = Typo.edit_distance(Name, true, BestEditDistance);
6571ca15eadd3da0c102a8539f7a88294a94456623Felipe Leme      if (EditDistance < BestEditDistance) {
6671ca15eadd3da0c102a8539f7a88294a94456623Felipe Leme        BestEditDistance = EditDistance;
6771ca15eadd3da0c102a8539f7a88294a94456623Felipe Leme        BestCommand.clear();
6878f2c86235d5882a8dc84c85a1c1864062e5f3afFelipe Leme      }
692a83daa8a3e1eab292dc1464bbe78f025f4bc0e9Todd Poynor      if (EditDistance == BestEditDistance)
70ced6078b0e03a75d9b78e61ce25609bd2cb97b1dMark Salyzyn        BestCommand.push_back(Command);
712a83daa8a3e1eab292dc1464bbe78f025f4bc0e9Todd Poynor    }
728d4cb7ffc11050eebb4d06684e0eb14d9aadacb5Sharvil Nanavati  };
73e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme
74d6ab01105bbd80dfa2fc2debc8e31d6422c378eeMark Salyzyn  for (const auto &Command : Commands)
754d42dea08915ccbb61ca05903af5330d02d66755Mark Salyzyn    ConsiderCorrection(&Command);
767dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris
777dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  for (const auto *Command : RegisteredCommands)
787dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris    if (!Command->IsUnknownCommand)
797dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris      ConsiderCorrection(Command);
807dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris
810816520c5cd60519d8e221ed92497aa5464e3039Erik Kline  return BestCommand.size() == 1 ? BestCommand[0] : nullptr;
827dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris}
837dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris
847dc7f3221f26b771c266a26ec785eb74287922f1Christopher FerrisCommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
857dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
867dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  memcpy(Name, CommandName.data(), CommandName.size());
877dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  Name[CommandName.size()] = '\0';
887dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris
897dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  // Value-initialize (=zero-initialize in this case) a new CommandInfo.
9071ca15eadd3da0c102a8539f7a88294a94456623Felipe Leme  CommandInfo *Info = new (Allocator) CommandInfo();
9171ca15eadd3da0c102a8539f7a88294a94456623Felipe Leme  Info->Name = Name;
92e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme  // We only have a limited number of bits to encode command IDs in the
93809d74e92c16cf694c929b8ca2b54515af13e9feFelipe Leme  // CommandInfo structure, so the ID numbers can potentially wrap around.
94809d74e92c16cf694c929b8ca2b54515af13e9feFelipe Leme  assert((NextID < (1 << CommandInfo::NumCommandIDBits))
95809d74e92c16cf694c929b8ca2b54515af13e9feFelipe Leme         && "Too many commands. We have limited bits for the command ID.");
96809d74e92c16cf694c929b8ca2b54515af13e9feFelipe Leme  Info->ID = NextID++;
97809d74e92c16cf694c929b8ca2b54515af13e9feFelipe Leme
98ca9c12e64d44f6c67cd46819583239f0ad051a51Felipe Leme  RegisteredCommands.push_back(Info);
99809d74e92c16cf694c929b8ca2b54515af13e9feFelipe Leme
100249beee359da256f7c41c481d45c06765b6a1d8aCalvin On  return Info;
101c4eee56dab06a7de1db18327f8d4831f89d1d640Felipe Leme}
102c4eee56dab06a7de1db18327f8d4831f89d1d640Felipe Leme
103c4eee56dab06a7de1db18327f8d4831f89d1d640Felipe Lemeconst CommandInfo *CommandTraits::registerUnknownCommand(
104e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme                                                  StringRef CommandName) {
105e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme  CommandInfo *Info = createCommandInfoWithName(CommandName);
1067dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  Info->IsUnknownCommand = true;
107e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme  return Info;
1087dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris}
1097dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris
11054bcc5ffd5a79f4f194089c58d3de571532bf39bChristopher Ferrisconst CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
11154bcc5ffd5a79f4f194089c58d3de571532bf39bChristopher Ferris  CommandInfo *Info = createCommandInfoWithName(CommandName);
1127dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  Info->IsBlockCommand = true;
1137dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  return Info;
114e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme}
115e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme
1167dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferrisconst CommandInfo *CommandTraits::getBuiltinCommandInfo(
117e82a27d0c1e3f2cef6f13a1a9efff55638601752Felipe Leme                                                  unsigned CommandID) {
1187dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  if (CommandID < llvm::array_lengthof(Commands))
1197dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris    return &Commands[CommandID];
1207dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris  return nullptr;
1217dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris}
1227dc7f3221f26b771c266a26ec785eb74287922f1Christopher Ferris
123635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Lemeconst CommandInfo *CommandTraits::getRegisteredCommandInfo(
124635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme                                                  StringRef Name) const {
125635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme  for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) {
126635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme    if (RegisteredCommands[i]->Name == Name)
127635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme      return RegisteredCommands[i];
128635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme  }
129f0922cc1786c0c2fbf44c10b0005243ecbb4227dNick Kralevich  return nullptr;
130635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme}
131635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme
132635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Lemeconst CommandInfo *CommandTraits::getRegisteredCommandInfo(
133cbce55d4fdbdd2e5a5515054c48d2116c5db2712Felipe Leme                                                  unsigned CommandID) const {
134635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme  return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)];
135635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme}
136635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme
137635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme} // end namespace comments
138635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme} // end namespace clang
139635ca31754ae734b0c540ac5600d58ae55cd4237Felipe Leme
140f0922cc1786c0c2fbf44c10b0005243ecbb4227dNick Kralevich