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_COLLECTEDMACROS_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTEDMACROS_H
11 
12 #include "AST.h"
13 #include "Protocol.h"
14 #include "SourceCode.h"
15 #include "index/SymbolID.h"
16 #include "clang/Basic/IdentifierTable.h"
17 #include "clang/Lex/PPCallbacks.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include <string>
20 
21 namespace clang {
22 namespace clangd {
23 
24 struct MainFileMacros {
25   llvm::StringSet<> Names;
26   // Instead of storing SourceLocation, we have to store the token range because
27   // SourceManager from preamble is not available when we build the AST.
28   llvm::DenseMap<SymbolID, std::vector<Range>> MacroRefs;
29   // Somtimes it is not possible to compute the SymbolID for the Macro, e.g. a
30   // reference to an undefined macro. Store them separately, e.g. for semantic
31   // highlighting.
32   std::vector<Range> UnknownMacros;
33   // Ranges skipped by the preprocessor due to being inactive.
34   std::vector<Range> SkippedRanges;
35 };
36 
37 /// Collects macro references (e.g. definitions, expansions) in the main file.
38 /// It is used to:
39 ///  - collect macros in the preamble section of the main file (in Preamble.cpp)
40 ///  - collect macros after the preamble of the main file (in ParsedAST.cpp)
41 class CollectMainFileMacros : public PPCallbacks {
42 public:
CollectMainFileMacros(const SourceManager & SM,MainFileMacros & Out)43   explicit CollectMainFileMacros(const SourceManager &SM, MainFileMacros &Out)
44       : SM(SM), Out(Out) {}
45 
FileChanged(SourceLocation Loc,FileChangeReason,SrcMgr::CharacteristicKind,FileID)46   void FileChanged(SourceLocation Loc, FileChangeReason,
47                    SrcMgr::CharacteristicKind, FileID) override {
48     InMainFile = isInsideMainFile(Loc, SM);
49   }
50 
MacroDefined(const Token & MacroName,const MacroDirective * MD)51   void MacroDefined(const Token &MacroName, const MacroDirective *MD) override {
52     add(MacroName, MD->getMacroInfo());
53   }
54 
MacroExpands(const Token & MacroName,const MacroDefinition & MD,SourceRange Range,const MacroArgs * Args)55   void MacroExpands(const Token &MacroName, const MacroDefinition &MD,
56                     SourceRange Range, const MacroArgs *Args) override {
57     add(MacroName, MD.getMacroInfo());
58   }
59 
MacroUndefined(const clang::Token & MacroName,const clang::MacroDefinition & MD,const clang::MacroDirective * Undef)60   void MacroUndefined(const clang::Token &MacroName,
61                       const clang::MacroDefinition &MD,
62                       const clang::MacroDirective *Undef) override {
63     add(MacroName, MD.getMacroInfo());
64   }
65 
Ifdef(SourceLocation Loc,const Token & MacroName,const MacroDefinition & MD)66   void Ifdef(SourceLocation Loc, const Token &MacroName,
67              const MacroDefinition &MD) override {
68     add(MacroName, MD.getMacroInfo());
69   }
70 
Ifndef(SourceLocation Loc,const Token & MacroName,const MacroDefinition & MD)71   void Ifndef(SourceLocation Loc, const Token &MacroName,
72               const MacroDefinition &MD) override {
73     add(MacroName, MD.getMacroInfo());
74   }
75 
Defined(const Token & MacroName,const MacroDefinition & MD,SourceRange Range)76   void Defined(const Token &MacroName, const MacroDefinition &MD,
77                SourceRange Range) override {
78     add(MacroName, MD.getMacroInfo());
79   }
80 
SourceRangeSkipped(SourceRange R,SourceLocation EndifLoc)81   void SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) override {
82     if (!InMainFile)
83       return;
84     Position Begin = sourceLocToPosition(SM, R.getBegin());
85     Position End = sourceLocToPosition(SM, R.getEnd());
86     Out.SkippedRanges.push_back(Range{Begin, End});
87   }
88 
89 private:
90   void add(const Token &MacroNameTok, const MacroInfo *MI);
91   const SourceManager &SM;
92   bool InMainFile = true;
93   MainFileMacros &Out;
94 };
95 
96 } // namespace clangd
97 } // namespace clang
98 
99 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTEDMACROS_H
100