forked from OSchip/llvm-project
212 lines
6.4 KiB
C++
212 lines
6.4 KiB
C++
//===-- ASTTests.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 "AST.h"
|
|
|
|
#include "Annotations.h"
|
|
#include "ParsedAST.h"
|
|
#include "TestTU.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/AST/DeclBase.h"
|
|
#include "clang/Basic/SourceManager.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
#include <cstddef>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace clang {
|
|
namespace clangd {
|
|
namespace {
|
|
|
|
TEST(GetDeducedType, KwAutoExpansion) {
|
|
struct Test {
|
|
StringRef AnnotatedCode;
|
|
const char *DeducedType;
|
|
} Tests[] = {
|
|
{"^auto i = 0;", "int"},
|
|
{"^auto f(){ return 1;};", "int"},
|
|
};
|
|
for (Test T : Tests) {
|
|
Annotations File(T.AnnotatedCode);
|
|
auto AST = TestTU::withCode(File.code()).build();
|
|
SourceManagerForFile SM("foo.cpp", File.code());
|
|
|
|
for (Position Pos : File.points()) {
|
|
auto Location = sourceLocationInMainFile(SM.get(), Pos);
|
|
ASSERT_TRUE(!!Location) << llvm::toString(Location.takeError());
|
|
auto DeducedType = getDeducedType(AST.getASTContext(), *Location);
|
|
EXPECT_EQ(DeducedType->getAsString(), T.DeducedType);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST(ClangdAST, GetQualification) {
|
|
// Tries to insert the decl `Foo` into position of each decl named `insert`.
|
|
// This is done to get an appropriate DeclContext for the insertion location.
|
|
// Qualifications are the required nested name specifier to spell `Foo` at the
|
|
// `insert`ion location.
|
|
// VisibleNamespaces are assumed to be visible at every insertion location.
|
|
const struct {
|
|
llvm::StringRef Test;
|
|
std::vector<llvm::StringRef> Qualifications;
|
|
std::vector<std::string> VisibleNamespaces;
|
|
} Cases[] = {
|
|
{
|
|
R"cpp(
|
|
namespace ns1 { namespace ns2 { class Foo {}; } }
|
|
void insert(); // ns1::ns2::Foo
|
|
namespace ns1 {
|
|
void insert(); // ns2::Foo
|
|
namespace ns2 {
|
|
void insert(); // Foo
|
|
}
|
|
using namespace ns2;
|
|
void insert(); // Foo
|
|
}
|
|
using namespace ns1;
|
|
void insert(); // ns2::Foo
|
|
using namespace ns2;
|
|
void insert(); // Foo
|
|
)cpp",
|
|
{"ns1::ns2::", "ns2::", "", "", "ns2::", ""},
|
|
{},
|
|
},
|
|
{
|
|
R"cpp(
|
|
namespace ns1 { namespace ns2 { class Bar { void Foo(); }; } }
|
|
void insert(); // ns1::ns2::Bar::Foo
|
|
namespace ns1 {
|
|
void insert(); // ns2::Bar::Foo
|
|
namespace ns2 {
|
|
void insert(); // Bar::Foo
|
|
}
|
|
using namespace ns2;
|
|
void insert(); // Bar::Foo
|
|
}
|
|
using namespace ns1;
|
|
void insert(); // ns2::Bar::Foo
|
|
using namespace ns2;
|
|
void insert(); // Bar::Foo
|
|
)cpp",
|
|
{"ns1::ns2::Bar::", "ns2::Bar::", "Bar::", "Bar::", "ns2::Bar::",
|
|
"Bar::"},
|
|
{},
|
|
},
|
|
{
|
|
R"cpp(
|
|
namespace ns1 { namespace ns2 { void Foo(); } }
|
|
void insert(); // ns2::Foo
|
|
namespace ns1 {
|
|
void insert(); // ns2::Foo
|
|
namespace ns2 {
|
|
void insert(); // Foo
|
|
}
|
|
}
|
|
)cpp",
|
|
{"ns2::", "ns2::", ""},
|
|
{"ns1::"},
|
|
},
|
|
};
|
|
for (const auto &Case : Cases) {
|
|
Annotations Test(Case.Test);
|
|
TestTU TU = TestTU::withCode(Test.code());
|
|
ParsedAST AST = TU.build();
|
|
std::vector<const Decl *> InsertionPoints;
|
|
const NamedDecl *TargetDecl;
|
|
findDecl(AST, [&](const NamedDecl &ND) {
|
|
if (ND.getNameAsString() == "Foo") {
|
|
TargetDecl = &ND;
|
|
return true;
|
|
}
|
|
|
|
if (ND.getNameAsString() == "insert")
|
|
InsertionPoints.push_back(&ND);
|
|
return false;
|
|
});
|
|
|
|
ASSERT_EQ(InsertionPoints.size(), Case.Qualifications.size());
|
|
for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
|
|
const Decl *D = InsertionPoints[I];
|
|
if (Case.VisibleNamespaces.empty()) {
|
|
EXPECT_EQ(getQualification(AST.getASTContext(),
|
|
D->getLexicalDeclContext(), D->getBeginLoc(),
|
|
TargetDecl),
|
|
Case.Qualifications[I]);
|
|
} else {
|
|
EXPECT_EQ(getQualification(AST.getASTContext(),
|
|
D->getLexicalDeclContext(), TargetDecl,
|
|
Case.VisibleNamespaces),
|
|
Case.Qualifications[I]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST(ClangdAST, PrintType) {
|
|
const struct {
|
|
llvm::StringRef Test;
|
|
std::vector<llvm::StringRef> Types;
|
|
} Cases[] = {
|
|
{
|
|
R"cpp(
|
|
namespace ns1 { namespace ns2 { class Foo {}; } }
|
|
void insert(); // ns1::ns2::Foo
|
|
namespace ns1 {
|
|
void insert(); // ns2::Foo
|
|
namespace ns2 {
|
|
void insert(); // Foo
|
|
}
|
|
}
|
|
)cpp",
|
|
{"ns1::ns2::Foo", "ns2::Foo", "Foo"},
|
|
},
|
|
{
|
|
R"cpp(
|
|
namespace ns1 {
|
|
typedef int Foo;
|
|
}
|
|
void insert(); // ns1::Foo
|
|
namespace ns1 {
|
|
void insert(); // Foo
|
|
}
|
|
)cpp",
|
|
{"ns1::Foo", "Foo"},
|
|
},
|
|
};
|
|
for (const auto &Case : Cases) {
|
|
Annotations Test(Case.Test);
|
|
TestTU TU = TestTU::withCode(Test.code());
|
|
ParsedAST AST = TU.build();
|
|
std::vector<const DeclContext *> InsertionPoints;
|
|
const TypeDecl *TargetDecl = nullptr;
|
|
findDecl(AST, [&](const NamedDecl &ND) {
|
|
if (ND.getNameAsString() == "Foo") {
|
|
if (const auto *TD = llvm::dyn_cast<TypeDecl>(&ND)) {
|
|
TargetDecl = TD;
|
|
return true;
|
|
}
|
|
} else if (ND.getNameAsString() == "insert")
|
|
InsertionPoints.push_back(ND.getDeclContext());
|
|
return false;
|
|
});
|
|
|
|
ASSERT_EQ(InsertionPoints.size(), Case.Types.size());
|
|
for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
|
|
const auto *DC = InsertionPoints[I];
|
|
EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC),
|
|
Case.Types[I]);
|
|
}
|
|
}
|
|
}
|
|
} // namespace
|
|
} // namespace clangd
|
|
} // namespace clang
|