Coverage Report

Created: 2020-02-15 09:57

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
Line
Count
Source (jump to first uncovered line)
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
14
#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
15
#include "clang/AST/AST.h"
16
#include "clang/AST/ASTContext.h"
17
#include "clang/AST/RecursiveASTVisitor.h"
18
#include "clang/Index/USRGeneration.h"
19
#include "clang/Lex/Lexer.h"
20
#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
21
#include "llvm/ADT/SmallVector.h"
22
23
using namespace llvm;
24
25
namespace clang {
26
namespace tooling {
27
28
namespace {
29
30
/// Recursively visits each AST node to find the symbol underneath the cursor.
31
class NamedDeclOccurrenceFindingVisitor
32
    : public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {
33
public:
34
  // Finds the NamedDecl at a point in the source.
35
  // \param Point the location in the source to search for the NamedDecl.
36
  explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,
37
                                             const ASTContext &Context)
38
      : RecursiveSymbolVisitor(Context.getSourceManager(),
39
                               Context.getLangOpts()),
40
76
        Point(Point), Context(Context) {}
41
42
  bool visitSymbolOccurrence(const NamedDecl *ND,
43
401
                             ArrayRef<SourceRange> NameRanges) {
44
401
    if (!ND)
45
3
      return true;
46
398
    for (const auto &Range : NameRanges) {
47
398
      SourceLocation Start = Range.getBegin();
48
398
      SourceLocation End = Range.getEnd();
49
398
      if (!Start.isValid() || !Start.isFileID() || 
!End.isValid()393
||
50
398
          
!End.isFileID()393
||
!isPointWithin(Start, End)393
)
51
330
        return true;
52
398
    }
53
398
    Result = ND;
54
68
    return false;
55
398
  }
56
57
76
  const NamedDecl *getNamedDecl() const { return Result; }
58
59
private:
60
  // Determines if the Point is within Start and End.
61
393
  bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
62
393
    // FIXME: Add tests for Point == End.
63
393
    return Point == Start || 
Point == End332
||
64
393
           
(332
Context.getSourceManager().isBeforeInTranslationUnit(Start,
65
332
                                                                 Point) &&
66
332
            
Context.getSourceManager().isBeforeInTranslationUnit(Point, End)319
);
67
393
  }
68
69
  const NamedDecl *Result = nullptr;
70
  const SourceLocation Point; // The location to find the NamedDecl.
71
  const ASTContext &Context;
72
};
73
74
} // end anonymous namespace
75
76
const NamedDecl *getNamedDeclAt(const ASTContext &Context,
77
76
                                const SourceLocation Point) {
78
76
  const SourceManager &SM = Context.getSourceManager();
79
76
  NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);
80
76
81
76
  // Try to be clever about pruning down the number of top-level declarations we
82
76
  // see. If both start and end is either before or after the point we're
83
76
  // looking for the point cannot be inside of this decl. Don't even look at it.
84
651
  for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
85
651
    SourceLocation StartLoc = CurrDecl->getBeginLoc();
86
651
    SourceLocation EndLoc = CurrDecl->getEndLoc();
87
651
    if (StartLoc.isValid() && 
EndLoc.isValid()243
&&
88
651
        SM.isBeforeInTranslationUnit(StartLoc, Point) !=
89
243
            SM.isBeforeInTranslationUnit(EndLoc, Point))
90
69
      Visitor.TraverseDecl(CurrDecl);
91
651
  }
92
76
93
76
  return Visitor.getNamedDecl();
94
76
}
95
96
namespace {
97
98
/// Recursively visits each NamedDecl node to find the declaration with a
99
/// specific name.
100
class NamedDeclFindingVisitor
101
    : public RecursiveASTVisitor<NamedDeclFindingVisitor> {
102
public:
103
271
  explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}
104
105
  // We don't have to traverse the uses to find some declaration with a
106
  // specific name, so just visit the named declarations.
107
2.46k
  bool VisitNamedDecl(const NamedDecl *ND) {
108
2.46k
    if (!ND)
109
0
      return true;
110
2.46k
    // Fully qualified name is used to find the declaration.
111
2.46k
    if (Name != ND->getQualifiedNameAsString() &&
112
2.46k
        
Name != "::" + ND->getQualifiedNameAsString()2.21k
)
113
2.19k
      return true;
114
269
    Result = ND;
115
269
    return false;
116
269
  }
117
118
271
  const NamedDecl *getNamedDecl() const { return Result; }
119
120
private:
121
  const NamedDecl *Result = nullptr;
122
  StringRef Name;
123
};
124
125
} // end anonymous namespace
126
127
const NamedDecl *getNamedDeclFor(const ASTContext &Context,
128
271
                                 const std::string &Name) {
129
271
  NamedDeclFindingVisitor Visitor(Name);
130
271
  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
131
271
  return Visitor.getNamedDecl();
132
271
}
133
134
10.4k
std::string getUSRForDecl(const Decl *Decl) {
135
10.4k
  llvm::SmallVector<char, 128> Buff;
136
10.4k
137
10.4k
  // FIXME: Add test for the nullptr case.
138
10.4k
  if (Decl == nullptr || 
index::generateUSRForDecl(Decl, Buff)10.2k
)
139
214
    return "";
140
10.2k
141
10.2k
  return std::string(Buff.data(), Buff.size());
142
10.2k
}
143
144
} // end namespace tooling
145
} // end namespace clang