1 //===-- CollectMacrosTests.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 "Annotations.h"
10 #include "CollectMacros.h"
12 #include "SourceCode.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "llvm/Support/ScopedPrinter.h"
16 #include "gmock/gmock.h"
17 #include "gtest/gtest.h"
24 using testing::UnorderedElementsAreArray
;
26 MATCHER_P(rangeIs
, R
, "") {
27 return arg
.StartOffset
== R
.Begin
&& arg
.EndOffset
== R
.End
;
29 MATCHER(isDef
, "") { return arg
.IsDefinition
; }
30 MATCHER(inConditionalDirective
, "") { return arg
.InConditionalDirective
; }
32 TEST(CollectMainFileMacros
, SelectedMacros
) {
33 // References of the same symbol must have the ranges with the same
34 // name(integer). If there are N different symbols then they must be named
35 // from 1 to N. Macros for which SymbolID cannot be computed must be named
36 // "Unknown". The payload of the annotation describes the extra bit
37 // information of the MacroOccurrence (e.g. $1(def) => IsDefinition).
38 const char *Tests
[] = {
39 R
"cpp(// Macros: Cursor on definition.
40 #define $1(def)[[FOO]](x,y) (x + y)
41 int main() { int x = $1[[FOO]]($1[[FOO]](3, 4), $1[[FOO]](5, 6)); }
44 #define $1(def)[[M]](X) X;
45 #define $2(def)[[abc]] 123
46 int s = $1[[M]]($2[[abc]]);
48 // FIXME: Locating macro in duplicate definitions doesn't work. Enable
49 // this once LocateMacro is fixed.
50 // R"cpp(// Multiple definitions.
51 // #define $1[[abc]] 1
52 // int func1() { int a = $1[[abc]];}
55 // #define $2[[abc]] 2
56 // int func2() { int a = $2[[abc]];}
60 #ifdef $Unknown(condit)[[UNDEFINED]]
61 #elifdef $Unknown(condit)[[UNDEFINED]]
64 #ifdef $Unknown(condit)[[UNDEFINED]]
65 #elifndef $Unknown(condit)[[UNDEFINED]]
68 #ifndef $Unknown(condit)[[UNDEFINED]]
71 #if defined($Unknown(condit)[[UNDEFINED]])
75 #ifndef $Unknown(condit)[[abc]]
76 #define $1(def)[[abc]]
77 #ifdef $1(condit)[[abc]]
82 // Macros from token concatenations not included.
83 #define $1(def)[[CONCAT]](X) X##A()
84 #define $2(def)[[PREPEND]](X) MACRO##X()
85 #define $3(def)[[MACROA]]() 123
86 int B = $1[[CONCAT]](MACRO);
87 int D = $2[[PREPEND]](A);
90 #define $1(def)[[MACRO_ARGS2]](X, Y) X Y
91 #define $3(def)[[BAR]] 1
92 #define $2(def)[[FOO]] $3[[BAR]]
95 auto ExpectedResults
= [](const llvm::Annotations
&T
, StringRef Name
) {
96 std::vector
<Matcher
<MacroOccurrence
>> ExpectedLocations
;
97 for (const auto &[R
, Bits
] : T
.rangesWithPayload(Name
)) {
99 ExpectedLocations
.push_back(testing::AllOf(rangeIs(R
), isDef()));
100 else if (Bits
== "condit")
101 ExpectedLocations
.push_back(
102 testing::AllOf(rangeIs(R
), inConditionalDirective()));
104 ExpectedLocations
.push_back(testing::AllOf(rangeIs(R
)));
106 return ExpectedLocations
;
109 for (const char *Test
: Tests
) {
110 llvm::Annotations
T(Test
);
111 auto Inputs
= TestTU::withCode(T
.code());
112 Inputs
.ExtraArgs
.push_back("-std=c++2b");
113 auto AST
= Inputs
.build();
114 auto ActualMacroRefs
= AST
.getMacros();
115 auto &SM
= AST
.getSourceManager();
116 auto &PP
= AST
.getPreprocessor();
117 for (const auto &[Name
, Ranges
] : T
.all_ranges()) {
118 if (Name
== "Unknown") {
119 EXPECT_THAT(ActualMacroRefs
.UnknownMacros
,
120 UnorderedElementsAreArray(ExpectedResults(T
, "Unknown")))
121 << "Unknown macros doesn't match in " << Test
;
125 auto Loc
= sourceLocationInMainFile(
126 SM
, offsetToPosition(T
.code(), Ranges
.front().Begin
));
127 ASSERT_TRUE(bool(Loc
));
128 const auto *Id
= syntax::spelledIdentifierTouching(*Loc
, AST
.getTokens());
130 auto Macro
= locateMacroAt(*Id
, PP
);
132 auto SID
= getSymbolID(Macro
->Name
, Macro
->Info
, SM
);
134 EXPECT_THAT(ActualMacroRefs
.MacroRefs
[SID
],
135 UnorderedElementsAreArray(ExpectedResults(T
, Name
)))
136 << "Annotation=" << Name
<< ", MacroName=" << Macro
->Name
137 << ", Test = " << Test
;
142 } // namespace clangd