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