12054ed05SUtkarsh Saxena //===-- CollectMacrosTests.cpp ----------------------------------*- C++ -*-===//
22054ed05SUtkarsh Saxena //
32054ed05SUtkarsh Saxena // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42054ed05SUtkarsh Saxena // See https://llvm.org/LICENSE.txt for license information.
52054ed05SUtkarsh Saxena // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62054ed05SUtkarsh Saxena //
72054ed05SUtkarsh Saxena //===----------------------------------------------------------------------===//
84d006520SSam McCall #include "AST.h"
92054ed05SUtkarsh Saxena #include "Annotations.h"
102054ed05SUtkarsh Saxena #include "CollectMacros.h"
11002c4b7bSHaojian Wu #include "Matchers.h"
122054ed05SUtkarsh Saxena #include "SourceCode.h"
132054ed05SUtkarsh Saxena #include "TestTU.h"
142054ed05SUtkarsh Saxena #include "clang/Basic/SourceLocation.h"
152054ed05SUtkarsh Saxena #include "llvm/Support/ScopedPrinter.h"
162054ed05SUtkarsh Saxena #include "gmock/gmock.h"
172054ed05SUtkarsh Saxena #include "gtest/gtest.h"
18002c4b7bSHaojian Wu #include <vector>
192054ed05SUtkarsh Saxena
202054ed05SUtkarsh Saxena namespace clang {
212054ed05SUtkarsh Saxena namespace clangd {
222054ed05SUtkarsh Saxena namespace {
232054ed05SUtkarsh Saxena
242054ed05SUtkarsh Saxena using testing::UnorderedElementsAreArray;
252054ed05SUtkarsh Saxena
26*7298bcf7SHaojian Wu MATCHER_P(rangeIs, R, "") {
27*7298bcf7SHaojian Wu return arg.StartOffset == R.Begin && arg.EndOffset == R.End;
28*7298bcf7SHaojian Wu }
29002c4b7bSHaojian Wu MATCHER(isDef, "") { return arg.IsDefinition; }
30002c4b7bSHaojian Wu MATCHER(inConditionalDirective, "") { return arg.InConditionalDirective; }
31002c4b7bSHaojian Wu
TEST(CollectMainFileMacros,SelectedMacros)322054ed05SUtkarsh Saxena TEST(CollectMainFileMacros, SelectedMacros) {
332054ed05SUtkarsh Saxena // References of the same symbol must have the ranges with the same
342054ed05SUtkarsh Saxena // name(integer). If there are N different symbols then they must be named
352054ed05SUtkarsh Saxena // from 1 to N. Macros for which SymbolID cannot be computed must be named
36002c4b7bSHaojian Wu // "Unknown". The payload of the annotation describes the extra bit
37002c4b7bSHaojian Wu // information of the MacroOccurrence (e.g. $1(def) => IsDefinition).
382054ed05SUtkarsh Saxena const char *Tests[] = {
392054ed05SUtkarsh Saxena R"cpp(// Macros: Cursor on definition.
40002c4b7bSHaojian Wu #define $1(def)[[FOO]](x,y) (x + y)
412054ed05SUtkarsh Saxena int main() { int x = $1[[FOO]]($1[[FOO]](3, 4), $1[[FOO]](5, 6)); }
422054ed05SUtkarsh Saxena )cpp",
432054ed05SUtkarsh Saxena R"cpp(
44002c4b7bSHaojian Wu #define $1(def)[[M]](X) X;
45002c4b7bSHaojian Wu #define $2(def)[[abc]] 123
462054ed05SUtkarsh Saxena int s = $1[[M]]($2[[abc]]);
472054ed05SUtkarsh Saxena )cpp",
482054ed05SUtkarsh Saxena // FIXME: Locating macro in duplicate definitions doesn't work. Enable
492054ed05SUtkarsh Saxena // this once LocateMacro is fixed.
502054ed05SUtkarsh Saxena // R"cpp(// Multiple definitions.
512054ed05SUtkarsh Saxena // #define $1[[abc]] 1
522054ed05SUtkarsh Saxena // int func1() { int a = $1[[abc]];}
532054ed05SUtkarsh Saxena // #undef $1[[abc]]
542054ed05SUtkarsh Saxena
552054ed05SUtkarsh Saxena // #define $2[[abc]] 2
562054ed05SUtkarsh Saxena // int func2() { int a = $2[[abc]];}
572054ed05SUtkarsh Saxena // #undef $2[[abc]]
582054ed05SUtkarsh Saxena // )cpp",
592054ed05SUtkarsh Saxena R"cpp(
60002c4b7bSHaojian Wu #ifdef $Unknown(condit)[[UNDEFINED]]
613ddfea07SHaojian Wu #elifdef $Unknown(condit)[[UNDEFINED]]
623ddfea07SHaojian Wu #endif
633ddfea07SHaojian Wu
643ddfea07SHaojian Wu #ifdef $Unknown(condit)[[UNDEFINED]]
653ddfea07SHaojian Wu #elifndef $Unknown(condit)[[UNDEFINED]]
66002c4b7bSHaojian Wu #endif
67002c4b7bSHaojian Wu
68002c4b7bSHaojian Wu #ifndef $Unknown(condit)[[UNDEFINED]]
69002c4b7bSHaojian Wu #endif
70002c4b7bSHaojian Wu
71002c4b7bSHaojian Wu #if defined($Unknown(condit)[[UNDEFINED]])
722054ed05SUtkarsh Saxena #endif
732054ed05SUtkarsh Saxena )cpp",
742054ed05SUtkarsh Saxena R"cpp(
75002c4b7bSHaojian Wu #ifndef $Unknown(condit)[[abc]]
76002c4b7bSHaojian Wu #define $1(def)[[abc]]
77002c4b7bSHaojian Wu #ifdef $1(condit)[[abc]]
782054ed05SUtkarsh Saxena #endif
792054ed05SUtkarsh Saxena #endif
802054ed05SUtkarsh Saxena )cpp",
812054ed05SUtkarsh Saxena R"cpp(
822054ed05SUtkarsh Saxena // Macros from token concatenations not included.
83002c4b7bSHaojian Wu #define $1(def)[[CONCAT]](X) X##A()
84002c4b7bSHaojian Wu #define $2(def)[[PREPEND]](X) MACRO##X()
85002c4b7bSHaojian Wu #define $3(def)[[MACROA]]() 123
862054ed05SUtkarsh Saxena int B = $1[[CONCAT]](MACRO);
87d3260bf5SSam McCall int D = $2[[PREPEND]](A);
882054ed05SUtkarsh Saxena )cpp",
892054ed05SUtkarsh Saxena R"cpp(
90002c4b7bSHaojian Wu #define $1(def)[[MACRO_ARGS2]](X, Y) X Y
91002c4b7bSHaojian Wu #define $3(def)[[BAR]] 1
92002c4b7bSHaojian Wu #define $2(def)[[FOO]] $3[[BAR]]
932054ed05SUtkarsh Saxena int A = $2[[FOO]];
942054ed05SUtkarsh Saxena )cpp"};
95*7298bcf7SHaojian Wu auto ExpectedResults = [](const llvm::Annotations &T, StringRef Name) {
96002c4b7bSHaojian Wu std::vector<Matcher<MacroOccurrence>> ExpectedLocations;
97002c4b7bSHaojian Wu for (const auto &[R, Bits] : T.rangesWithPayload(Name)) {
98002c4b7bSHaojian Wu if (Bits == "def")
99002c4b7bSHaojian Wu ExpectedLocations.push_back(testing::AllOf(rangeIs(R), isDef()));
100002c4b7bSHaojian Wu else if (Bits == "condit")
101002c4b7bSHaojian Wu ExpectedLocations.push_back(
102002c4b7bSHaojian Wu testing::AllOf(rangeIs(R), inConditionalDirective()));
103002c4b7bSHaojian Wu else
104002c4b7bSHaojian Wu ExpectedLocations.push_back(testing::AllOf(rangeIs(R)));
105002c4b7bSHaojian Wu }
106002c4b7bSHaojian Wu return ExpectedLocations;
107002c4b7bSHaojian Wu };
108002c4b7bSHaojian Wu
1092054ed05SUtkarsh Saxena for (const char *Test : Tests) {
110*7298bcf7SHaojian Wu llvm::Annotations T(Test);
1113ddfea07SHaojian Wu auto Inputs = TestTU::withCode(T.code());
1123ddfea07SHaojian Wu Inputs.ExtraArgs.push_back("-std=c++2b");
1133ddfea07SHaojian Wu auto AST = Inputs.build();
1142054ed05SUtkarsh Saxena auto ActualMacroRefs = AST.getMacros();
1152054ed05SUtkarsh Saxena auto &SM = AST.getSourceManager();
1162054ed05SUtkarsh Saxena auto &PP = AST.getPreprocessor();
117002c4b7bSHaojian Wu for (const auto &[Name, Ranges] : T.all_ranges()) {
118002c4b7bSHaojian Wu if (Name == "Unknown") {
119002c4b7bSHaojian Wu EXPECT_THAT(ActualMacroRefs.UnknownMacros,
120002c4b7bSHaojian Wu UnorderedElementsAreArray(ExpectedResults(T, "Unknown")))
121002c4b7bSHaojian Wu << "Unknown macros doesn't match in " << Test;
122002c4b7bSHaojian Wu continue;
123002c4b7bSHaojian Wu }
1242054ed05SUtkarsh Saxena
125002c4b7bSHaojian Wu auto Loc = sourceLocationInMainFile(
126002c4b7bSHaojian Wu SM, offsetToPosition(T.code(), Ranges.front().Begin));
1272bb7774dSKadir Cetinkaya ASSERT_TRUE(bool(Loc));
1283ae2fc7aSKadir Cetinkaya const auto *Id = syntax::spelledIdentifierTouching(*Loc, AST.getTokens());
1293ae2fc7aSKadir Cetinkaya ASSERT_TRUE(Id);
1303ae2fc7aSKadir Cetinkaya auto Macro = locateMacroAt(*Id, PP);
1312054ed05SUtkarsh Saxena assert(Macro);
1322054ed05SUtkarsh Saxena auto SID = getSymbolID(Macro->Name, Macro->Info, SM);
1332054ed05SUtkarsh Saxena
134002c4b7bSHaojian Wu EXPECT_THAT(ActualMacroRefs.MacroRefs[SID],
135002c4b7bSHaojian Wu UnorderedElementsAreArray(ExpectedResults(T, Name)))
136002c4b7bSHaojian Wu << "Annotation=" << Name << ", MacroName=" << Macro->Name
1372054ed05SUtkarsh Saxena << ", Test = " << Test;
1382054ed05SUtkarsh Saxena }
1392054ed05SUtkarsh Saxena }
1402054ed05SUtkarsh Saxena }
1412054ed05SUtkarsh Saxena } // namespace
1422054ed05SUtkarsh Saxena } // namespace clangd
1432054ed05SUtkarsh Saxena } // namespace clang
144