Coverage Report

Created: 2020-09-22 08:39

/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/Basic/SourceManager.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
76
        Point(Point), Context(Context) {}
42
43
  bool visitSymbolOccurrence(const NamedDecl *ND,
44
401
                             ArrayRef<SourceRange> NameRanges) {
45
401
    if (!ND)
46
3
      return true;
47
398
    for (const auto &Range : NameRanges) {
48
398
      SourceLocation Start = Range.getBegin();
49
398
      SourceLocation End = Range.getEnd();
50
398
      if (!Start.isValid() || !Start.isFileID() || 
!End.isValid()393
||
51
393
          !End.isFileID() || !isPointWithin(Start, End))
52
330
        return true;
53
398
    }
54
68
    Result = ND;
55
68
    return false;
56
398
  }
57
58
76
  const NamedDecl *getNamedDecl() const { return Result; }
59
60
private:
61
  // Determines if the Point is within Start and End.
62
393
  bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
63
    // FIXME: Add tests for Point == End.
64
393
    return Point == Start || 
Point == End332
||
65
332
           (Context.getSourceManager().isBeforeInTranslationUnit(Start,
66
332
                                                                 Point) &&
67
319
            Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
68
393
  }
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
76
                                const SourceLocation Point) {
79
76
  const SourceManager &SM = Context.getSourceManager();
80
76
  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
651
  for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
86
651
    SourceLocation StartLoc = CurrDecl->getBeginLoc();
87
651
    SourceLocation EndLoc = CurrDecl->getEndLoc();
88
651
    if (StartLoc.isValid() && 
EndLoc.isValid()243
&&
89
243
        SM.isBeforeInTranslationUnit(StartLoc, Point) !=
90
243
            SM.isBeforeInTranslationUnit(EndLoc, Point))
91
69
      Visitor.TraverseDecl(CurrDecl);
92
651
  }
93
94
76
  return Visitor.getNamedDecl();
95
76
}
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
270
  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
2.46k
  bool VisitNamedDecl(const NamedDecl *ND) {
109
2.46k
    if (!ND)
110
0
      return true;
111
    // Fully qualified name is used to find the declaration.
112
2.46k
    if (Name != ND->getQualifiedNameAsString() &&
113
2.21k
        Name != "::" + ND->getQualifiedNameAsString())
114
2.19k
      return true;
115
268
    Result = ND;
116
268
    return false;
117
268
  }
118
119
270
  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
270
                                 const std::string &Name) {
130
270
  NamedDeclFindingVisitor Visitor(Name);
131
270
  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
132
270
  return Visitor.getNamedDecl();
133
270
}
134
135
10.4k
std::string getUSRForDecl(const Decl *Decl) {
136
10.4k
  llvm::SmallVector<char, 128> Buff;
137
138
  // FIXME: Add test for the nullptr case.
139
10.4k
  if (Decl == nullptr || 
index::generateUSRForDecl(Decl, Buff)10.2k
)
140
216
    return "";
141
142
10.2k
  return std::string(Buff.data(), Buff.size());
143
10.2k
}
144
145
} // end namespace tooling
146
} // end namespace clang