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