brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.9 KiB · 98987ad Raw
143 lines · cpp
1//===--- FuzzySymbolIndex.cpp - Lookup symbols for autocomplete -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8#include "FuzzySymbolIndex.h"9#include "llvm/Support/Regex.h"10 11using clang::find_all_symbols::SymbolAndSignals;12using llvm::StringRef;13 14namespace clang {15namespace include_fixer {16namespace {17 18class MemSymbolIndex : public FuzzySymbolIndex {19public:20  MemSymbolIndex(std::vector<SymbolAndSignals> Symbols) {21    for (auto &Symbol : Symbols) {22      auto Tokens = tokenize(Symbol.Symbol.getName());23      this->Symbols.emplace_back(24          StringRef(llvm::join(Tokens.begin(), Tokens.end(), " ")),25          std::move(Symbol));26    }27  }28 29  std::vector<SymbolAndSignals> search(StringRef Query) override {30    auto Tokens = tokenize(Query);31    llvm::Regex Pattern("^" + queryRegexp(Tokens));32    std::vector<SymbolAndSignals> Results;33    for (const Entry &E : Symbols)34      if (Pattern.match(E.first))35        Results.push_back(E.second);36    return Results;37  }38 39private:40  using Entry = std::pair<llvm::SmallString<32>, SymbolAndSignals>;41  std::vector<Entry> Symbols;42};43 44// Helpers for tokenize state machine.45enum TokenizeState {46  EMPTY,      // No pending characters.47  ONE_BIG,    // Read one uppercase letter, could be WORD or Word.48  BIG_WORD,   // Reading an uppercase WORD.49  SMALL_WORD, // Reading a lowercase word.50  NUMBER      // Reading a number.51};52 53enum CharType { UPPER, LOWER, DIGIT, MISC };54CharType classify(char c) {55  if (isupper(c))56    return UPPER;57  if (islower(c))58    return LOWER;59  if (isdigit(c))60    return DIGIT;61  return MISC;62}63 64} // namespace65 66std::vector<std::string> FuzzySymbolIndex::tokenize(StringRef Text) {67  std::vector<std::string> Result;68  // State describes the treatment of text from Start to I.69  // Once text is Flush()ed into Result, we're done with it and advance Start.70  TokenizeState State = EMPTY;71  size_t Start = 0;72  auto Flush = [&](size_t End) {73    if (State != EMPTY) {74      Result.push_back(Text.substr(Start, End - Start).lower());75      State = EMPTY;76    }77    Start = End;78  };79  for (size_t I = 0; I < Text.size(); ++I) {80    CharType Type = classify(Text[I]);81    if (Type == MISC)82      Flush(I);83    else if (Type == LOWER)84      switch (State) {85      case BIG_WORD:86        Flush(I - 1); // FOOBar: first token is FOO, not FOOB.87        [[fallthrough]];88      case ONE_BIG:89        State = SMALL_WORD;90        [[fallthrough]];91      case SMALL_WORD:92        break;93      default:94        Flush(I);95        State = SMALL_WORD;96      }97    else if (Type == UPPER)98      switch (State) {99      case ONE_BIG:100        State = BIG_WORD;101        [[fallthrough]];102      case BIG_WORD:103        break;104      default:105        Flush(I);106        State = ONE_BIG;107      }108    else if (Type == DIGIT && State != NUMBER) {109      Flush(I);110      State = NUMBER;111    }112  }113  Flush(Text.size());114  return Result;115}116 117std::string118FuzzySymbolIndex::queryRegexp(const std::vector<std::string> &Tokens) {119  std::string Result;120  for (size_t I = 0; I < Tokens.size(); ++I) {121    if (I)122      Result.append("[[:alnum:]]* ");123    for (size_t J = 0; J < Tokens[I].size(); ++J) {124      if (J)125        Result.append("([[:alnum:]]* )?");126      Result.push_back(Tokens[I][J]);127    }128  }129  return Result;130}131 132llvm::Expected<std::unique_ptr<FuzzySymbolIndex>>133FuzzySymbolIndex::createFromYAML(StringRef FilePath) {134  auto Buffer = llvm::MemoryBuffer::getFile(FilePath, /*IsText=*/true);135  if (!Buffer)136    return llvm::errorCodeToError(Buffer.getError());137  return std::make_unique<MemSymbolIndex>(138      find_all_symbols::ReadSymbolInfosFromYAML(Buffer.get()->getBuffer()));139}140 141} // namespace include_fixer142} // namespace clang143