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"
16 #include "clang/AST/ASTContext.h"
20 #include "clang/Lex/Lexer.h"
22 #include "llvm/ADT/SmallVector.h"
23 
24 using namespace llvm;
25 
26 namespace clang {
27 namespace tooling {
28 
29 namespace {
30 
31 /// Recursively visits each AST node to find the symbol underneath the cursor.
32 class NamedDeclOccurrenceFindingVisitor
33  : public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {
34 public:
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 
60 private:
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 
77 const 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 
97 namespace {
98 
99 /// Recursively visits each NamedDecl node to find the declaration with a
100 /// specific name.
101 class NamedDeclFindingVisitor
102  : public RecursiveASTVisitor<NamedDeclFindingVisitor> {
103 public:
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 
121 private:
122  const NamedDecl *Result = nullptr;
123  StringRef Name;
124 };
125 
126 } // end anonymous namespace
127 
128 const NamedDecl *getNamedDeclFor(const ASTContext &Context,
129  const std::string &Name) {
130  NamedDeclFindingVisitor Visitor(Name);
131  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
132  return Visitor.getNamedDecl();
133 }
134 
135 std::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:83
A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol.
SourceRange Range
Definition: SemaObjC.cpp:754
Defines the SourceManager interface.
Methods for determining the USR of a symbol at a location in source code.
SourceLocation End
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
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