1//===--- CollectMacros.cpp ---------------------------------------*- 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#include "CollectMacros.h"
10#include "AST.h"
11#include "Protocol.h"
12#include "SourceCode.h"
13#include "clang/Basic/SourceLocation.h"
14#include "clang/Tooling/Syntax/Tokens.h"
15#include "llvm/ADT/STLExtras.h"
16#include <cstddef>
17
18namespace clang {
19namespace clangd {
20
21Range MacroOccurrence::toRange(const SourceManager &SM) const {
22 auto MainFile = SM.getMainFileID();
23 return halfOpenToRange(
24 SM, R: syntax::FileRange(MainFile, StartOffset, EndOffset).toCharRange(SM));
25}
26
27void CollectMainFileMacros::add(const Token &MacroNameTok, const MacroInfo *MI,
28 bool IsDefinition, bool InIfCondition) {
29 if (!InMainFile)
30 return;
31 auto Loc = MacroNameTok.getLocation();
32 if (Loc.isInvalid() || Loc.isMacroID())
33 return;
34
35 auto Name = MacroNameTok.getIdentifierInfo()->getName();
36 Out.Names.insert(key: Name);
37 size_t Start = SM.getFileOffset(SpellingLoc: Loc);
38 size_t End = SM.getFileOffset(SpellingLoc: MacroNameTok.getEndLoc());
39 if (auto SID = getSymbolID(MacroName: Name, MI, SM))
40 Out.MacroRefs[SID].push_back(x: {.StartOffset: Start, .EndOffset: End, .IsDefinition: IsDefinition, .InConditionalDirective: InIfCondition});
41 else
42 Out.UnknownMacros.push_back(x: {.StartOffset: Start, .EndOffset: End, .IsDefinition: IsDefinition, .InConditionalDirective: InIfCondition});
43}
44
45void CollectMainFileMacros::FileChanged(SourceLocation Loc, FileChangeReason,
46 SrcMgr::CharacteristicKind, FileID) {
47 InMainFile = isInsideMainFile(Loc, SM);
48}
49
50void CollectMainFileMacros::MacroExpands(const Token &MacroName,
51 const MacroDefinition &MD,
52 SourceRange Range,
53 const MacroArgs *Args) {
54 add(MacroNameTok: MacroName, MI: MD.getMacroInfo());
55}
56
57void CollectMainFileMacros::MacroUndefined(const clang::Token &MacroName,
58 const clang::MacroDefinition &MD,
59 const clang::MacroDirective *Undef) {
60 add(MacroNameTok: MacroName, MI: MD.getMacroInfo());
61}
62
63void CollectMainFileMacros::Ifdef(SourceLocation Loc, const Token &MacroName,
64 const MacroDefinition &MD) {
65 add(MacroNameTok: MacroName, MI: MD.getMacroInfo(), /*IsDefinition=*/false,
66 /*InConditionalDirective=*/InIfCondition: true);
67}
68
69void CollectMainFileMacros::Ifndef(SourceLocation Loc, const Token &MacroName,
70 const MacroDefinition &MD) {
71 add(MacroNameTok: MacroName, MI: MD.getMacroInfo(), /*IsDefinition=*/false,
72 /*InConditionalDirective=*/InIfCondition: true);
73}
74
75void CollectMainFileMacros::Elifdef(SourceLocation Loc, const Token &MacroName,
76 const MacroDefinition &MD) {
77 add(MacroNameTok: MacroName, MI: MD.getMacroInfo(), /*IsDefinition=*/false,
78 /*InConditionalDirective=*/InIfCondition: true);
79}
80
81void CollectMainFileMacros::Elifndef(SourceLocation Loc, const Token &MacroName,
82 const MacroDefinition &MD) {
83 add(MacroNameTok: MacroName, MI: MD.getMacroInfo(), /*IsDefinition=*/false,
84 /*InConditionalDirective=*/InIfCondition: true);
85}
86
87void CollectMainFileMacros::Defined(const Token &MacroName,
88 const MacroDefinition &MD,
89 SourceRange Range) {
90 add(MacroNameTok: MacroName, MI: MD.getMacroInfo(), /*IsDefinition=*/false,
91 /*InConditionalDirective=*/InIfCondition: true);
92}
93
94void CollectMainFileMacros::SourceRangeSkipped(SourceRange R,
95 SourceLocation EndifLoc) {
96 if (!InMainFile)
97 return;
98 Position Begin = sourceLocToPosition(SM, Loc: R.getBegin());
99 Position End = sourceLocToPosition(SM, Loc: R.getEnd());
100 Out.SkippedRanges.push_back(x: Range{.start: Begin, .end: End});
101}
102
103class CollectPragmaMarks : public PPCallbacks {
104public:
105 explicit CollectPragmaMarks(const SourceManager &SM,
106 std::vector<clangd::PragmaMark> &Out)
107 : SM(SM), Out(Out) {}
108
109 void PragmaMark(SourceLocation Loc, StringRef Trivia) override {
110 if (isInsideMainFile(Loc, SM)) {
111 // FIXME: This range should just cover `XX` in `#pragma mark XX` and
112 // `- XX` in `#pragma mark - XX`.
113 Position Start = sourceLocToPosition(SM, Loc);
114 Position End = {.line: Start.line + 1, .character: 0};
115 Out.emplace_back(args: clangd::PragmaMark{.Rng: {.start: Start, .end: End}, .Trivia: Trivia.str()});
116 }
117 }
118
119private:
120 const SourceManager &SM;
121 std::vector<clangd::PragmaMark> &Out;
122};
123
124std::unique_ptr<PPCallbacks>
125collectPragmaMarksCallback(const SourceManager &SM,
126 std::vector<PragmaMark> &Out) {
127 return std::make_unique<CollectPragmaMarks>(args: SM, args&: Out);
128}
129
130void CollectMainFileMacros::MacroDefined(const Token &MacroName,
131 const MacroDirective *MD) {
132
133 if (!InMainFile)
134 return;
135 const auto *MI = MD->getMacroInfo();
136 add(MacroNameTok: MacroName, MI: MD->getMacroInfo(), IsDefinition: true);
137 if (MI)
138 for (const auto &Tok : MI->tokens()) {
139 auto *II = Tok.getIdentifierInfo();
140 // Could this token be a reference to a macro? (Not param to this macro).
141 if (!II || !II->hadMacroDefinition() ||
142 llvm::is_contained(Range: MI->params(), Element: II))
143 continue;
144 if (const MacroInfo *MI = PP.getMacroInfo(II))
145 add(MacroNameTok: Tok, MI);
146 }
147}
148
149} // namespace clangd
150} // namespace clang
151

source code of clang-tools-extra/clangd/CollectMacros.cpp