| //===-- 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); |
| |
| std::vector<Range> Ranges; |
| for (const auto &Ref : ActualMacroRefs.MacroRefs[SID]) |
| Ranges.push_back(Ref.Rng); |
| EXPECT_THAT(ExpectedRefs, UnorderedElementsAreArray(Ranges)) |
| << "Annotation=" << I << ", MacroName=" << Macro->Name |
| << ", Test = " << Test; |
| } |
| // Unknown macros. |
| std::vector<Range> Ranges; |
| for (const auto &Ref : AST.getMacros().UnknownMacros) |
| Ranges.push_back(Ref.Rng); |
| EXPECT_THAT(Ranges, UnorderedElementsAreArray(T.ranges("Unknown"))) |
| << "Unknown macros doesn't match in " << Test; |
| } |
| } |
| } // namespace |
| } // namespace clangd |
| } // namespace clang |