2019-11-07 19:14:38 +08:00
|
|
|
//===-- 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 = getBeginningOfIdentifier(ExpectedRefs.begin()->start, SM,
|
2019-12-05 07:09:35 +08:00
|
|
|
AST.getLangOpts());
|
2019-11-07 19:14:38 +08:00
|
|
|
auto Macro = locateMacroAt(Loc, 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;
|
|
|
|
}
|
|
|
|
// Unkown macros.
|
|
|
|
EXPECT_THAT(AST.getMacros().UnknownMacros,
|
|
|
|
UnorderedElementsAreArray(T.ranges("Unknown")))
|
|
|
|
<< "Unknown macros doesn't match in " << Test;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|