1 | //===--- CollectMacros.h -----------------------------------------*- 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 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTMACROS_H |
10 | #define |
11 | |
12 | #include "Protocol.h" |
13 | #include "SourceCode.h" |
14 | #include "index/SymbolID.h" |
15 | #include "clang/Basic/SourceLocation.h" |
16 | #include "clang/Lex/PPCallbacks.h" |
17 | #include "clang/Lex/Preprocessor.h" |
18 | #include "llvm/ADT/DenseMap.h" |
19 | #include <cstddef> |
20 | #include <string> |
21 | |
22 | namespace clang { |
23 | namespace clangd { |
24 | |
25 | struct MacroOccurrence { |
26 | // Half-open range (end offset is exclusive) inside the main file. |
27 | size_t StartOffset; |
28 | size_t EndOffset; |
29 | |
30 | bool IsDefinition; |
31 | // True if the occurence is used in a conditional directive, e.g. #ifdef MACRO |
32 | bool InConditionalDirective; |
33 | |
34 | CharSourceRange toSourceRange(const SourceManager &SM) const; |
35 | Range toRange(const SourceManager &SM) const; |
36 | }; |
37 | |
38 | struct MainFileMacros { |
39 | llvm::StringSet<> Names; |
40 | llvm::DenseMap<SymbolID, std::vector<MacroOccurrence>> MacroRefs; |
41 | // Somtimes it is not possible to compute the SymbolID for the Macro, e.g. a |
42 | // reference to an undefined macro. Store them separately, e.g. for semantic |
43 | // highlighting. |
44 | std::vector<MacroOccurrence> UnknownMacros; |
45 | // Ranges skipped by the preprocessor due to being inactive. |
46 | std::vector<Range> SkippedRanges; |
47 | }; |
48 | |
49 | /// Collects macro references (e.g. definitions, expansions) in the main file. |
50 | /// It is used to: |
51 | /// - collect macros in the preamble section of the main file (in Preamble.cpp) |
52 | /// - collect macros after the preamble of the main file (in ParsedAST.cpp) |
53 | class CollectMainFileMacros : public PPCallbacks { |
54 | public: |
55 | explicit CollectMainFileMacros(const Preprocessor &PP, MainFileMacros &Out) |
56 | : SM(PP.getSourceManager()), PP(PP), Out(Out) {} |
57 | |
58 | void FileChanged(SourceLocation Loc, FileChangeReason, |
59 | SrcMgr::CharacteristicKind, FileID) override; |
60 | |
61 | void MacroDefined(const Token &MacroName, const MacroDirective *MD) override; |
62 | |
63 | void MacroExpands(const Token &MacroName, const MacroDefinition &MD, |
64 | SourceRange Range, const MacroArgs *Args) override; |
65 | |
66 | void MacroUndefined(const clang::Token &MacroName, |
67 | const clang::MacroDefinition &MD, |
68 | const clang::MacroDirective *Undef) override; |
69 | |
70 | void Ifdef(SourceLocation Loc, const Token &MacroName, |
71 | const MacroDefinition &MD) override; |
72 | void Ifndef(SourceLocation Loc, const Token &MacroName, |
73 | const MacroDefinition &MD) override; |
74 | using PPCallbacks::Elifdef; |
75 | using PPCallbacks::Elifndef; |
76 | void Elifdef(SourceLocation Loc, const Token &MacroNameTok, |
77 | const MacroDefinition &MD) override; |
78 | void Elifndef(SourceLocation Loc, const Token &MacroNameTok, |
79 | const MacroDefinition &MD) override; |
80 | |
81 | void Defined(const Token &MacroName, const MacroDefinition &MD, |
82 | SourceRange Range) override; |
83 | |
84 | void SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) override; |
85 | |
86 | // Called when the AST build is done to disable further recording |
87 | // of macros by this class. This is needed because some clang-tidy |
88 | // checks can trigger PP callbacks by calling directly into the |
89 | // preprocessor. Such calls are not interleaved with FileChanged() |
90 | // in the expected way, leading this class to erroneously process |
91 | // macros that are not in the main file. |
92 | void doneParse() { InMainFile = false; } |
93 | |
94 | private: |
95 | void add(const Token &MacroNameTok, const MacroInfo *MI, |
96 | bool IsDefinition = false, bool InConditionalDirective = false); |
97 | const SourceManager &SM; |
98 | const Preprocessor &PP; |
99 | bool InMainFile = true; |
100 | MainFileMacros &Out; |
101 | }; |
102 | |
103 | /// Represents a `#pragma mark` in the main file. |
104 | /// |
105 | /// There can be at most one pragma mark per line. |
106 | struct PragmaMark { |
107 | Range Rng; |
108 | std::string Trivia; |
109 | }; |
110 | |
111 | /// Collect all pragma marks from the main file. |
112 | std::unique_ptr<PPCallbacks> |
113 | collectPragmaMarksCallback(const SourceManager &, std::vector<PragmaMark> &Out); |
114 | |
115 | } // namespace clangd |
116 | } // namespace clang |
117 | |
118 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTMACROS_H |
119 | |