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