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 /// 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 23 namespace clang { 24 namespace tooling { 25 26 /// Traverses the AST and visits the occurrence of each named symbol in the 27 /// given nodes. 28 template <typename T> 29 class RecursiveSymbolVisitor 30 : public RecursiveASTVisitor<RecursiveSymbolVisitor<T>> { 31 using BaseType = RecursiveASTVisitor<RecursiveSymbolVisitor<T>>; 32 33 public: RecursiveSymbolVisitor(const SourceManager & SM,const LangOptions & LangOpts)34 RecursiveSymbolVisitor(const SourceManager &SM, const LangOptions &LangOpts) 35 : SM(SM), LangOpts(LangOpts) {} 36 visitSymbolOccurrence(const NamedDecl * ND,ArrayRef<SourceRange> NameRanges)37 bool visitSymbolOccurrence(const NamedDecl *ND, 38 ArrayRef<SourceRange> NameRanges) { 39 return true; 40 } 41 42 // Declaration visitors: 43 VisitNamedDecl(const NamedDecl * D)44 bool VisitNamedDecl(const NamedDecl *D) { 45 return isa<CXXConversionDecl>(D) ? true : visit(D, D->getLocation()); 46 } 47 VisitCXXConstructorDecl(const CXXConstructorDecl * CD)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 VisitDeclRefExpr(const DeclRefExpr * Expr)65 bool VisitDeclRefExpr(const DeclRefExpr *Expr) { 66 return visit(Expr->getFoundDecl(), Expr->getLocation()); 67 } 68 VisitMemberExpr(const MemberExpr * Expr)69 bool VisitMemberExpr(const MemberExpr *Expr) { 70 return visit(Expr->getFoundDecl().getDecl(), Expr->getMemberLoc()); 71 } 72 VisitOffsetOfExpr(const OffsetOfExpr * S)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())) 78 return false; 79 } 80 // FIXME: Try to resolve dependent field references. 81 } 82 return true; 83 } 84 85 // Other visitors: 86 VisitTypeLoc(const TypeLoc Loc)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)) 94 return false; 95 } 96 if (const auto *TemplateSpecType = 97 dyn_cast<TemplateSpecializationType>(Loc.getType())) { 98 if (!visit(TemplateSpecType->getTemplateName().getAsTemplateDecl(), 99 TypeBeginLoc, TypeEndLoc)) 100 return false; 101 } 102 return visit(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc); 103 } 104 TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)105 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { 106 // The base visitor will visit NNSL prefixes, so we should only look at 107 // the current NNS. 108 if (NNS) { 109 const NamespaceDecl *ND = NNS.getNestedNameSpecifier()->getAsNamespace(); 110 if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc())) 111 return false; 112 } 113 return BaseType::TraverseNestedNameSpecifierLoc(NNS); 114 } 115 116 private: 117 const SourceManager &SM; 118 const LangOptions &LangOpts; 119 visit(const NamedDecl * ND,SourceLocation BeginLoc,SourceLocation EndLoc)120 bool visit(const NamedDecl *ND, SourceLocation BeginLoc, 121 SourceLocation EndLoc) { 122 return static_cast<T *>(this)->visitSymbolOccurrence( 123 ND, SourceRange(BeginLoc, EndLoc)); 124 } visit(const NamedDecl * ND,SourceLocation Loc)125 bool visit(const NamedDecl *ND, SourceLocation Loc) { 126 return visit(ND, Loc, 127 Loc.getLocWithOffset(ND->getNameAsString().length() - 1)); 128 } 129 }; 130 131 } // end namespace tooling 132 } // end namespace clang 133 134 #endif // LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H 135