clang 19.0.0git
USRFinder.cpp
Go to the documentation of this file.
1//===--- USRFinder.cpp - Clang refactoring library ------------------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file Implements a recursive AST visitor that finds the USR of a symbol at a
10/// point.
11///
12//===----------------------------------------------------------------------===//
13
15#include "clang/AST/AST.h"
20#include "clang/Lex/Lexer.h"
22#include "llvm/ADT/SmallVector.h"
23
24using namespace llvm;
25
26namespace clang {
27namespace tooling {
28
29namespace {
30
31/// Recursively visits each AST node to find the symbol underneath the cursor.
32class NamedDeclOccurrenceFindingVisitor
33 : public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {
34public:
35 // Finds the NamedDecl at a point in the source.
36 // \param Point the location in the source to search for the NamedDecl.
37 explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,
38 const ASTContext &Context)
39 : RecursiveSymbolVisitor(Context.getSourceManager(),
40 Context.getLangOpts()),
41 Point(Point), Context(Context) {}
42
43 bool visitSymbolOccurrence(const NamedDecl *ND,
44 ArrayRef<SourceRange> NameRanges) {
45 if (!ND)
46 return true;
47 for (const auto &Range : NameRanges) {
48 SourceLocation Start = Range.getBegin();
49 SourceLocation End = Range.getEnd();
50 if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
51 !End.isFileID() || !isPointWithin(Start, End))
52 return true;
53 }
54 Result = ND;
55 return false;
56 }
57
58 const NamedDecl *getNamedDecl() const { return Result; }
59
60private:
61 // Determines if the Point is within Start and End.
62 bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
63 // FIXME: Add tests for Point == End.
64 return Point == Start || Point == End ||
65 (Context.getSourceManager().isBeforeInTranslationUnit(Start,
66 Point) &&
67 Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
68 }
69
70 const NamedDecl *Result = nullptr;
71 const SourceLocation Point; // The location to find the NamedDecl.
72 const ASTContext &Context;
73};
74
75} // end anonymous namespace
76
77const NamedDecl *getNamedDeclAt(const ASTContext &Context,
78 const SourceLocation Point) {
79 const SourceManager &SM = Context.getSourceManager();
80 NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);
81
82 // Try to be clever about pruning down the number of top-level declarations we
83 // see. If both start and end is either before or after the point we're
84 // looking for the point cannot be inside of this decl. Don't even look at it.
85 for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
86 SourceLocation StartLoc = CurrDecl->getBeginLoc();
87 SourceLocation EndLoc = CurrDecl->getEndLoc();
88 if (StartLoc.isValid() && EndLoc.isValid() &&
89 SM.isBeforeInTranslationUnit(StartLoc, Point) !=
90 SM.isBeforeInTranslationUnit(EndLoc, Point))
91 Visitor.TraverseDecl(CurrDecl);
92 }
93
94 return Visitor.getNamedDecl();
95}
96
97namespace {
98
99/// Recursively visits each NamedDecl node to find the declaration with a
100/// specific name.
101class NamedDeclFindingVisitor
102 : public RecursiveASTVisitor<NamedDeclFindingVisitor> {
103public:
104 explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}
105
106 // We don't have to traverse the uses to find some declaration with a
107 // specific name, so just visit the named declarations.
108 bool VisitNamedDecl(const NamedDecl *ND) {
109 if (!ND)
110 return true;
111 // Fully qualified name is used to find the declaration.
112 if (Name != ND->getQualifiedNameAsString() &&
113 Name != "::" + ND->getQualifiedNameAsString())
114 return true;
115 Result = ND;
116 return false;
117 }
118
119 const NamedDecl *getNamedDecl() const { return Result; }
120
121private:
122 const NamedDecl *Result = nullptr;
123 StringRef Name;
124};
125
126} // end anonymous namespace
127
129 const std::string &Name) {
130 NamedDeclFindingVisitor Visitor(Name);
131 Visitor.TraverseDecl(Context.getTranslationUnitDecl());
132 return Visitor.getNamedDecl();
133}
134
135std::string getUSRForDecl(const Decl *Decl) {
137
138 // FIXME: Add test for the nullptr case.
139 if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
140 return "";
141
142 return std::string(Buff);
143}
144
145} // end namespace tooling
146} // end namespace clang
Defines the clang::ASTContext interface.
#define SM(sm)
Definition: Cuda.cpp:82
A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol.
Defines the SourceManager interface.
Methods for determining the USR of a symbol at a location in source code.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
This represents a decl that may have a name.
Definition: Decl.h:249
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
const NamedDecl * getNamedDeclFor(const ASTContext &Context, const std::string &Name)
Definition: USRFinder.cpp:128
const NamedDecl * getNamedDeclAt(const ASTContext &Context, const SourceLocation Point)
Definition: USRFinder.cpp:77
std::string getUSRForDecl(const Decl *Decl)
Definition: USRFinder.cpp:135
The JSON file list parser is used to communicate input to InstallAPI.
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30