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 LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTMACROS_H 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 Range toRange(const SourceManager &SM) const; 35 }; 36 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; 46 }; 47 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) {} 56 57 void FileChanged(SourceLocation Loc, FileChangeReason, 58 SrcMgr::CharacteristicKind, FileID) override; 59 60 void MacroDefined(const Token &MacroName, const MacroDirective *MD) override; 61 62 void MacroExpands(const Token &MacroName, const MacroDefinition &MD, 63 SourceRange Range, const MacroArgs *Args) override; 64 65 void MacroUndefined(const clang::Token &MacroName, 66 const clang::MacroDefinition &MD, 67 const clang::MacroDirective *Undef) override; 68 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; 79 80 void Defined(const Token &MacroName, const MacroDefinition &MD, 81 SourceRange Range) override; 82 83 void SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) override; 84 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; } 92 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; 100 }; 101 102 /// Represents a `#pragma mark` in the main file. 103 /// 104 /// There can be at most one pragma mark per line. 105 struct PragmaMark { 106 Range Rng; 107 std::string Trivia; 108 }; 109 110 /// Collect all pragma marks from the main file. 111 std::unique_ptr<PPCallbacks> 112 collectPragmaMarksCallback(const SourceManager &, std::vector<PragmaMark> &Out); 113 114 } // namespace clangd 115 } // namespace clang 116 117 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTMACROS_H 118