1 | //===--- LocateSymbol.cpp - Find locations providing a symbol -------------===// |
---|---|
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 "AnalysisInternal.h" |
10 | #include "clang-include-cleaner/Types.h" |
11 | #include "clang/AST/Decl.h" |
12 | #include "clang/AST/DeclBase.h" |
13 | #include "clang/AST/DeclCXX.h" |
14 | #include "clang/AST/DeclTemplate.h" |
15 | #include "clang/Tooling/Inclusions/StandardLibrary.h" |
16 | #include "llvm/Support/Casting.h" |
17 | #include <utility> |
18 | #include <vector> |
19 | |
20 | namespace clang::include_cleaner { |
21 | namespace { |
22 | |
23 | template <typename T> Hints completeIfDefinition(T *D) { |
24 | return D->isThisDeclarationADefinition() ? Hints::CompleteSymbol |
25 | : Hints::None; |
26 | } |
27 | |
28 | Hints declHints(const Decl *D) { |
29 | // Definition is only needed for classes and templates for completeness. |
30 | if (auto *TD = llvm::dyn_cast<TagDecl>(Val: D)) |
31 | return completeIfDefinition(D: TD); |
32 | else if (auto *CTD = llvm::dyn_cast<ClassTemplateDecl>(Val: D)) |
33 | return completeIfDefinition(D: CTD); |
34 | else if (auto *FTD = llvm::dyn_cast<FunctionTemplateDecl>(Val: D)) |
35 | return completeIfDefinition(D: FTD); |
36 | // Any other declaration is assumed usable. |
37 | return Hints::CompleteSymbol; |
38 | } |
39 | |
40 | std::vector<Hinted<SymbolLocation>> locateDecl(const Decl &D) { |
41 | std::vector<Hinted<SymbolLocation>> Result; |
42 | // FIXME: Should we also provide physical locations? |
43 | if (auto SS = tooling::stdlib::Recognizer()(&D)) |
44 | return {{*SS, Hints::CompleteSymbol}}; |
45 | // FIXME: Signal foreign decls, e.g. a forward declaration not owned by a |
46 | // library. Some useful signals could be derived by checking the DeclContext. |
47 | // Most incidental forward decls look like: |
48 | // namespace clang { |
49 | // class SourceManager; // likely an incidental forward decl. |
50 | // namespace my_own_ns {} |
51 | // } |
52 | for (auto *Redecl : D.redecls()) |
53 | Result.push_back(x: {Redecl->getLocation(), declHints(D: Redecl)}); |
54 | return Result; |
55 | } |
56 | |
57 | std::vector<Hinted<SymbolLocation>> locateMacro(const Macro &M) { |
58 | // FIXME: Should we also provide physical locations? |
59 | if (auto SS = tooling::stdlib::Symbol::named(Scope: "", Name: M.Name->getName())) |
60 | return {{*SS, Hints::CompleteSymbol}}; |
61 | return {{M.Definition, Hints::CompleteSymbol}}; |
62 | } |
63 | } // namespace |
64 | |
65 | std::vector<Hinted<SymbolLocation>> locateSymbol(const Symbol &S) { |
66 | switch (S.kind()) { |
67 | case Symbol::Declaration: |
68 | return locateDecl(D: S.declaration()); |
69 | case Symbol::Macro: |
70 | return locateMacro(M: S.macro()); |
71 | } |
72 | llvm_unreachable("Unknown Symbol::Kind enum"); |
73 | } |
74 | |
75 | } // namespace clang::include_cleaner |
76 |