116 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- 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
 |