//===-- CollectMacrosTests.cpp ----------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Annotations.h" #include "CollectMacros.h" #include "Matchers.h" #include "SourceCode.h" #include "TestTU.h" #include "index/SymbolID.h" #include "clang/Basic/SourceLocation.h" #include "llvm/Support/ScopedPrinter.h" #include "gmock/gmock.h" #include "gtest/gtest.h" namespace clang { namespace clangd { namespace { using testing::UnorderedElementsAreArray; TEST(CollectMainFileMacros, SelectedMacros) { // References of the same symbol must have the ranges with the same // name(integer). If there are N different symbols then they must be named // from 1 to N. Macros for which SymbolID cannot be computed must be named // "Unknown". const char *Tests[] = { R"cpp(// Macros: Cursor on definition. #define $1[[FOO]](x,y) (x + y) int main() { int x = $1[[FOO]]($1[[FOO]](3, 4), $1[[FOO]](5, 6)); } )cpp", R"cpp( #define $1[[M]](X) X; #define $2[[abc]] 123 int s = $1[[M]]($2[[abc]]); )cpp", // FIXME: Locating macro in duplicate definitions doesn't work. Enable // this once LocateMacro is fixed. // R"cpp(// Multiple definitions. // #define $1[[abc]] 1 // int func1() { int a = $1[[abc]];} // #undef $1[[abc]] // #define $2[[abc]] 2 // int func2() { int a = $2[[abc]];} // #undef $2[[abc]] // )cpp", R"cpp( #ifdef $Unknown[[UNDEFINED]] #endif )cpp", R"cpp( #ifndef $Unknown[[abc]] #define $1[[abc]] #ifdef $1[[abc]] #endif #endif )cpp", R"cpp( // Macros from token concatenations not included. #define $1[[CONCAT]](X) X##A() #define $2[[PREPEND]](X) MACRO##X() #define $3[[MACROA]]() 123 int B = $1[[CONCAT]](MACRO); int D = $2[[PREPEND]](A); )cpp", R"cpp( // FIXME: Macro names in a definition are not detected. #define $1[[MACRO_ARGS2]](X, Y) X Y #define $2[[FOO]] BAR #define $3[[BAR]] 1 int A = $2[[FOO]]; )cpp"}; for (const char *Test : Tests) { Annotations T(Test); auto AST = TestTU::withCode(T.code()).build(); auto ActualMacroRefs = AST.getMacros(); auto &SM = AST.getSourceManager(); auto &PP = AST.getPreprocessor(); // Known macros. for (int I = 1;; I++) { const auto ExpectedRefs = T.ranges(llvm::to_string(I)); if (ExpectedRefs.empty()) break; auto Loc = sourceLocationInMainFile(SM, ExpectedRefs.begin()->start); ASSERT_TRUE(bool(Loc)); const auto *Id = syntax::spelledIdentifierTouching(*Loc, AST.getTokens()); ASSERT_TRUE(Id); auto Macro = locateMacroAt(*Id, PP); assert(Macro); auto SID = getSymbolID(Macro->Name, Macro->Info, SM); EXPECT_THAT(ExpectedRefs, UnorderedElementsAreArray(ActualMacroRefs.MacroRefs[SID])) << "Annotation=" << I << ", MacroName=" << Macro->Name << ", Test = " << Test; } // Unknown macros. EXPECT_THAT(AST.getMacros().UnknownMacros, UnorderedElementsAreArray(T.ranges("Unknown"))) << "Unknown macros doesn't match in " << Test; } } } // namespace } // namespace clangd } // namespace clang