xref: /llvm-project/clang-tools-extra/clangd/CollectMacros.h (revision ee6961dbf13167bf09b602b136d72f72d7c8ff0c)
17e3c74bcSHaojian Wu //===--- CollectMacros.h -----------------------------------------*- C++-*-===//
27e3c74bcSHaojian Wu //
37e3c74bcSHaojian Wu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47e3c74bcSHaojian Wu // See https://llvm.org/LICENSE.txt for license information.
57e3c74bcSHaojian Wu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67e3c74bcSHaojian Wu //
77e3c74bcSHaojian Wu //===----------------------------------------------------------------------===//
87e3c74bcSHaojian Wu 
95bd643d3SChristian Kühnel #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTMACROS_H
105bd643d3SChristian Kühnel #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTMACROS_H
117e3c74bcSHaojian Wu 
127e3c74bcSHaojian Wu #include "Protocol.h"
137e3c74bcSHaojian Wu #include "SourceCode.h"
142054ed05SUtkarsh Saxena #include "index/SymbolID.h"
153ddfea07SHaojian Wu #include "clang/Basic/SourceLocation.h"
167e3c74bcSHaojian Wu #include "clang/Lex/PPCallbacks.h"
17002c4b7bSHaojian Wu #include "clang/Lex/Preprocessor.h"
182054ed05SUtkarsh Saxena #include "llvm/ADT/DenseMap.h"
197298bcf7SHaojian Wu #include <cstddef>
207e3c74bcSHaojian Wu #include <string>
217e3c74bcSHaojian Wu 
227e3c74bcSHaojian Wu namespace clang {
237e3c74bcSHaojian Wu namespace clangd {
247e3c74bcSHaojian Wu 
252e25be0bSAleksandr Platonov struct MacroOccurrence {
267298bcf7SHaojian Wu   // Half-open range (end offset is exclusive) inside the main file.
277298bcf7SHaojian Wu   size_t StartOffset;
287298bcf7SHaojian Wu   size_t EndOffset;
297298bcf7SHaojian Wu 
302e25be0bSAleksandr Platonov   bool IsDefinition;
31002c4b7bSHaojian Wu   // True if the occurence is used in a conditional directive, e.g. #ifdef MACRO
32002c4b7bSHaojian Wu   bool InConditionalDirective;
337298bcf7SHaojian Wu 
347298bcf7SHaojian Wu   Range toRange(const SourceManager &SM) const;
352e25be0bSAleksandr Platonov };
362e25be0bSAleksandr Platonov 
372e25be0bSAleksandr Platonov struct MainFileMacros {
382e25be0bSAleksandr Platonov   llvm::StringSet<> Names;
392e25be0bSAleksandr Platonov   llvm::DenseMap<SymbolID, std::vector<MacroOccurrence>> MacroRefs;
402054ed05SUtkarsh Saxena   // Somtimes it is not possible to compute the SymbolID for the Macro, e.g. a
412054ed05SUtkarsh Saxena   // reference to an undefined macro. Store them separately, e.g. for semantic
422054ed05SUtkarsh Saxena   // highlighting.
432e25be0bSAleksandr Platonov   std::vector<MacroOccurrence> UnknownMacros;
44b2e6c2b9SNathan Ridge   // Ranges skipped by the preprocessor due to being inactive.
45b2e6c2b9SNathan Ridge   std::vector<Range> SkippedRanges;
467e3c74bcSHaojian Wu };
477e3c74bcSHaojian Wu 
482fa81d20SHaojian Wu /// Collects macro references (e.g. definitions, expansions) in the main file.
492fa81d20SHaojian Wu /// It is used to:
507e3c74bcSHaojian Wu ///  - collect macros in the preamble section of the main file (in Preamble.cpp)
517e3c74bcSHaojian Wu ///  - collect macros after the preamble of the main file (in ParsedAST.cpp)
527e3c74bcSHaojian Wu class CollectMainFileMacros : public PPCallbacks {
537e3c74bcSHaojian Wu public:
54002c4b7bSHaojian Wu   explicit CollectMainFileMacros(const Preprocessor &PP, MainFileMacros &Out)
55002c4b7bSHaojian Wu       : SM(PP.getSourceManager()), PP(PP), Out(Out) {}
567e3c74bcSHaojian Wu 
577e3c74bcSHaojian Wu   void FileChanged(SourceLocation Loc, FileChangeReason,
58002c4b7bSHaojian Wu                    SrcMgr::CharacteristicKind, FileID) override;
597e3c74bcSHaojian Wu 
60002c4b7bSHaojian Wu   void MacroDefined(const Token &MacroName, const MacroDirective *MD) override;
617e3c74bcSHaojian Wu 
627e3c74bcSHaojian Wu   void MacroExpands(const Token &MacroName, const MacroDefinition &MD,
63002c4b7bSHaojian Wu                     SourceRange Range, const MacroArgs *Args) override;
647e3c74bcSHaojian Wu 
652fa81d20SHaojian Wu   void MacroUndefined(const clang::Token &MacroName,
662fa81d20SHaojian Wu                       const clang::MacroDefinition &MD,
67002c4b7bSHaojian Wu                       const clang::MacroDirective *Undef) override;
682fa81d20SHaojian Wu 
692fa81d20SHaojian Wu   void Ifdef(SourceLocation Loc, const Token &MacroName,
70002c4b7bSHaojian Wu              const MacroDefinition &MD) override;
712fa81d20SHaojian Wu   void Ifndef(SourceLocation Loc, const Token &MacroName,
72002c4b7bSHaojian Wu               const MacroDefinition &MD) override;
733ddfea07SHaojian Wu   using PPCallbacks::Elifdef;
743ddfea07SHaojian Wu   using PPCallbacks::Elifndef;
753ddfea07SHaojian Wu   void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
763ddfea07SHaojian Wu                const MacroDefinition &MD) override;
773ddfea07SHaojian Wu   void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
783ddfea07SHaojian Wu                 const MacroDefinition &MD) override;
792fa81d20SHaojian Wu 
802fa81d20SHaojian Wu   void Defined(const Token &MacroName, const MacroDefinition &MD,
81002c4b7bSHaojian Wu                SourceRange Range) override;
822fa81d20SHaojian Wu 
83002c4b7bSHaojian Wu   void SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) override;
84b2e6c2b9SNathan Ridge 
85*ee6961dbSNathan Ridge   // Called when the AST build is done to disable further recording
86*ee6961dbSNathan Ridge   // of macros by this class. This is needed because some clang-tidy
87*ee6961dbSNathan Ridge   // checks can trigger PP callbacks by calling directly into the
88*ee6961dbSNathan Ridge   // preprocessor. Such calls are not interleaved with FileChanged()
89*ee6961dbSNathan Ridge   // in the expected way, leading this class to erroneously process
90*ee6961dbSNathan Ridge   // macros that are not in the main file.
91*ee6961dbSNathan Ridge   void doneParse() { InMainFile = false; }
92*ee6961dbSNathan Ridge 
937e3c74bcSHaojian Wu private:
942e25be0bSAleksandr Platonov   void add(const Token &MacroNameTok, const MacroInfo *MI,
95002c4b7bSHaojian Wu            bool IsDefinition = false, bool InConditionalDirective = false);
967e3c74bcSHaojian Wu   const SourceManager &SM;
97002c4b7bSHaojian Wu   const Preprocessor &PP;
987e3c74bcSHaojian Wu   bool InMainFile = true;
997e3c74bcSHaojian Wu   MainFileMacros &Out;
1007e3c74bcSHaojian Wu };
1017e3c74bcSHaojian Wu 
102d75fb1eeSDavid Goldman /// Represents a `#pragma mark` in the main file.
103d75fb1eeSDavid Goldman ///
104d75fb1eeSDavid Goldman /// There can be at most one pragma mark per line.
105d75fb1eeSDavid Goldman struct PragmaMark {
106d75fb1eeSDavid Goldman   Range Rng;
107d75fb1eeSDavid Goldman   std::string Trivia;
108d75fb1eeSDavid Goldman };
109d75fb1eeSDavid Goldman 
110d75fb1eeSDavid Goldman /// Collect all pragma marks from the main file.
111d75fb1eeSDavid Goldman std::unique_ptr<PPCallbacks>
112d75fb1eeSDavid Goldman collectPragmaMarksCallback(const SourceManager &, std::vector<PragmaMark> &Out);
113d75fb1eeSDavid Goldman 
1147e3c74bcSHaojian Wu } // namespace clangd
1157e3c74bcSHaojian Wu } // namespace clang
1167e3c74bcSHaojian Wu 
1175bd643d3SChristian Kühnel #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_COLLECTMACROS_H
118