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