summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/XRefs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd/XRefs.cpp')
-rw-r--r--clang-tools-extra/clangd/XRefs.cpp270
1 files changed, 270 insertions, 0 deletions
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
new file mode 100644
index 00000000000..9bd4131b03f
--- /dev/null
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -0,0 +1,270 @@
+//===--- XRefs.cpp ----------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "XRefs.h"
+#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexingAction.h"
+namespace clang {
+namespace clangd {
+using namespace llvm;
+namespace {
+
+/// Finds declarations locations that a given source location refers to.
+class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
+ std::vector<const Decl *> Decls;
+ std::vector<const MacroInfo *> MacroInfos;
+ const SourceLocation &SearchedLocation;
+ const ASTContext &AST;
+ Preprocessor &PP;
+
+public:
+ DeclarationAndMacrosFinder(raw_ostream &OS,
+ const SourceLocation &SearchedLocation,
+ ASTContext &AST, Preprocessor &PP)
+ : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
+
+ std::vector<const Decl *> takeDecls() {
+ // Don't keep the same declaration multiple times.
+ // This can happen when nodes in the AST are visited twice.
+ std::sort(Decls.begin(), Decls.end());
+ auto Last = std::unique(Decls.begin(), Decls.end());
+ Decls.erase(Last, Decls.end());
+ return std::move(Decls);
+ }
+
+ std::vector<const MacroInfo *> takeMacroInfos() {
+ // Don't keep the same Macro info multiple times.
+ std::sort(MacroInfos.begin(), MacroInfos.end());
+ auto Last = std::unique(MacroInfos.begin(), MacroInfos.end());
+ MacroInfos.erase(Last, MacroInfos.end());
+ return std::move(MacroInfos);
+ }
+
+ bool
+ handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
+ ArrayRef<index::SymbolRelation> Relations, FileID FID,
+ unsigned Offset,
+ index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
+ if (isSearchedLocation(FID, Offset))
+ Decls.push_back(D);
+ return true;
+ }
+
+private:
+ bool isSearchedLocation(FileID FID, unsigned Offset) const {
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ return SourceMgr.getFileOffset(SearchedLocation) == Offset &&
+ SourceMgr.getFileID(SearchedLocation) == FID;
+ }
+
+ void finish() override {
+ // Also handle possible macro at the searched location.
+ Token Result;
+ auto &Mgr = AST.getSourceManager();
+ if (!Lexer::getRawToken(SearchedLocation, Result, Mgr, AST.getLangOpts(),
+ false)) {
+ if (Result.is(tok::raw_identifier)) {
+ PP.LookUpIdentifierInfo(Result);
+ }
+ IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
+ if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
+ std::pair<FileID, unsigned int> DecLoc =
+ Mgr.getDecomposedExpansionLoc(SearchedLocation);
+ // Get the definition just before the searched location so that a macro
+ // referenced in a '#undef MACRO' can still be found.
+ SourceLocation BeforeSearchedLocation = Mgr.getMacroArgExpandedLocation(
+ Mgr.getLocForStartOfFile(DecLoc.first)
+ .getLocWithOffset(DecLoc.second - 1));
+ MacroDefinition MacroDef =
+ PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
+ MacroInfo *MacroInf = MacroDef.getMacroInfo();
+ if (MacroInf) {
+ MacroInfos.push_back(MacroInf);
+ }
+ }
+ }
+ }
+};
+
+llvm::Optional<Location>
+getDeclarationLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
+ SourceLocation LocStart = ValSourceRange.getBegin();
+
+ const FileEntry *F =
+ SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
+ if (!F)
+ return llvm::None;
+ SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(), 0,
+ SourceMgr, LangOpts);
+ Position Begin;
+ Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
+ Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
+ Position End;
+ End.line = SourceMgr.getSpellingLineNumber(LocEnd) - 1;
+ End.character = SourceMgr.getSpellingColumnNumber(LocEnd) - 1;
+ Range R = {Begin, End};
+ Location L;
+
+ StringRef FilePath = F->tryGetRealPathName();
+ if (FilePath.empty())
+ FilePath = F->getName();
+ L.uri = URI::fromFile(FilePath);
+ L.range = R;
+ return L;
+}
+
+} // namespace
+
+std::vector<Location> findDefinitions(const Context &Ctx, ParsedAST &AST,
+ Position Pos) {
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+ if (!FE)
+ return {};
+
+ SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
+
+ auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
+ llvm::errs(), SourceLocationBeg, AST.getASTContext(),
+ AST.getPreprocessor());
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::All;
+ IndexOpts.IndexFunctionLocals = true;
+
+ indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
+ DeclMacrosFinder, IndexOpts);
+
+ std::vector<const Decl *> Decls = DeclMacrosFinder->takeDecls();
+ std::vector<const MacroInfo *> MacroInfos =
+ DeclMacrosFinder->takeMacroInfos();
+ std::vector<Location> Result;
+
+ for (auto Item : Decls) {
+ auto L = getDeclarationLocation(AST, Item->getSourceRange());
+ if (L)
+ Result.push_back(*L);
+ }
+
+ for (auto Item : MacroInfos) {
+ SourceRange SR(Item->getDefinitionLoc(), Item->getDefinitionEndLoc());
+ auto L = getDeclarationLocation(AST, SR);
+ if (L)
+ Result.push_back(*L);
+ }
+
+ return Result;
+}
+
+namespace {
+
+/// Finds document highlights that a given list of declarations refers to.
+class DocumentHighlightsFinder : public index::IndexDataConsumer {
+ std::vector<const Decl *> &Decls;
+ std::vector<DocumentHighlight> DocumentHighlights;
+ const ASTContext &AST;
+
+public:
+ DocumentHighlightsFinder(raw_ostream &OS, ASTContext &AST, Preprocessor &PP,
+ std::vector<const Decl *> &Decls)
+ : Decls(Decls), AST(AST) {}
+ std::vector<DocumentHighlight> takeHighlights() {
+ // Don't keep the same highlight multiple times.
+ // This can happen when nodes in the AST are visited twice.
+ std::sort(DocumentHighlights.begin(), DocumentHighlights.end());
+ auto Last =
+ std::unique(DocumentHighlights.begin(), DocumentHighlights.end());
+ DocumentHighlights.erase(Last, DocumentHighlights.end());
+ return std::move(DocumentHighlights);
+ }
+
+ bool
+ handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
+ ArrayRef<index::SymbolRelation> Relations, FileID FID,
+ unsigned Offset,
+ index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ if (SourceMgr.getMainFileID() != FID ||
+ std::find(Decls.begin(), Decls.end(), D) == Decls.end()) {
+ return true;
+ }
+ SourceLocation End;
+ const LangOptions &LangOpts = AST.getLangOpts();
+ SourceLocation StartOfFileLoc = SourceMgr.getLocForStartOfFile(FID);
+ SourceLocation HightlightStartLoc = StartOfFileLoc.getLocWithOffset(Offset);
+ End =
+ Lexer::getLocForEndOfToken(HightlightStartLoc, 0, SourceMgr, LangOpts);
+ SourceRange SR(HightlightStartLoc, End);
+
+ DocumentHighlightKind Kind = DocumentHighlightKind::Text;
+ if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Write) & Roles)
+ Kind = DocumentHighlightKind::Write;
+ else if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Read) & Roles)
+ Kind = DocumentHighlightKind::Read;
+
+ DocumentHighlights.push_back(getDocumentHighlight(SR, Kind));
+ return true;
+ }
+
+private:
+ DocumentHighlight getDocumentHighlight(SourceRange SR,
+ DocumentHighlightKind Kind) {
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ SourceLocation LocStart = SR.getBegin();
+ Position Begin;
+ Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
+ Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
+ Position End;
+ End.line = SourceMgr.getSpellingLineNumber(SR.getEnd()) - 1;
+ End.character = SourceMgr.getSpellingColumnNumber(SR.getEnd()) - 1;
+ Range R = {Begin, End};
+ DocumentHighlight DH;
+ DH.range = R;
+ DH.kind = Kind;
+ return DH;
+ }
+};
+
+} // namespace
+
+std::vector<DocumentHighlight>
+findDocumentHighlights(const Context &Ctx, ParsedAST &AST, Position Pos) {
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+ if (!FE)
+ return {};
+
+ SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
+
+ auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
+ llvm::errs(), SourceLocationBeg, AST.getASTContext(),
+ AST.getPreprocessor());
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::All;
+ IndexOpts.IndexFunctionLocals = true;
+
+ // Macro occurences are not currently handled.
+ indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
+ DeclMacrosFinder, IndexOpts);
+
+ std::vector<const Decl *> SelectedDecls = DeclMacrosFinder->takeDecls();
+
+ auto DocHighlightsFinder = std::make_shared<DocumentHighlightsFinder>(
+ llvm::errs(), AST.getASTContext(), AST.getPreprocessor(), SelectedDecls);
+
+ indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
+ DocHighlightsFinder, IndexOpts);
+
+ return DocHighlightsFinder->takeHighlights();
+}
+
+} // namespace clangd
+} // namespace clang
OpenPOWER on IntegriCloud