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 auto Name
= MacroNameTok
.getIdentifierInfo()->getName();
36 Out
.Names
.insert(Name
);
37 size_t Start
= SM
.getFileOffset(Loc
);
38 size_t End
= SM
.getFileOffset(MacroNameTok
.getEndLoc());
39 if (auto SID
= getSymbolID(Name
, MI
, SM
))
40 Out
.MacroRefs
[SID
].push_back({Start
, End
, IsDefinition
, InIfCondition
});
42 Out
.UnknownMacros
.push_back({Start
, End
, IsDefinition
, InIfCondition
});
45 void CollectMainFileMacros::FileChanged(SourceLocation Loc
, FileChangeReason
,
46 SrcMgr::CharacteristicKind
, FileID
) {
47 InMainFile
= isInsideMainFile(Loc
, SM
);
50 void CollectMainFileMacros::MacroExpands(const Token
&MacroName
,
51 const MacroDefinition
&MD
,
53 const MacroArgs
*Args
) {
54 add(MacroName
, MD
.getMacroInfo());
57 void CollectMainFileMacros::MacroUndefined(const clang::Token
&MacroName
,
58 const clang::MacroDefinition
&MD
,
59 const clang::MacroDirective
*Undef
) {
60 add(MacroName
, MD
.getMacroInfo());
63 void CollectMainFileMacros::Ifdef(SourceLocation Loc
, const Token
&MacroName
,
64 const MacroDefinition
&MD
) {
65 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
66 /*InConditionalDirective=*/true);
69 void CollectMainFileMacros::Ifndef(SourceLocation Loc
, const Token
&MacroName
,
70 const MacroDefinition
&MD
) {
71 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
72 /*InConditionalDirective=*/true);
75 void CollectMainFileMacros::Elifdef(SourceLocation Loc
, const Token
&MacroName
,
76 const MacroDefinition
&MD
) {
77 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
78 /*InConditionalDirective=*/true);
81 void CollectMainFileMacros::Elifndef(SourceLocation Loc
, const Token
&MacroName
,
82 const MacroDefinition
&MD
) {
83 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
84 /*InConditionalDirective=*/true);
87 void CollectMainFileMacros::Defined(const Token
&MacroName
,
88 const MacroDefinition
&MD
,
90 add(MacroName
, MD
.getMacroInfo(), /*IsDefinition=*/false,
91 /*InConditionalDirective=*/true);
94 void CollectMainFileMacros::SourceRangeSkipped(SourceRange R
,
95 SourceLocation EndifLoc
) {
98 Position Begin
= sourceLocToPosition(SM
, R
.getBegin());
99 Position End
= sourceLocToPosition(SM
, R
.getEnd());
100 Out
.SkippedRanges
.push_back(Range
{Begin
, End
});
103 class CollectPragmaMarks
: public PPCallbacks
{
105 explicit CollectPragmaMarks(const SourceManager
&SM
,
106 std::vector
<clangd::PragmaMark
> &Out
)
107 : SM(SM
), Out(Out
) {}
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
= {Start
.line
+ 1, 0};
115 Out
.emplace_back(clangd::PragmaMark
{{Start
, End
}, Trivia
.str()});
120 const SourceManager
&SM
;
121 std::vector
<clangd::PragmaMark
> &Out
;
124 std::unique_ptr
<PPCallbacks
>
125 collectPragmaMarksCallback(const SourceManager
&SM
,
126 std::vector
<PragmaMark
> &Out
) {
127 return std::make_unique
<CollectPragmaMarks
>(SM
, Out
);
130 void CollectMainFileMacros::MacroDefined(const Token
&MacroName
,
131 const MacroDirective
*MD
) {
135 const auto *MI
= MD
->getMacroInfo();
136 add(MacroName
, MD
->getMacroInfo(), true);
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(MI
->params(), II
))
144 if (const MacroInfo
*MI
= PP
.getMacroInfo(II
))
149 } // namespace clangd