352 lines
8.5 KiB
C++
352 lines
8.5 KiB
C++
#include "Support/Logger.h"
|
|
#include "Test/Tester.h"
|
|
#include "Index/USR.h"
|
|
#include "clang/AST/DeclBase.h"
|
|
#include "clang/AST/RecursiveASTVisitor.h"
|
|
|
|
namespace clice::testing {
|
|
|
|
namespace {
|
|
|
|
struct USRInfo {
|
|
llvm::SmallString<128> USR;
|
|
uint32_t offset;
|
|
clang::Decl* decl;
|
|
};
|
|
|
|
struct GetUSRVisitor : public clang::RecursiveASTVisitor<GetUSRVisitor> {
|
|
bool VisitDecl(clang::Decl* decl) {
|
|
auto offset = [&]() -> std::optional<std::uint32_t> {
|
|
auto loc = decl->getLocation();
|
|
if(!loc.isValid())
|
|
return std::nullopt;
|
|
|
|
auto& SM = decl->getASTContext().getSourceManager();
|
|
auto [_, offset] = SM.getDecomposedLoc(loc);
|
|
return offset;
|
|
}();
|
|
|
|
auto USR = [&]() -> std::optional<llvm::SmallString<128>> {
|
|
llvm::SmallString<128> buffer;
|
|
if(!clice::index::generateUSRForDecl(decl, buffer)) {
|
|
return buffer;
|
|
}
|
|
return std::nullopt;
|
|
}();
|
|
|
|
if(offset.has_value() && USR.has_value()) {
|
|
USRs[*offset] = USRInfo{*USR, *offset, decl};
|
|
// log::info("USR: {} at {}:{}", USR->str(), pos->line, pos->character);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::map<std::uint32_t, USRInfo> USRs;
|
|
};
|
|
|
|
struct USRTester : public Tester {
|
|
USRTester(llvm::StringRef file, llvm::StringRef content) {
|
|
add_main(file, content);
|
|
}
|
|
|
|
void run(llvm::StringRef standard = "-std=c++20") {
|
|
Tester::compile(standard);
|
|
|
|
GetUSRVisitor visitor;
|
|
visitor.TraverseDecl(unit->tu());
|
|
USRs = std::move(visitor.USRs);
|
|
}
|
|
|
|
llvm::StringRef lookup(llvm::StringRef key) {
|
|
auto iter = USRs.find((*this)["main.cpp", key]);
|
|
if(iter == USRs.end()) {
|
|
log::fatal("USR not found for key: {}", key);
|
|
}
|
|
return iter->second.USR;
|
|
}
|
|
|
|
std::map<uint32_t, USRInfo> USRs;
|
|
};
|
|
|
|
suite<"USR"> suite = [] {
|
|
/// fixme: headers not found
|
|
///
|
|
/// TEST(Index, USRTemplateClassRequireClause) {
|
|
/// llvm::StringRef content = R"cpp(
|
|
/// #include <concepts>
|
|
/// template <typename T> struct A;
|
|
///
|
|
/// template <typename T> requires (__is_same(T, float))
|
|
/// struct $(1)A<T>;
|
|
///
|
|
/// template <typename T> requires (__is_same(T, int))
|
|
/// struct $(2)A<T>;
|
|
///
|
|
/// template <typename T> requires (std::same_as<T, double>)
|
|
/// struct $(3)A<T> {};
|
|
/// )cpp";
|
|
///
|
|
/// USRTester tester("main.cpp", content);
|
|
/// tester.run();
|
|
///
|
|
/// auto usr1 = tester.lookupUSR("1");
|
|
/// auto usr2 = tester.lookupUSR("2");
|
|
/// auto usr3 = tester.lookupUSR("3");
|
|
///
|
|
/// EXPECT_NE(usr1, usr2);
|
|
/// EXPECT_NE(usr1, usr3);
|
|
/// EXPECT_NE(usr2, usr3);
|
|
/// }
|
|
|
|
test("USRTemplateClassRequireClauseComplex") = [&] {
|
|
llvm::StringRef content = R"cpp(
|
|
template <typename T> struct A;
|
|
|
|
template <typename T> requires (__is_same(T, float))
|
|
struct $(1)A<T>;
|
|
|
|
using FLOAT = float;
|
|
template <typename T> requires (__is_same(T, FLOAT))
|
|
struct $(2)A<T>;
|
|
|
|
template <typename T> requires (__is_same(T, A<int>))
|
|
struct $(11)A<T>;
|
|
template <typename T> requires (__is_same(T, A<float>))
|
|
struct $(12)A<T>;
|
|
template <typename T> requires (__is_same(T, A<FLOAT>))
|
|
struct $(13)A<T>;
|
|
)cpp";
|
|
|
|
USRTester tester("main.cpp", content);
|
|
tester.run();
|
|
|
|
auto usr1 = tester.lookup("1");
|
|
auto usr2 = tester.lookup("2");
|
|
|
|
expect(that % usr1 == usr2);
|
|
|
|
auto usr11 = tester.lookup("11");
|
|
auto usr12 = tester.lookup("12");
|
|
auto usr13 = tester.lookup("13");
|
|
|
|
expect(that % usr11 != usr12);
|
|
expect(that % usr12 == usr13);
|
|
};
|
|
|
|
test("USRTemplateClassConceptConstraint") = [&] {
|
|
llvm::StringRef content = R"cpp(
|
|
template<typename T>
|
|
concept C = requires(T t) { true; };
|
|
template<typename T, typename U>
|
|
struct A;
|
|
|
|
template<typename T, C U>
|
|
struct $(1)A<T, U>;
|
|
|
|
template<C T, typename U>
|
|
struct $(2)A<T, U>;
|
|
)cpp";
|
|
|
|
USRTester tester("main.cpp", content);
|
|
tester.run();
|
|
|
|
auto usr1 = tester.lookup("1");
|
|
auto usr2 = tester.lookup("2");
|
|
|
|
expect(that % usr1 != usr2);
|
|
};
|
|
|
|
test("USRTemplateClassConceptConstraintPack") = [&] {
|
|
llvm::StringRef content1 = R"cpp(
|
|
template<typename... Ts>
|
|
struct $(1)A;
|
|
)cpp";
|
|
|
|
llvm::StringRef content2 = R"cpp(
|
|
template<typename T>
|
|
concept C = requires(T t) { true; };
|
|
template<C... Ts>
|
|
struct $(2)A;
|
|
)cpp";
|
|
|
|
USRTester tester1("main.cpp", content1);
|
|
tester1.run();
|
|
USRTester tester2("main.cpp", content2);
|
|
tester2.run();
|
|
|
|
auto usr1 = tester1.lookup("1");
|
|
auto usr2 = tester2.lookup("2");
|
|
|
|
expect(that % usr1 != usr2);
|
|
};
|
|
|
|
test("USRTemplateArgumentExpr") = [&] {
|
|
llvm::StringRef content = R"cpp(
|
|
template <typename T, int N> struct C;
|
|
|
|
template <int N> struct $(1)C<float, N>;
|
|
template <int M> struct $(2)C<float, M>;
|
|
template <char c> struct $(3)C<float, c>;
|
|
)cpp";
|
|
|
|
USRTester tester("main.cpp", content);
|
|
tester.run();
|
|
|
|
auto usr1 = tester.lookup("1");
|
|
auto usr2 = tester.lookup("2");
|
|
auto usr3 = tester.lookup("3");
|
|
|
|
expect(that % usr1 == usr2);
|
|
expect(that % usr1 != usr3);
|
|
};
|
|
|
|
test("USRTemplateFunctionRequireClause") = [&] {
|
|
llvm::StringRef content = R"cpp(
|
|
template<typename T>
|
|
void $(1)func(T t) requires (sizeof(T) == 4) {};
|
|
|
|
template<typename T>
|
|
void $(2)func(T t) requires (sizeof(T) == 8) {};
|
|
)cpp";
|
|
|
|
USRTester tester("main.cpp", content);
|
|
tester.run();
|
|
|
|
auto usr1 = tester.lookup("1");
|
|
auto usr2 = tester.lookup("2");
|
|
|
|
expect(that % usr1 != usr2);
|
|
};
|
|
|
|
test("USRTemplateVarConceptConstraint") = [&] {
|
|
llvm::StringRef content1 = R"cpp(
|
|
template <typename T>
|
|
constexpr T $(1)pi = 3.14;
|
|
)cpp";
|
|
|
|
llvm::StringRef content2 = R"cpp(
|
|
template <typename T>
|
|
concept integral = requires (T t) { t + 1; };
|
|
template <integral T>
|
|
constexpr T $(2)pi = 3;
|
|
)cpp";
|
|
|
|
USRTester tester1("main.cpp", content1);
|
|
tester1.run();
|
|
USRTester tester2("main.cpp", content2);
|
|
tester2.run();
|
|
|
|
auto usr1 = tester1.lookup("1");
|
|
auto usr2 = tester2.lookup("2");
|
|
|
|
expect(that % usr1 != usr2);
|
|
};
|
|
|
|
test("USRCTAD") = [&] {
|
|
llvm::StringRef content = R"cpp(
|
|
template<typename T>
|
|
struct array {};
|
|
template<typename U, array arr>
|
|
struct $(1)L;
|
|
)cpp";
|
|
|
|
USRTester tester("main.cpp", content);
|
|
tester.run();
|
|
|
|
auto usr1 = tester.lookup("1");
|
|
|
|
expect(that % usr1.contains("array"));
|
|
};
|
|
|
|
test("USRTemplateParamObject") = [&] {
|
|
llvm::StringRef content = R"cpp(
|
|
template<typename T> struct array {
|
|
constexpr array(T x_) : x(x_) {}
|
|
int x;
|
|
};
|
|
template<array U> struct L;
|
|
template<> struct $(1)L<{1}>;
|
|
template<> struct $(2)L<{2}>;
|
|
)cpp";
|
|
|
|
USRTester tester("main.cpp", content);
|
|
tester.run();
|
|
|
|
auto usr1 = tester.lookup("1");
|
|
auto usr2 = tester.lookup("2");
|
|
|
|
expect(that % usr1 != usr2);
|
|
};
|
|
|
|
test("USRNTTPConstraint") = [&] {
|
|
llvm::StringRef content1 = R"cpp(
|
|
template<auto N> struct $(1)M;
|
|
)cpp";
|
|
|
|
llvm::StringRef content2 = R"cpp(
|
|
template<typename T> concept C = requires {requires true;};
|
|
template<C auto N> struct $(2)M;
|
|
)cpp";
|
|
|
|
USRTester tester1("main.cpp", content1);
|
|
tester1.run();
|
|
USRTester tester2("main.cpp", content2);
|
|
tester2.run();
|
|
|
|
auto usr1 = tester1.lookup("1");
|
|
auto usr2 = tester2.lookup("2");
|
|
|
|
expect(that % usr1 != usr2);
|
|
};
|
|
|
|
test("USRDependentTemplateName") = [&] {
|
|
llvm::StringRef content = R"cpp(
|
|
template <typename MetaFun>
|
|
struct X {
|
|
template <template <typename, typename> class Tmpl>
|
|
class Y;
|
|
|
|
template <>
|
|
class $(1)Y<MetaFun::template apply>;
|
|
|
|
template <>
|
|
class $(2)Y<MetaFun::template apply2>;
|
|
};
|
|
)cpp";
|
|
|
|
USRTester tester("main.cpp", content);
|
|
tester.run();
|
|
|
|
auto usr1 = tester.lookup("1");
|
|
auto usr2 = tester.lookup("2");
|
|
|
|
expect(that % usr1 != usr2);
|
|
};
|
|
|
|
test("USRDeducingThis") = [&] {
|
|
llvm::StringRef content = R"cpp(
|
|
class A {
|
|
public:
|
|
template <typename Self>
|
|
void $(1)foo(this Self&& s);
|
|
|
|
template <typename Self>
|
|
void $(2)foo(Self&& s);
|
|
};
|
|
)cpp";
|
|
|
|
USRTester tester("main.cpp", content);
|
|
tester.run("-std=c++23");
|
|
|
|
auto usr1 = tester.lookup("1");
|
|
auto usr2 = tester.lookup("2");
|
|
|
|
expect(that % usr1 != usr2);
|
|
};
|
|
};
|
|
|
|
} // namespace
|
|
|
|
} // namespace clice::testing
|