RecursiveSymbolVisitor.h revision 321238
1//===--- RecursiveSymbolVisitor.h - 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
11/// \brief A wrapper class around \c RecursiveASTVisitor that visits each
12/// occurrences of a named symbol.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
17#define LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
18
19#include "clang/AST/AST.h"
20#include "clang/AST/RecursiveASTVisitor.h"
21#include "clang/Lex/Lexer.h"
22
23namespace clang {
24namespace tooling {
25
26/// Traverses the AST and visits the occurrence of each named symbol in the
27/// given nodes.
28template <typename T>
29class RecursiveSymbolVisitor
30    : public RecursiveASTVisitor<RecursiveSymbolVisitor<T>> {
31  using BaseType = RecursiveASTVisitor<RecursiveSymbolVisitor<T>>;
32
33public:
34  RecursiveSymbolVisitor(const SourceManager &SM, const LangOptions &LangOpts)
35      : SM(SM), LangOpts(LangOpts) {}
36
37  bool visitSymbolOccurrence(const NamedDecl *ND,
38                             ArrayRef<SourceRange> NameRanges) {
39    return true;
40  }
41
42  // Declaration visitors:
43
44  bool VisitNamedDecl(const NamedDecl *D) {
45    return isa<CXXConversionDecl>(D) ? true : visit(D, D->getLocation());
46  }
47
48  bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
49    for (const auto *Initializer : CD->inits()) {
50      // Ignore implicit initializers.
51      if (!Initializer->isWritten())
52        continue;
53      if (const FieldDecl *FD = Initializer->getMember()) {
54        if (!visit(FD, Initializer->getSourceLocation(),
55                   Lexer::getLocForEndOfToken(Initializer->getSourceLocation(),
56                                              0, SM, LangOpts)))
57          return false;
58      }
59    }
60    return true;
61  }
62
63  // Expression visitors:
64
65  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
66    return visit(Expr->getFoundDecl(), Expr->getLocation());
67  }
68
69  bool VisitMemberExpr(const MemberExpr *Expr) {
70    return visit(Expr->getFoundDecl().getDecl(), Expr->getMemberLoc());
71  }
72
73  // Other visitors:
74
75  bool VisitTypeLoc(const TypeLoc Loc) {
76    const SourceLocation TypeBeginLoc = Loc.getBeginLoc();
77    const SourceLocation TypeEndLoc =
78        Lexer::getLocForEndOfToken(TypeBeginLoc, 0, SM, LangOpts);
79    if (const auto *TemplateTypeParm =
80            dyn_cast<TemplateTypeParmType>(Loc.getType())) {
81      if (!visit(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc))
82        return false;
83    }
84    if (const auto *TemplateSpecType =
85            dyn_cast<TemplateSpecializationType>(Loc.getType())) {
86      if (!visit(TemplateSpecType->getTemplateName().getAsTemplateDecl(),
87                 TypeBeginLoc, TypeEndLoc))
88        return false;
89    }
90    return visit(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc);
91  }
92
93  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
94    // The base visitor will visit NNSL prefixes, so we should only look at
95    // the current NNS.
96    if (NNS) {
97      const NamespaceDecl *ND = NNS.getNestedNameSpecifier()->getAsNamespace();
98      if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc()))
99        return false;
100    }
101    return BaseType::TraverseNestedNameSpecifierLoc(NNS);
102  }
103
104private:
105  const SourceManager &SM;
106  const LangOptions &LangOpts;
107
108  bool visit(const NamedDecl *ND, SourceLocation BeginLoc,
109             SourceLocation EndLoc) {
110    return static_cast<T *>(this)->visitSymbolOccurrence(
111        ND, SourceRange(BeginLoc, EndLoc));
112  }
113  bool visit(const NamedDecl *ND, SourceLocation Loc) {
114    return visit(ND, Loc,
115                 Loc.getLocWithOffset(ND->getNameAsString().length() - 1));
116  }
117};
118
119} // end namespace tooling
120} // end namespace clang
121
122#endif // LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
123