RecursiveSymbolVisitor.h revision 353358
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