15#include "clang/AST/ASTTypeTraits.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclBase.h"
19#include "clang/AST/DeclTemplate.h"
20#include "clang/Basic/AttrKinds.h"
21#include "clang/Basic/SourceManager.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/Support/Casting.h"
24#include "gmock/gmock.h"
25#include "gtest/gtest.h"
33using testing::Contains;
35using testing::IsEmpty;
37TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
39 StringRef AnnotatedCode;
40 const char *DeducedType;
42 {
"^auto i = 0;",
"int"},
43 {
"^auto f(){ return 1;};",
"int"},
45 R
"cpp( // auto on struct in a namespace
46 namespace ns1 { struct S {}; }
52 R
"cpp( // decltype on struct
53 namespace ns1 { struct S {}; }
60 R
"cpp(// decltype(auto) on struct&
67 ^decltype(auto) k = j;
72 R
"cpp( // auto on template class
74 template<typename T> class Foo {};
80 R
"cpp( // auto on initializer list.
84 class [[initializer_list]] { const _E *a, *b; };
89 "std::initializer_list<int>",
92 R
"cpp( // auto in function return type with trailing return type
94 ^auto test() -> decltype(Foo()) {
101 R
"cpp( // decltype in trailing return type
103 auto test() -> ^decltype(Foo()) {
110 R
"cpp( // auto in function return type
119 R
"cpp( // auto& in function return type
129 R
"cpp( // auto* in function return type
139 R
"cpp( // const auto& in function return type
141 const ^auto& test() {
149 R
"cpp( // decltype(auto) in function return (value)
151 ^decltype(auto) test() {
158 R
"cpp( // decltype(auto) in function return (ref)
160 ^decltype(auto) test() {
168 R
"cpp( // decltype(auto) in function return (const ref)
170 ^decltype(auto) test() {
178 R
"cpp( // auto on alias
187 // Generic lambda param.
189 auto Generic = [](^auto x) { return 0; };
190 int m = Generic(Foo{});
196 // Generic lambda instantiated twice, matching deduction.
198 auto Generic = [](^auto x, auto y) { return 0; };
199 int m = Generic(Foo{}, "one");
200 int n = Generic(Foo{}, 2);
207 // Generic lambda instantiated twice, conflicting deduction.
209 auto Generic = [](^auto y) { return 0; };
210 int m = Generic("one");
217 // Generic function param.
219 int generic(^auto x) { return 0; }
220 int m = generic(Foo{});
226 // More complicated param type involving auto.
227 template <class> concept C = true;
229 int generic(C ^auto *x) { return 0; }
230 const Foo *Ptr = nullptr;
231 int m = generic(Ptr);
236 for (Test T : Tests) {
239 TU.ExtraArgs.push_back(
"-std=c++20");
240 auto AST = TU.build();
241 SourceManagerForFile SM(
"foo.cpp",
File.code());
243 SCOPED_TRACE(
T.AnnotatedCode);
244 EXPECT_FALSE(
File.points().empty());
250 if (
T.DeducedType ==
nullptr) {
251 EXPECT_FALSE(DeducedType);
253 ASSERT_TRUE(DeducedType);
254 EXPECT_EQ(DeducedType->getAsString(),
T.DeducedType);
260TEST(ClangdAST, GetOnlyInstantiation) {
263 llvm::StringLiteral NodeType;
268 template <typename> class X {};
272 "template<> class X<int> {}",
276 template <typename T> T X = T{};
285 template <typename T> int X(T) { return 42; }
289 "template<> int X<const char *>(const char *)",
293 int X(auto *x) { return 42; }
297 "template<> int X<const char>(const char *x)",
301 for (
const auto &Case : Cases) {
302 SCOPED_TRACE(Case.Code);
304 TU.ExtraArgs.push_back(
"-std=c++20");
305 auto AST = TU.build();
306 PrintingPolicy PP =
AST.getASTContext().getPrintingPolicy();
307 PP.TerseOutput =
true;
310 const_cast<NamedDecl *
>(&
findDecl(
AST, [&](
const NamedDecl &D) {
311 return D.getDescribedTemplate() !=
nullptr &&
312 D.getDeclKindName() == Case.NodeType;
314 llvm::raw_string_ostream OS(Name);
315 Result->print(OS, PP);
319 EXPECT_EQ(Case.Name, Name);
321 EXPECT_THAT(Name, IsEmpty());
325TEST(ClangdAST, GetContainedAutoParamType) {
345 TU.ExtraArgs.push_back("-std=c++20");
346 auto AST = TU.build();
348 const auto &WithAuto =
349 llvm::cast<FunctionTemplateDecl>(
findDecl(
AST,
"withAuto"));
350 auto ParamsWithAuto = WithAuto.getTemplatedDecl()->parameters();
351 auto *TemplateParamsWithAuto = WithAuto.getTemplateParameters();
352 ASSERT_EQ(ParamsWithAuto.size(), TemplateParamsWithAuto->size());
354 for (
unsigned I = 0; I < ParamsWithAuto.size(); ++I) {
355 SCOPED_TRACE(ParamsWithAuto[I]->getNameAsString());
357 ParamsWithAuto[I]->getTypeSourceInfo()->getTypeLoc());
358 ASSERT_FALSE(Loc.isNull());
359 EXPECT_EQ(Loc.getTypePtr()->getDecl(), TemplateParamsWithAuto->getParam(I));
362 const auto &WithoutAuto =
363 llvm::cast<FunctionDecl>(
findDecl(
AST,
"withoutAuto"));
364 for (
auto *ParamWithoutAuto : WithoutAuto.parameters()) {
366 ParamWithoutAuto->getTypeSourceInfo()->getTypeLoc())
371TEST(ClangdAST, GetQualification) {
378 llvm::StringRef Test;
379 std::vector<llvm::StringRef> Qualifications;
380 std::vector<std::string> VisibleNamespaces;
384 namespace ns1 { namespace ns2 { class Foo {}; } }
385 void insert(); // ns1::ns2::Foo
387 void insert(); // ns2::Foo
389 void insert(); // Foo
392 void insert(); // Foo
395 void insert(); // ns2::Foo
397 void insert(); // Foo
399 {"ns1::ns2::",
"ns2::",
"",
"",
"ns2::",
""},
404 namespace ns1 { namespace ns2 { class Bar { void Foo(); }; } }
405 void insert(); // ns1::ns2::Bar::Foo
407 void insert(); // ns2::Bar::Foo
409 void insert(); // Bar::Foo
412 void insert(); // Bar::Foo
415 void insert(); // ns2::Bar::Foo
417 void insert(); // Bar::Foo
419 {"ns1::ns2::Bar::",
"ns2::Bar::",
"Bar::",
"Bar::",
"ns2::Bar::",
425 namespace ns1 { namespace ns2 { void Foo(); } }
426 void insert(); // ns1::ns2::Foo
428 void insert(); // ns2::Foo
430 void insert(); // Foo
434 {"ns1::ns2::",
"ns2::",
""},
444 void insert(); // ns::Foo
450 for (
const auto &Case : Cases) {
454 std::vector<const Decl *> InsertionPoints;
455 const NamedDecl *TargetDecl;
457 if (ND.getNameAsString() ==
"Foo") {
462 if (ND.getNameAsString() ==
"insert")
463 InsertionPoints.push_back(&ND);
467 ASSERT_EQ(InsertionPoints.size(), Case.Qualifications.size());
468 for (
size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
469 const Decl *
D = InsertionPoints[I];
470 if (Case.VisibleNamespaces.empty()) {
472 D->getLexicalDeclContext(),
D->getBeginLoc(),
474 Case.Qualifications[I]);
477 D->getLexicalDeclContext(), TargetDecl,
478 Case.VisibleNamespaces),
479 Case.Qualifications[I]);
485TEST(ClangdAST, PrintType) {
487 llvm::StringRef Test;
488 std::vector<llvm::StringRef> Types;
492 namespace ns1 { namespace ns2 { class Foo {}; } }
493 void insert(); // ns1::ns2::Foo
495 void insert(); // ns2::Foo
497 void insert(); // Foo
501 {"ns1::ns2::Foo",
"ns2::Foo",
"Foo"},
508 void insert(); // ns1::Foo
510 void insert(); // Foo
516 for (
const auto &Case : Cases) {
520 std::vector<const DeclContext *> InsertionPoints;
521 const TypeDecl *TargetDecl =
nullptr;
523 if (ND.getNameAsString() ==
"Foo") {
524 if (
const auto *TD = llvm::dyn_cast<TypeDecl>(&ND)) {
528 }
else if (ND.getNameAsString() ==
"insert")
529 InsertionPoints.push_back(ND.getDeclContext());
533 ASSERT_EQ(InsertionPoints.size(), Case.Types.size());
534 for (
size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
535 const auto *DC = InsertionPoints[I];
536 EXPECT_EQ(
printType(
AST.getASTContext().getTypeDeclType(TargetDecl), *DC,
543TEST(ClangdAST, IsDeeplyNested) {
569MATCHER_P(attrKind, K,
"") {
return arg->getKind() == K; }
571MATCHER(implicitAttr,
"") {
return arg->isImplicit(); }
573TEST(ClangdAST, GetAttributes) {
574 const char *Code = R
"cpp(
576 class [[nodiscard]] Y{};
577 void f(int * a, int * __attribute__((nonnull)) b);
584 auto DeclAttrs = [&](llvm::StringRef Name) {
588 ASSERT_THAT(DeclAttrs(
"X"), Each(implicitAttr()));
589 ASSERT_THAT(DeclAttrs(
"Y"), Contains(attrKind(attr::WarnUnusedResult)));
590 ASSERT_THAT(DeclAttrs(
"f"), Each(implicitAttr()));
591 ASSERT_THAT(DeclAttrs(
"a"), Each(implicitAttr()));
592 ASSERT_THAT(DeclAttrs(
"b"), Contains(attrKind(attr::NonNull)));
594 Stmt *FooBody = cast<FunctionDecl>(
findDecl(
AST,
"foo")).getBody();
595 IfStmt *FooIf = cast<IfStmt>(cast<CompoundStmt>(FooBody)->body_front());
597 Each(implicitAttr()));
598 ASSERT_THAT(
getAttributes(DynTypedNode::create(*FooIf->getThen())),
599 Contains(attrKind(attr::Unlikely)));
602TEST(ClangdAST, HasReservedName) {
606 inline namespace __1 { class error_code; }
607 namespace __detail { int secret; }
625TEST(ClangdAST, PreferredIncludeDirective) {
626 auto ComputePreferredDirective = [](
TestTU &TU) {
627 auto AST = TU.build();
629 AST.getIncludeStructure().MainFileIncludes,
630 AST.getLocalTopLevelDecls());
635 ObjCTU.Filename = "TestTU.m";
636 EXPECT_EQ(ComputePreferredDirective(ObjCTU),
642 HeaderTU.Filename = "TestTUHeader.h";
643 HeaderTU.ExtraArgs = {
"-xobjective-c++-header"};
644 EXPECT_EQ(ComputePreferredDirective(HeaderTU),
648 HeaderTU.Code = R
"cpp(
651 EXPECT_EQ(ComputePreferredDirective(HeaderTU),
654 HeaderTU.Code = R"cpp(
660 EXPECT_EQ(ComputePreferredDirective(HeaderTU),
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Stores and provides access to parsed AST.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
std::string printType(const QualType QT, const DeclContext &CurContext, const llvm::StringRef Placeholder, bool FullyQualify)
Returns a QualType as string.
std::string getQualification(ASTContext &Context, const DeclContext *DestContext, SourceLocation InsertionPoint, const NamedDecl *ND)
Gets the nested name specifier necessary for spelling ND in DestContext, at InsertionPoint.
NamedDecl * getOnlyInstantiation(NamedDecl *TemplatedDecl)
std::optional< QualType > getDeducedType(ASTContext &ASTCtx, const HeuristicResolver *Resolver, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
Symbol::IncludeDirective preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts, ArrayRef< Inclusion > MainFileIncludes, ArrayRef< const Decl * > TopLevelDecls)
Infer the include directive to use for the given FileName.
TEST(BackgroundQueueTest, Priority)
bool hasReservedName(const Decl &D)
Returns true if this is a NamedDecl with a reserved name.
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
std::vector< const Attr * > getAttributes(const DynTypedNode &N)
Return attributes attached directly to a node.
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
bool hasReservedScope(const DeclContext &DC)
Returns true if this scope would be written with a reserved name.
TemplateTypeParmTypeLoc getContainedAutoParamType(TypeLoc TL)
bool isDeeplyNested(const Decl *D, unsigned MaxDepth)
Checks whether D is more than MaxDepth away from translation unit scope.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
@ Include
#include "header.h"
@ Import
#import "header.h"
static TestTU withCode(llvm::StringRef Code)