]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Tooling / Refactoring / Rename / USRFinder.cpp
1 //===--- USRFinder.cpp - Clang refactoring library ------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file Implements a recursive AST visitor that finds the USR of a symbol at a
11 /// point.
12 ///
13 //===----------------------------------------------------------------------===//
14
15 #include "clang/Tooling/Refactoring/Rename/USRFinder.h"
16 #include "clang/AST/AST.h"
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/RecursiveASTVisitor.h"
19 #include "clang/Index/USRGeneration.h"
20 #include "clang/Lex/Lexer.h"
21 #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.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) {
136   llvm::SmallVector<char, 128> Buff;
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.data(), Buff.size());
143 }
144
145 } // end namespace tooling
146 } // end namespace clang