1 //===--- RecursiveSymbolVisitor.h - Clang refactoring library -------------===//
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
7 //===----------------------------------------------------------------------===//
10 /// A wrapper class around \c RecursiveASTVisitor that visits each
11 /// occurrences of a named symbol.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
16 #define LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
18 #include "clang/AST/AST.h"
19 #include "clang/AST/RecursiveASTVisitor.h"
20 #include "clang/Lex/Lexer.h"
25 /// Traverses the AST and visits the occurrence of each named symbol in the
28 class RecursiveSymbolVisitor
29 : public RecursiveASTVisitor<RecursiveSymbolVisitor<T>> {
30 using BaseType = RecursiveASTVisitor<RecursiveSymbolVisitor<T>>;
33 RecursiveSymbolVisitor(const SourceManager &SM, const LangOptions &LangOpts)
34 : SM(SM), LangOpts(LangOpts) {}
36 bool visitSymbolOccurrence(const NamedDecl *ND,
37 ArrayRef<SourceRange> NameRanges) {
41 // Declaration visitors:
43 bool VisitNamedDecl(const NamedDecl *D) {
44 return isa<CXXConversionDecl>(D) ? true : visit(D, D->getLocation());
47 bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
48 for (const auto *Initializer : CD->inits()) {
49 // Ignore implicit initializers.
50 if (!Initializer->isWritten())
52 if (const FieldDecl *FD = Initializer->getMember()) {
53 if (!visit(FD, Initializer->getSourceLocation(),
54 Lexer::getLocForEndOfToken(Initializer->getSourceLocation(),
62 // Expression visitors:
64 bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
65 return visit(Expr->getFoundDecl(), Expr->getLocation());
68 bool VisitMemberExpr(const MemberExpr *Expr) {
69 return visit(Expr->getFoundDecl().getDecl(), Expr->getMemberLoc());
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()))
79 // FIXME: Try to resolve dependent field references.
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))
95 if (const auto *TemplateSpecType =
96 dyn_cast<TemplateSpecializationType>(Loc.getType())) {
97 if (!visit(TemplateSpecType->getTemplateName().getAsTemplateDecl(),
98 TypeBeginLoc, TypeEndLoc))
101 if (const Type *TP = Loc.getTypePtr()) {
102 if (TP->getTypeClass() == clang::Type::Record)
103 return visit(TP->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc);
108 bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
109 const SourceLocation TypeEndLoc =
110 Lexer::getLocForEndOfToken(TL.getBeginLoc(), 0, SM, LangOpts);
111 return visit(TL.getTypedefNameDecl(), TL.getBeginLoc(), TypeEndLoc);
114 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
115 // The base visitor will visit NNSL prefixes, so we should only look at
118 const NamespaceDecl *ND = NNS.getNestedNameSpecifier()->getAsNamespace();
119 if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc()))
122 return BaseType::TraverseNestedNameSpecifierLoc(NNS);
126 const SourceManager &SM;
127 const LangOptions &LangOpts;
129 bool visit(const NamedDecl *ND, SourceLocation BeginLoc,
130 SourceLocation EndLoc) {
131 return static_cast<T *>(this)->visitSymbolOccurrence(
132 ND, SourceRange(BeginLoc, EndLoc));
134 bool visit(const NamedDecl *ND, SourceLocation Loc) {
135 return visit(ND, Loc, Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts));
139 } // end namespace tooling
140 } // end namespace clang
142 #endif // LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H