144 lines · cpp
1//===-- CollectMacrosTests.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-exception6//7//===----------------------------------------------------------------------===//8#include "AST.h"9#include "Annotations.h"10#include "CollectMacros.h"11#include "Matchers.h"12#include "SourceCode.h"13#include "TestTU.h"14#include "clang/Basic/SourceLocation.h"15#include "llvm/Support/ScopedPrinter.h"16#include "gmock/gmock.h"17#include "gtest/gtest.h"18#include <vector>19 20namespace clang {21namespace clangd {22namespace {23 24using testing::UnorderedElementsAreArray;25 26MATCHER_P(rangeIs, R, "") {27 return arg.StartOffset == R.Begin && arg.EndOffset == R.End;28}29MATCHER(isDef, "") { return arg.IsDefinition; }30MATCHER(inConditionalDirective, "") { return arg.InConditionalDirective; }31 32TEST(CollectMainFileMacros, SelectedMacros) {33 // References of the same symbol must have the ranges with the same34 // name(integer). If there are N different symbols then they must be named35 // from 1 to N. Macros for which SymbolID cannot be computed must be named36 // "Unknown". The payload of the annotation describes the extra bit37 // 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)); }42 )cpp",43 R"cpp(44 #define $1(def)[[M]](X) X;45 #define $2(def)[[abc]] 12346 int s = $1[[M]]($2[[abc]]);47 )cpp",48 // FIXME: Locating macro in duplicate definitions doesn't work. Enable49 // this once LocateMacro is fixed.50 // R"cpp(// Multiple definitions.51 // #define $1[[abc]] 152 // int func1() { int a = $1[[abc]];}53 // #undef $1[[abc]]54 55 // #define $2[[abc]] 256 // int func2() { int a = $2[[abc]];}57 // #undef $2[[abc]]58 // )cpp",59 R"cpp(60 #ifdef $Unknown(condit)[[UNDEFINED]]61 #elifdef $Unknown(condit)[[UNDEFINED]]62 #endif63 64 #ifdef $Unknown(condit)[[UNDEFINED]]65 #elifndef $Unknown(condit)[[UNDEFINED]]66 #endif67 68 #ifndef $Unknown(condit)[[UNDEFINED]]69 #endif70 71 #if defined($Unknown(condit)[[UNDEFINED]])72 #endif73 )cpp",74 R"cpp(75 #ifndef $Unknown(condit)[[abc]]76 #define $1(def)[[abc]]77 #ifdef $1(condit)[[abc]]78 #endif79 #endif80 )cpp",81 R"cpp(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]]() 12386 int B = $1[[CONCAT]](MACRO);87 int D = $2[[PREPEND]](A);88 )cpp",89 R"cpp(90 #define $1(def)[[MACRO_ARGS2]](X, Y) X Y91 #define $3(def)[[BAR]] 192 #define $2(def)[[FOO]] $3[[BAR]]93 int A = $2[[FOO]];94 )cpp"};95 auto ExpectedResults = [](const llvm::Annotations &T, StringRef Name) {96 std::vector<Matcher<MacroOccurrence>> ExpectedLocations;97 for (const auto &[R, Bits] : T.rangesWithPayload(Name)) {98 if (Bits == "def")99 ExpectedLocations.push_back(testing::AllOf(rangeIs(R), isDef()));100 else if (Bits == "condit")101 ExpectedLocations.push_back(102 testing::AllOf(rangeIs(R), inConditionalDirective()));103 else104 ExpectedLocations.push_back(testing::AllOf(rangeIs(R)));105 }106 return ExpectedLocations;107 };108 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;122 continue;123 }124 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());129 ASSERT_TRUE(Id);130 auto Macro = locateMacroAt(*Id, PP);131 assert(Macro);132 auto SID = getSymbolID(Macro->Name, Macro->Info, SM);133 134 EXPECT_THAT(ActualMacroRefs.MacroRefs[SID],135 UnorderedElementsAreArray(ExpectedResults(T, Name)))136 << "Annotation=" << Name << ", MacroName=" << Macro->Name137 << ", Test = " << Test;138 }139 }140}141} // namespace142} // namespace clangd143} // namespace clang144