Index: clangd/index/dex/dexp/CMakeLists.txt =================================================================== --- clangd/index/dex/dexp/CMakeLists.txt +++ clangd/index/dex/dexp/CMakeLists.txt @@ -1,3 +1,5 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../..) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../) set(LLVM_LINK_COMPONENTS Index: clangd/index/dex/dexp/Dexp.cpp =================================================================== --- clangd/index/dex/dexp/Dexp.cpp +++ clangd/index/dex/dexp/Dexp.cpp @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "../../Serialization.h" -#include "../Dex.h" +#include "Dex.h" +#include "Serialization.h" +#include "SourceCode.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" @@ -52,6 +53,26 @@ llvm::outs() << llvm::formatv("{0} took {1:ms+n}.\n", Name, Duration); } +std::vector +getSymbolIDsFromIndex(llvm::StringRef QualifiedName, const SymbolIndex *Index) { + FuzzyFindRequest Request; + // Remove leading "::" qualifier as FuzzyFind doesn't need leading "::" + // qualifier for global scope. + bool IsGlobalScope = QualifiedName.consume_front("::"); + auto Names = clang::clangd::splitQualifiedName(QualifiedName); + if (IsGlobalScope || !Names.first.empty()) + Request.Scopes = {Names.first}; + + Request.Query = Names.second; + std::vector SymIDs; + Index->fuzzyFind(Request, [&](const Symbol &Sym) { + std::string SymQualifiedName = (Sym.Scope + Sym.Name).str(); + if (QualifiedName == SymQualifiedName) + SymIDs.push_back(Sym.ID); + }); + return SymIDs; +} + // REPL commands inherit from Command and contain their options as members. // Creating a Command populates parser options, parseAndRun() resets them. class Command { @@ -88,7 +109,6 @@ }; // FIXME(kbobyrev): Ideas for more commands: -// * find symbol references: print set of reference locations // * load/swap/reload index: this would make it possible to get rid of llvm::cl // usages in the tool driver and actually use llvm::cl library in the REPL. // * show posting list density histogram (our dump data somewhere so that user @@ -139,19 +159,32 @@ cl::opt ID{ "id", cl::Positional, - cl::Required, cl::desc("Symbol ID to look up (hex)"), }; + cl::opt Name{ + "name", cl::desc("Qualified name to look up."), + }; void run() override { - auto SID = clang::clangd::SymbolID::fromStr(ID); - if (!SID) { - llvm::outs() << llvm::toString(SID.takeError()) << "\n"; + if (ID.getNumOccurrences() == 0 && Name.getNumOccurrences() == 0) { + llvm::outs() + << "Missing required argument: please provide id or -name.\n"; return; } + std::vector IDs; + if (ID.getNumOccurrences()) { + auto SID = clang::clangd::SymbolID::fromStr(ID); + if (!SID) { + llvm::outs() << llvm::toString(SID.takeError()) << "\n"; + return; + } + IDs.push_back(*SID); + } else { + IDs = getSymbolIDsFromIndex(Name, Index); + } clang::clangd::LookupRequest Request; - Request.IDs = {*SID}; + Request.IDs.insert(IDs.begin(), IDs.end()); bool FoundSymbol = false; Index->lookup(Request, [&](const Symbol &Sym) { FoundSymbol = true; @@ -162,13 +195,62 @@ } }; +class Refs : public Command { + cl::opt ID{ + "id", cl::Positional, + cl::desc("Symbol ID of the symbol being queried (hex)."), + }; + cl::opt Name{ + "name", cl::desc("Qualified name of the symbol being queried."), + }; + cl::opt Filter{ + "filter", cl::init(".*"), + cl::desc( + "Print all results from files matching this regular expression."), + }; + + void run() override { + if (ID.getNumOccurrences() == 0 && Name.getNumOccurrences() == 0) { + llvm::outs() + << "Missing required argument: please provide id or -name.\n"; + return; + } + std::vector IDs; + if (ID.getNumOccurrences()) { + auto SID = clang::clangd::SymbolID::fromStr(ID); + if (!SID) { + llvm::outs() << llvm::toString(SID.takeError()) << "\n"; + return; + } + IDs.push_back(*SID); + } else { + IDs = getSymbolIDsFromIndex(Name, Index); + } + clang::clangd::RefsRequest RefRequest; + RefRequest.IDs.insert(IDs.begin(), IDs.end()); + llvm::Regex RegexFilter(Filter); + Index->refs(RefRequest, [&RegexFilter](const clang::clangd::Ref &R) { + auto U = clang::clangd::URI::parse(R.Location.FileURI); + if (!U) { + llvm::outs() << U.takeError(); + return; + } + if (RegexFilter.match(U->body())) + llvm::outs() << R << "\n"; + }); + } +}; + struct { const char *Name; const char *Description; std::function()> Implementation; } CommandInfo[] = { {"find", "Search for symbols with fuzzyFind", llvm::make_unique}, - {"lookup", "Dump symbol details by ID", llvm::make_unique}, + {"lookup", "Dump symbol details by ID or qualified name", + llvm::make_unique}, + {"refs", "Find references by ID or qualified name", + llvm::make_unique}, }; } // namespace