1 //===--- RecursiveSymbolVisitor.h - Clang refactoring library -------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief A wrapper class around \c RecursiveASTVisitor that visits each
12 /// occurrences of a named symbol.
14 //===----------------------------------------------------------------------===//
16 #ifndef LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
17 #define LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
19 #include "clang/AST/AST.h"
20 #include "clang/AST/RecursiveASTVisitor.h"
21 #include "clang/Lex/Lexer.h"
26 /// Traverses the AST and visits the occurrence of each named symbol in the
29 class RecursiveSymbolVisitor
30 : public RecursiveASTVisitor<RecursiveSymbolVisitor<T>> {
31 using BaseType = RecursiveASTVisitor<RecursiveSymbolVisitor<T>>;
34 RecursiveSymbolVisitor(const SourceManager &SM, const LangOptions &LangOpts)
35 : SM(SM), LangOpts(LangOpts) {}
37 bool visitSymbolOccurrence(const NamedDecl *ND,
38 ArrayRef<SourceRange> NameRanges) {
42 // Declaration visitors:
44 bool VisitNamedDecl(const NamedDecl *D) {
45 return isa<CXXConversionDecl>(D) ? true : visit(D, D->getLocation());
48 bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
49 for (const auto *Initializer : CD->inits()) {
50 // Ignore implicit initializers.
51 if (!Initializer->isWritten())
53 if (const FieldDecl *FD = Initializer->getMember()) {
54 if (!visit(FD, Initializer->getSourceLocation(),
55 Lexer::getLocForEndOfToken(Initializer->getSourceLocation(),
63 // Expression visitors:
65 bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
66 return visit(Expr->getFoundDecl(), Expr->getLocation());
69 bool VisitMemberExpr(const MemberExpr *Expr) {
70 return visit(Expr->getFoundDecl().getDecl(), Expr->getMemberLoc());
73 bool VisitOffsetOfExpr(const OffsetOfExpr *S) {
74 for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) {
75 const OffsetOfNode &Component = S->getComponent(I);
76 if (Component.getKind() == OffsetOfNode::Field) {
77 if (!visit(Component.getField(), Component.getLocEnd()))
80 // FIXME: Try to resolve dependent field references.
87 bool VisitTypeLoc(const TypeLoc Loc) {
88 const SourceLocation TypeBeginLoc = Loc.getBeginLoc();
89 const SourceLocation TypeEndLoc =
90 Lexer::getLocForEndOfToken(TypeBeginLoc, 0, SM, LangOpts);
91 if (const auto *TemplateTypeParm =
92 dyn_cast<TemplateTypeParmType>(Loc.getType())) {
93 if (!visit(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc))
96 if (const auto *TemplateSpecType =
97 dyn_cast<TemplateSpecializationType>(Loc.getType())) {
98 if (!visit(TemplateSpecType->getTemplateName().getAsTemplateDecl(),
99 TypeBeginLoc, TypeEndLoc))
102 return visit(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc);
105 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
106 // The base visitor will visit NNSL prefixes, so we should only look at
109 const NamespaceDecl *ND = NNS.getNestedNameSpecifier()->getAsNamespace();
110 if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc()))
113 return BaseType::TraverseNestedNameSpecifierLoc(NNS);
117 const SourceManager &SM;
118 const LangOptions &LangOpts;
120 bool visit(const NamedDecl *ND, SourceLocation BeginLoc,
121 SourceLocation EndLoc) {
122 return static_cast<T *>(this)->visitSymbolOccurrence(
123 ND, SourceRange(BeginLoc, EndLoc));
125 bool visit(const NamedDecl *ND, SourceLocation Loc) {
126 return visit(ND, Loc,
127 Loc.getLocWithOffset(ND->getNameAsString().length() - 1));
131 } // end namespace tooling
132 } // end namespace clang
134 #endif // LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H