1 //===--- CollectMacros.cpp ---------------------------------------*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "CollectMacros.h"
12 #include "SourceCode.h"
13 #include "clang/Basic/SourceLocation.h"
14 #include "clang/Tooling/Syntax/Tokens.h"
15 #include "llvm/ADT/STLExtras.h"
21 Range
MacroOccurrence::toRange(const SourceManager
&SM
) const {
22 auto MainFile
= SM
.getMainFileID();
23 return halfOpenToRange(
24 SM
, syntax::FileRange(MainFile
, StartOffset
, EndOffset
).toCharRange(SM
));
27 void CollectMainFileMacros::add(const Token
&MacroNameTok
, const MacroInfo
*MI
,
28 bool IsDefinition
, bool InIfCondition
) {
31 auto Loc
= MacroNameTok
.getLocation();
32 if (Loc
.isInvalid() || Loc
.isMacroID())
35 assert(isInsideMainFile(Loc
, SM
));
36 auto Name
= MacroNameTok
.getIdentifierInfo()->getName();
37 Out
.Names
.insert(Name
);
38 size_t Start
= SM
.getFileOffset(Loc
);
39 size_t End
= SM
.getFileOffset(MacroNameTok
.getEndLoc());
40 if (auto SID
= getSymbolID(Name
, MI
, SM
))
41 Out
.MacroRefs
[SID
].push_back({Start
, End
, IsDefinition
, InIfCondition
});
43 Out
.UnknownMacros
.push_back({Start
, End
, IsDefinition
, InIfCondition
});
46 void CollectMainFileMacros::FileChanged(SourceLocation Loc
, FileChangeReason
,
47 SrcMgr::CharacteristicKind
, FileID
) {
48 InMainFile
= isInsideMainFile(Loc
, SM
);
51 void CollectMainFileMacros::MacroExpands(const Token
&MacroName
,
52 const MacroDefinition
&MD
,
54 const MacroArgs
*Args
) {
55 add(MacroName
, MD
.getMacroInfo());
58 void CollectMainFileMacros::MacroUndefined(const clang::Token
&MacroName
,
59 const clang::MacroDefinition
&MD
,
60 const clang::MacroDirective
*Undef
) {
61 add(MacroName
, MD
.getMacroInfo());
64 void CollectMainFileMacros::Ifdef(SourceLocation Loc
, const Token
&MacroName
,
65 const MacroDefinition
&MD
) {
66 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
67 /*InConditionalDirective=*/true);
70 void CollectMainFileMacros::Ifndef(SourceLocation Loc
, const Token
&MacroName
,
71 const MacroDefinition
&MD
) {
72 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
73 /*InConditionalDirective=*/true);
76 void CollectMainFileMacros::Elifdef(SourceLocation Loc
, const Token
&MacroName
,
77 const MacroDefinition
&MD
) {
78 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
79 /*InConditionalDirective=*/true);
82 void CollectMainFileMacros::Elifndef(SourceLocation Loc
, const Token
&MacroName
,
83 const MacroDefinition
&MD
) {
84 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
85 /*InConditionalDirective=*/true);
88 void CollectMainFileMacros::Defined(const Token
&MacroName
,
89 const MacroDefinition
&MD
,
91 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
92 /*InConditionalDirective=*/true);
95 void CollectMainFileMacros::SourceRangeSkipped(SourceRange R
,
96 SourceLocation EndifLoc
) {
99 Position Begin
= sourceLocToPosition(SM
, R
.getBegin());
100 Position End
= sourceLocToPosition(SM
, R
.getEnd());
101 Out
.SkippedRanges
.push_back(Range
{Begin
, End
});
104 class CollectPragmaMarks
: public PPCallbacks
{
106 explicit CollectPragmaMarks(const SourceManager
&SM
,
107 std::vector
<clangd::PragmaMark
> &Out
)
108 : SM(SM
), Out(Out
) {}
110 void PragmaMark(SourceLocation Loc
, StringRef Trivia
) override
{
111 if (isInsideMainFile(Loc
, SM
)) {
112 // FIXME: This range should just cover `XX` in `#pragma mark XX` and
113 // `- XX` in `#pragma mark - XX`.
114 Position Start
= sourceLocToPosition(SM
, Loc
);
115 Position End
= {Start
.line
+ 1, 0};
116 Out
.emplace_back(clangd::PragmaMark
{{Start
, End
}, Trivia
.str()});
121 const SourceManager
&SM
;
122 std::vector
<clangd::PragmaMark
> &Out
;
125 std::unique_ptr
<PPCallbacks
>
126 collectPragmaMarksCallback(const SourceManager
&SM
,
127 std::vector
<PragmaMark
> &Out
) {
128 return std::make_unique
<CollectPragmaMarks
>(SM
, Out
);
131 void CollectMainFileMacros::MacroDefined(const Token
&MacroName
,
132 const MacroDirective
*MD
) {
136 const auto *MI
= MD
->getMacroInfo();
137 add(MacroName
, MD
->getMacroInfo(), true);
139 for (const auto &Tok
: MI
->tokens()) {
140 auto *II
= Tok
.getIdentifierInfo();
141 // Could this token be a reference to a macro? (Not param to this macro).
142 if (!II
|| !II
->hadMacroDefinition() ||
143 llvm::is_contained(MI
->params(), II
))
145 if (const MacroInfo
*MI
= PP
.getMacroInfo(II
))
150 } // namespace clangd