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/Basic/AttrKinds.h"
20#include "clang/Basic/SourceManager.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/Casting.h"
23#include "gmock/gmock.h"
24#include "gtest/gtest.h"
32using testing::Contains;
34using testing::IsEmpty;
36TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
38 StringRef AnnotatedCode;
39 const char *DeducedType;
41 {
"^auto i = 0;",
"int"},
42 {
"^auto f(){ return 1;};",
"int"},
44 R
"cpp( // auto on struct in a namespace
45 namespace ns1 { struct S {}; }
51 R
"cpp( // decltype on struct
52 namespace ns1 { struct S {}; }
59 R
"cpp(// decltype(auto) on struct&
66 ^decltype(auto) k = j;
71 R
"cpp( // auto on template class
73 template<typename T> class Foo {};
79 R
"cpp( // auto on initializer list.
83 class [[initializer_list]] { const _E *a, *b; };
88 "std::initializer_list<int>",
91 R
"cpp( // auto in function return type with trailing return type
93 ^auto test() -> decltype(Foo()) {
100 R
"cpp( // decltype in trailing return type
102 auto test() -> ^decltype(Foo()) {
109 R
"cpp( // auto in function return type
118 R
"cpp( // auto& in function return type
128 R
"cpp( // auto* in function return type
138 R
"cpp( // const auto& in function return type
140 const ^auto& test() {
148 R
"cpp( // decltype(auto) in function return (value)
150 ^decltype(auto) test() {
157 R
"cpp( // decltype(auto) in function return (ref)
159 ^decltype(auto) test() {
167 R
"cpp( // decltype(auto) in function return (const ref)
169 ^decltype(auto) test() {
177 R
"cpp( // auto on alias
186 // Generic lambda param.
188 auto Generic = [](^auto x) { return 0; };
189 int m = Generic(Foo{});
195 // Generic lambda instantiated twice, matching deduction.
197 auto Generic = [](^auto x, auto y) { return 0; };
198 int m = Generic(Foo{}, "one");
199 int n = Generic(Foo{}, 2);
206 // Generic lambda instantiated twice, conflicting deduction.
208 auto Generic = [](^auto y) { return 0; };
209 int m = Generic("one");
216 // Generic function param.
218 int generic(^auto x) { return 0; }
219 int m = generic(Foo{});
225 // More complicated param type involving auto.
226 template <class> concept C = true;
228 int generic(C ^auto *x) { return 0; }
229 const Foo *Ptr = nullptr;
230 int m = generic(Ptr);
235 for (Test T : Tests) {
238 TU.ExtraArgs.push_back(
"-std=c++20");
239 auto AST = TU.build();
240 SourceManagerForFile SM(
"foo.cpp",
File.code());
242 SCOPED_TRACE(
T.AnnotatedCode);
243 EXPECT_FALSE(
File.points().empty());
249 if (
T.DeducedType ==
nullptr) {
250 EXPECT_FALSE(DeducedType);
252 ASSERT_TRUE(DeducedType);
253 EXPECT_EQ(DeducedType->getAsString(),
T.DeducedType);
259TEST(ClangdAST, GetOnlyInstantiation) {
262 llvm::StringLiteral NodeType;
267 template <typename> class X {};
271 "template<> class X<int> {}",
275 template <typename T> T X = T{};
284 template <typename T> int X(T) { return 42; }
288 "template<> int X<const char *>(const char *)",
292 int X(auto *x) { return 42; }
296 "template<> int X<const char>(const char *x)",
300 for (
const auto &Case : Cases) {
301 SCOPED_TRACE(Case.Code);
303 TU.ExtraArgs.push_back(
"-std=c++20");
304 auto AST = TU.build();
305 PrintingPolicy PP =
AST.getASTContext().getPrintingPolicy();
306 PP.TerseOutput =
true;
309 const_cast<NamedDecl *
>(&
findDecl(
AST, [&](
const NamedDecl &D) {
310 return D.getDescribedTemplate() !=
nullptr &&
311 D.getDeclKindName() == Case.NodeType;
313 llvm::raw_string_ostream OS(Name);
314 Result->print(OS, PP);
318 EXPECT_EQ(Case.Name, Name);
320 EXPECT_THAT(Name, IsEmpty());
324TEST(ClangdAST, GetContainedAutoParamType) {
344 TU.ExtraArgs.push_back("-std=c++20");
345 auto AST = TU.build();
347 const auto &WithAuto =
348 llvm::cast<FunctionTemplateDecl>(
findDecl(
AST,
"withAuto"));
349 auto ParamsWithAuto = WithAuto.getTemplatedDecl()->parameters();
350 auto *TemplateParamsWithAuto = WithAuto.getTemplateParameters();
351 ASSERT_EQ(ParamsWithAuto.size(), TemplateParamsWithAuto->size());
353 for (
unsigned I = 0; I < ParamsWithAuto.size(); ++I) {
354 SCOPED_TRACE(ParamsWithAuto[I]->getNameAsString());
356 ParamsWithAuto[I]->getTypeSourceInfo()->getTypeLoc());
357 ASSERT_FALSE(Loc.isNull());
358 EXPECT_EQ(Loc.getTypePtr()->getDecl(), TemplateParamsWithAuto->getParam(I));
361 const auto &WithoutAuto =
362 llvm::cast<FunctionDecl>(
findDecl(
AST,
"withoutAuto"));
363 for (
auto *ParamWithoutAuto : WithoutAuto.parameters()) {
365 ParamWithoutAuto->getTypeSourceInfo()->getTypeLoc())
370TEST(ClangdAST, GetQualification) {
377 llvm::StringRef Test;
378 std::vector<llvm::StringRef> Qualifications;
379 std::vector<std::string> VisibleNamespaces;
383 namespace ns1 { namespace ns2 { class Foo {}; } }
384 void insert(); // ns1::ns2::Foo
386 void insert(); // ns2::Foo
388 void insert(); // Foo
391 void insert(); // Foo
394 void insert(); // ns2::Foo
396 void insert(); // Foo
398 {"ns1::ns2::",
"ns2::",
"",
"",
"ns2::",
""},
403 namespace ns1 { namespace ns2 { class Bar { void Foo(); }; } }
404 void insert(); // ns1::ns2::Bar::Foo
406 void insert(); // ns2::Bar::Foo
408 void insert(); // Bar::Foo
411 void insert(); // Bar::Foo
414 void insert(); // ns2::Bar::Foo
416 void insert(); // Bar::Foo
418 {"ns1::ns2::Bar::",
"ns2::Bar::",
"Bar::",
"Bar::",
"ns2::Bar::",
424 namespace ns1 { namespace ns2 { void Foo(); } }
425 void insert(); // ns1::ns2::Foo
427 void insert(); // ns2::Foo
429 void insert(); // Foo
433 {"ns1::ns2::",
"ns2::",
""},
443 void insert(); // ns::Foo
449 for (
const auto &Case : Cases) {
453 std::vector<const Decl *> InsertionPoints;
454 const NamedDecl *TargetDecl;
456 if (ND.getNameAsString() ==
"Foo") {
461 if (ND.getNameAsString() ==
"insert")
462 InsertionPoints.push_back(&ND);
466 ASSERT_EQ(InsertionPoints.size(), Case.Qualifications.size());
467 for (
size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
468 const Decl *
D = InsertionPoints[I];
469 if (Case.VisibleNamespaces.empty()) {
471 D->getLexicalDeclContext(),
D->getBeginLoc(),
473 Case.Qualifications[I]);
476 D->getLexicalDeclContext(), TargetDecl,
477 Case.VisibleNamespaces),
478 Case.Qualifications[I]);
484TEST(ClangdAST, PrintType) {
486 llvm::StringRef Test;
487 std::vector<llvm::StringRef> Types;
491 namespace ns1 { namespace ns2 { class Foo {}; } }
492 void insert(); // ns1::ns2::Foo
494 void insert(); // ns2::Foo
496 void insert(); // Foo
500 {"ns1::ns2::Foo",
"ns2::Foo",
"Foo"},
507 void insert(); // ns1::Foo
509 void insert(); // Foo
515 for (
const auto &Case : Cases) {
519 std::vector<const DeclContext *> InsertionPoints;
520 const TypeDecl *TargetDecl =
nullptr;
522 if (ND.getNameAsString() ==
"Foo") {
523 if (
const auto *TD = llvm::dyn_cast<TypeDecl>(&ND)) {
527 }
else if (ND.getNameAsString() ==
"insert")
528 InsertionPoints.push_back(ND.getDeclContext());
532 ASSERT_EQ(InsertionPoints.size(), Case.Types.size());
533 for (
size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
534 const auto *DC = InsertionPoints[I];
535 EXPECT_EQ(
printType(
AST.getASTContext().getTypeDeclType(TargetDecl), *DC,
542TEST(ClangdAST, IsDeeplyNested) {
568MATCHER_P(attrKind, K,
"") {
return arg->getKind() == K; }
570MATCHER(implicitAttr,
"") {
return arg->isImplicit(); }
572TEST(ClangdAST, GetAttributes) {
573 const char *Code = R
"cpp(
575 class [[nodiscard]] Y{};
576 void f(int * a, int * __attribute__((nonnull)) b);
583 auto DeclAttrs = [&](llvm::StringRef Name) {
587 ASSERT_THAT(DeclAttrs(
"X"), Each(implicitAttr()));
588 ASSERT_THAT(DeclAttrs(
"Y"), Contains(attrKind(attr::WarnUnusedResult)));
589 ASSERT_THAT(DeclAttrs(
"f"), Each(implicitAttr()));
590 ASSERT_THAT(DeclAttrs(
"a"), Each(implicitAttr()));
591 ASSERT_THAT(DeclAttrs(
"b"), Contains(attrKind(attr::NonNull)));
593 Stmt *FooBody = cast<FunctionDecl>(
findDecl(
AST,
"foo")).getBody();
594 IfStmt *FooIf = cast<IfStmt>(cast<CompoundStmt>(FooBody)->body_front());
596 Each(implicitAttr()));
597 ASSERT_THAT(
getAttributes(DynTypedNode::create(*FooIf->getThen())),
598 Contains(attrKind(attr::Unlikely)));
601TEST(ClangdAST, HasReservedName) {
605 inline namespace __1 { class error_code; }
606 namespace __detail { int secret; }
624TEST(ClangdAST, PreferredIncludeDirective) {
625 auto ComputePreferredDirective = [](
TestTU &TU) {
626 auto AST = TU.build();
628 AST.getIncludeStructure().MainFileIncludes,
629 AST.getLocalTopLevelDecls());
634 ObjCTU.Filename = "TestTU.m";
635 EXPECT_EQ(ComputePreferredDirective(ObjCTU),
641 HeaderTU.Filename = "TestTUHeader.h";
642 HeaderTU.ExtraArgs = {
"-xobjective-c++-header"};
643 EXPECT_EQ(ComputePreferredDirective(HeaderTU),
647 HeaderTU.Code = R
"cpp(
650 EXPECT_EQ(ComputePreferredDirective(HeaderTU),
653 HeaderTU.Code = R"cpp(
659 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)