1 //===--- IncludeCleaner.cpp - Unused/Missing Headers Analysis ---*- C++ -*-===// 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 #include "IncludeCleaner.h" 10 #include "support/Logger.h" 11 #include "clang/AST/RecursiveASTVisitor.h" 12 #include "clang/Basic/SourceLocation.h" 13 14 namespace clang { 15 namespace clangd { 16 namespace { 17 18 /// Crawler traverses the AST and feeds in the locations of (sometimes 19 /// implicitly) used symbols into \p Result. 20 class ReferencedLocationCrawler 21 : public RecursiveASTVisitor<ReferencedLocationCrawler> { 22 public: 23 ReferencedLocationCrawler(ReferencedLocations &Result) : Result(Result) {} 24 25 bool VisitDeclRefExpr(DeclRefExpr *DRE) { 26 add(DRE->getDecl()); 27 add(DRE->getFoundDecl()); 28 return true; 29 } 30 31 bool VisitMemberExpr(MemberExpr *ME) { 32 add(ME->getMemberDecl()); 33 add(ME->getFoundDecl().getDecl()); 34 return true; 35 } 36 37 bool VisitTagType(TagType *TT) { 38 add(TT->getDecl()); 39 return true; 40 } 41 42 bool VisitCXXConstructExpr(CXXConstructExpr *CCE) { 43 add(CCE->getConstructor()); 44 return true; 45 } 46 47 bool VisitTemplateSpecializationType(TemplateSpecializationType *TST) { 48 if (isNew(TST)) { 49 add(TST->getTemplateName().getAsTemplateDecl()); // Primary template. 50 add(TST->getAsCXXRecordDecl()); // Specialization 51 } 52 return true; 53 } 54 55 bool VisitTypedefType(TypedefType *TT) { 56 add(TT->getDecl()); 57 return true; 58 } 59 60 // Consider types of any subexpression used, even if the type is not named. 61 // This is helpful in getFoo().bar(), where Foo must be complete. 62 // FIXME(kirillbobyrev): Should we tweak this? It may not be desirable to 63 // consider types "used" when they are not directly spelled in code. 64 bool VisitExpr(Expr *E) { 65 TraverseType(E->getType()); 66 return true; 67 } 68 69 bool TraverseType(QualType T) { 70 if (isNew(T.getTypePtrOrNull())) { // don't care about quals 71 Base::TraverseType(T); 72 } 73 return true; 74 } 75 76 bool VisitUsingDecl(UsingDecl *D) { 77 for (const auto *Shadow : D->shadows()) { 78 add(Shadow->getTargetDecl()); 79 } 80 return true; 81 } 82 83 private: 84 using Base = RecursiveASTVisitor<ReferencedLocationCrawler>; 85 86 void add(const Decl *D) { 87 if (!D || !isNew(D->getCanonicalDecl())) { 88 return; 89 } 90 for (const Decl *Redecl : D->redecls()) { 91 Result.insert(Redecl->getLocation()); 92 } 93 } 94 95 bool isNew(const void *P) { return P && Visited.insert(P).second; } 96 97 ReferencedLocations &Result; 98 llvm::DenseSet<const void *> Visited; 99 }; 100 101 } // namespace 102 103 ReferencedLocations findReferencedLocations(ParsedAST &AST) { 104 ReferencedLocations Result; 105 ReferencedLocationCrawler Crawler(Result); 106 Crawler.TraverseAST(AST.getASTContext()); 107 // FIXME(kirillbobyrev): Handle macros. 108 return Result; 109 } 110 111 } // namespace clangd 112 } // namespace clang 113