diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2043,9 +2043,14 @@ // will be mistakenly used (since the default is to assume that the record // is not anonymous). This is a relatively uncommon case and therefore the // additional complexity needed to prevent this is not worthwhile. - OS << Policy.getOpenDelimiterForUnnamedEntity() - << (IsAnonymousStructOrUnion ? "anonymous " : "unnamed ") - << TD->getKindName(); + OS << Policy.getOpenDelimiterForUnnamedEntity(); + + if (isa(TD) && cast(TD)->isLambda()) { + OS << "lambda"; + } else { + OS << (IsAnonymousStructOrUnion ? "anonymous " : "unnamed ") + << TD->getKindName(); + } if (Policy.AnonymousTagLocations) printPresumedLocationAt(OS, Ctx.getSourceManager(), Policy, @@ -2054,6 +2059,63 @@ OS << Policy.getCloseDelimiterForUnnamedEntity(); } +/// If \p FD is an unnamed field corresponding to a lambda capture print +/// the pretty-printed name of the capture and return true. Return false +/// otherwise. +static bool maybePrintFieldForLambdaCapture(raw_ostream &OS, + const PrintingPolicy &Policy, + const FieldDecl *FD) { + assert(FD && "missing field decl!"); + struct Result { + LambdaCaptureKind LCK; + const VarDecl *VD; + }; + auto getVarForLambdaField = + [](const FieldDecl *FD) -> llvm::Optional { + if (const auto *CXXRD = dyn_cast(FD->getParent())) { + if (CXXRD->isLambda()) { + // For a simple-capture, refer to the captured variable. + // For an init-capture, refer to the introduced variable. + // + // The captures and the fields are in 1-to-1 correspondance. + // Look at the fields until we find the corresponding capture. + RecordDecl::field_iterator Field = CXXRD->field_begin(); + for (const LambdaCapture &C : CXXRD->captures()) { + if (*Field == FD) + return Result{C.getCaptureKind(), + C.capturesVariable() ? C.getCapturedVar() : nullptr}; + ++Field; + } + } + } + return llvm::None; + }; + + llvm::Optional VarForLambdaField = getVarForLambdaField(FD); + if (VarForLambdaField) { + switch (VarForLambdaField->LCK) { + case LCK_This: + OS << "this"; + return true; + case LCK_StarThis: + OS << "*this"; + return true; + case LCK_ByCopy: + case LCK_ByRef: + VarForLambdaField->VD->getNameForDiagnostic(OS, Policy, + /*Qualified=*/false); + return true; + case LCK_VLAType: + // The captured VLA bound is not stored in the LambdaCapture, so fall + // back to displaying (unnamed field at ...). + return false; + } + llvm_unreachable("unexpected LambdaCaptureKind!"); + } + + return false; +} + static void printUnnamedDeclarator(raw_ostream &OS, const ASTContext &Ctx, const DeclaratorDecl *DD) { assert(DD && "missing DeclaratorDecl!"); @@ -2062,8 +2124,16 @@ isa(DD) && "expected a field or variable declaration!"); const PrintingPolicy &Policy = Ctx.getPrintingPolicy(); + // The field in a lambda class for a capture is formally unnamed. However if + // this field correspond to a capture (either implicit or explicit) we can use + // the pretty-printed name of the capture instead. + if (isa(DD) && + maybePrintFieldForLambdaCapture(OS, Policy, cast(DD))) + return; + OS << Policy.getOpenDelimiterForUnnamedEntity() << "unnamed " - << (isa(DD) ? "field" : "variable"); + << (isa(DD) ? "field" + : isa(DD) ? "parameter" : "variable"); // Don't print the location of anonymous records twice. bool SuppressLocation = false; diff --git a/clang/test/AST/ast-dump-record-definition-data-json.cpp b/clang/test/AST/ast-dump-record-definition-data-json.cpp --- a/clang/test/AST/ast-dump-record-definition-data-json.cpp +++ b/clang/test/AST/ast-dump-record-definition-data-json.cpp @@ -323,7 +323,7 @@ // CHECK-NEXT: }, // CHECK-NEXT: "isImplicit": true, // CHECK-NEXT: "isReferenced": true, -// CHECK-NEXT: "name": "~(unnamed class at {{.*}}:4:29)", +// CHECK-NEXT: "name": "~(lambda at {{.*}}:4:29)", // CHECK-NEXT: "mangledName": "_ZZ1fvEN3$_0D1Ev", // CHECK-NEXT: "type": { // CHECK-NEXT: "qualType": "void () noexcept" @@ -708,7 +708,7 @@ // CHECK-NEXT: }, // CHECK-NEXT: "isImplicit": true, // CHECK-NEXT: "isReferenced": true, -// CHECK-NEXT: "name": "~(unnamed class at {{.*}}:5:26)", +// CHECK-NEXT: "name": "~(lambda at {{.*}}:5:26)", // CHECK-NEXT: "mangledName": "_ZZ1fvEN3$_1D1Ev", // CHECK-NEXT: "type": { // CHECK-NEXT: "qualType": "void () noexcept" diff --git a/clang/test/Analysis/explain-svals.cpp b/clang/test/Analysis/explain-svals.cpp --- a/clang/test/Analysis/explain-svals.cpp +++ b/clang/test/Analysis/explain-svals.cpp @@ -98,7 +98,7 @@ } // end of anonymous namespace void test_6() { - clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of parameter '\(unnamed variable at .*:23:30 of type S\)'$}}}} + clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of parameter '\(unnamed parameter at .*:23:30 of type S\)'$}}}} clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}} } diff --git a/clang/test/Index/annotate-tokens.cpp b/clang/test/Index/annotate-tokens.cpp --- a/clang/test/Index/annotate-tokens.cpp +++ b/clang/test/Index/annotate-tokens.cpp @@ -77,7 +77,7 @@ // CHECK: Keyword: "operator" [9:5 - 9:13] CXXMethod=operator++:9:5 // CHECK: Punctuation: "++" [9:13 - 9:15] CXXMethod=operator++:9:5 // CHECK: Punctuation: "(" [9:15 - 9:16] CXXMethod=operator++:9:5 -// CHECK: Keyword: "int" [9:16 - 9:19] ParmDecl=(unnamed variable at {{.*}}:9:19 of type int):9:19 (Definition +// CHECK: Keyword: "int" [9:16 - 9:19] ParmDecl=(unnamed parameter at {{.*}}:9:19 of type int):9:19 (Definition // CHECK: Punctuation: ")" [9:19 - 9:20] CXXMethod=operator++:9:5 // CHECK: Punctuation: ";" [9:20 - 9:21] StructDecl=X:7:8 (Definition) // CHECK: Punctuation: "}" [10:1 - 10:2] StructDecl=X:7:8 (Definition) @@ -148,7 +148,7 @@ // CHECK: Punctuation: ")" [23:21 - 23:22] NonTypeTemplateParameter=tfn:23:18 (Definition) // CHECK: Punctuation: "(" [23:22 - 23:23] NonTypeTemplateParameter=tfn:23:18 (Definition) // CHECK: Identifier: "X" [23:23 - 23:24] TypeRef=struct X:7:8 -// CHECK: Punctuation: "*" [23:24 - 23:25] ParmDecl=(unnamed variable at {{.*}}:23:25 of type X *):23:25 (Definition) +// CHECK: Punctuation: "*" [23:24 - 23:25] ParmDecl=(unnamed parameter at {{.*}}:23:25 of type X *):23:25 (Definition) // CHECK: Punctuation: ")" [23:25 - 23:26] NonTypeTemplateParameter=tfn:23:18 (Definition) // CHECK: Punctuation: ">" [23:26 - 23:27] ClassTemplate=TS:24:8 (Definition) // CHECK: Keyword: "struct" [24:1 - 24:7] ClassTemplate=TS:24:8 (Definition) @@ -170,7 +170,7 @@ // CHECK: Punctuation: ")" [28:21 - 28:22] NonTypeTemplateParameter=tfn:28:18 (Definition) // CHECK: Punctuation: "(" [28:22 - 28:23] NonTypeTemplateParameter=tfn:28:18 (Definition) // CHECK: Identifier: "X" [28:23 - 28:24] TypeRef=struct X:7:8 -// CHECK: Punctuation: "*" [28:24 - 28:25] ParmDecl=(unnamed variable at {{.*}}:28:25 of type X *):28:25 (Definition) +// CHECK: Punctuation: "*" [28:24 - 28:25] ParmDecl=(unnamed parameter at {{.*}}:28:25 of type X *):28:25 (Definition) // CHECK: Punctuation: ")" [28:25 - 28:26] NonTypeTemplateParameter=tfn:28:18 (Definition) // CHECK: Punctuation: ">" [28:26 - 28:27] CXXMethod=foo:29:15 (Definition) // CHECK: Keyword: "void" [29:1 - 29:5] CXXMethod=foo:29:15 (Definition) diff --git a/clang/test/Index/linkage.c b/clang/test/Index/linkage.c --- a/clang/test/Index/linkage.c +++ b/clang/test/Index/linkage.c @@ -30,7 +30,7 @@ // CHECK: VarDecl=k:9:7 (Definition)linkage=NoLinkage // CHECK: VarDecl=n:11:12linkage=External // CHECK: FunctionDecl=wibble:12:12linkage=Internal -// CHECK: ParmDecl=(unnamed variable at {{.*}}:12:22 of type int):12:22 (Definition)linkage=NoLinkage +// CHECK: ParmDecl=(unnamed parameter at {{.*}}:12:22 of type int):12:22 (Definition)linkage=NoLinkage // CHECK: FunctionDecl=ena:14:6linkage=External // CHECK: ParmDecl=dio:14:16 (Definition)linkage=NoLinkage // CHECK: ParmDecl=tria:14:25 (Definition)linkage=NoLinkage diff --git a/clang/test/Index/load-decls.c b/clang/test/Index/load-decls.c --- a/clang/test/Index/load-decls.c +++ b/clang/test/Index/load-decls.c @@ -17,6 +17,6 @@ // CHECK: load-decls.c:6:11: DeclRefExpr=Red:2:3 Extent=[6:11 - 6:14] // // CHECK: load-decls.c:9:6: FunctionDecl=PR17970:9:6 Extent=[9:1 - 9:35] -// CHECK: load-decls.c:9:21: ParmDecl=(unnamed variable at {{.*}}:9:21 of type void (*)(int)):9:21 (Definition) Extent=[9:14 - 9:27] -// CHECK: load-decls.c:9:26: ParmDecl=(unnamed variable at {{.*}}:9:26 of type int):9:26 (Definition) Extent=[9:23 - 9:26] -// CHECK: load-decls.c:9:34: ParmDecl=(unnamed variable at {{.*}}:9:34 of type float):9:34 (Definition) Extent=[9:29 - 9:34] +// CHECK: load-decls.c:9:21: ParmDecl=(unnamed parameter at {{.*}}:9:21 of type void (*)(int)):9:21 (Definition) Extent=[9:14 - 9:27] +// CHECK: load-decls.c:9:26: ParmDecl=(unnamed parameter at {{.*}}:9:26 of type int):9:26 (Definition) Extent=[9:23 - 9:26] +// CHECK: load-decls.c:9:34: ParmDecl=(unnamed parameter at {{.*}}:9:34 of type float):9:34 (Definition) Extent=[9:29 - 9:34] diff --git a/clang/test/Index/load-namespaces.cpp b/clang/test/Index/load-namespaces.cpp --- a/clang/test/Index/load-namespaces.cpp +++ b/clang/test/Index/load-namespaces.cpp @@ -40,7 +40,7 @@ // CHECK: load-namespaces.cpp:16:17: NamespaceRef=std0x:14:11 Extent=[16:17 - 16:22] // CHECK: load-namespaces.cpp:18:11: Namespace=std:18:11 (Definition) Extent=[18:1 - 20:2] // CHECK: load-namespaces.cpp:19:7: FunctionDecl=g:19:7 Extent=[19:3 - 19:13] -// CHECK: load-namespaces.cpp:19:12: ParmDecl=(unnamed variable at {{.*}}:19:12 of type int):19:12 (Definition) Extent=[19:9 - 19:12] +// CHECK: load-namespaces.cpp:19:12: ParmDecl=(unnamed parameter at {{.*}}:19:12 of type int):19:12 (Definition) Extent=[19:9 - 19:12] // CHECK: load-namespaces.cpp:22:12: UsingDeclaration=g[19:7, 10:8] Extent=[22:1 - 22:13] // CHECK: load-namespaces.cpp:22:7: NamespaceRef=std:18:11 Extent=[22:7 - 22:10] // CHECK: load-namespaces.cpp:24:11: FunctionDecl=g:24:11 (Definition) Extent=[24:1 - 25:2] diff --git a/clang/test/Index/preamble.c b/clang/test/Index/preamble.c --- a/clang/test/Index/preamble.c +++ b/clang/test/Index/preamble.c @@ -20,7 +20,7 @@ // CHECK: preamble.h:4:9: DeclRefExpr=ptr1:3:10 Extent=[4:9 - 4:13] // CHECK: preamble.h:5:10: IntegerLiteral= Extent=[5:10 - 5:11] // CHECK: preamble.c:8:5: FunctionDecl=wibble:8:5 Extent=[8:1 - 8:16] -// CHECK: preamble.c:8:15: ParmDecl=(unnamed variable at {{.*}}:8:15 of type int):8:15 (Definition) Extent=[8:12 - 8:15] +// CHECK: preamble.c:8:15: ParmDecl=(unnamed parameter at {{.*}}:8:15 of type int):8:15 (Definition) Extent=[8:12 - 8:15] // CHECK-DIAG: preamble.h:4:7:{4:9-4:13}: warning: incompatible pointer types assigning to 'int *' from 'float *' // FIXME: Should see: // preamble.c:5:9: warning: macro is not used diff --git a/clang/test/Index/print-type.c b/clang/test/Index/print-type.c --- a/clang/test/Index/print-type.c +++ b/clang/test/Index/print-type.c @@ -40,7 +40,7 @@ // CHECK: ParmDecl=arr:3:40 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1] // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] // CHECK: ParmDecl=fn:3:55 (Definition) [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=void (int)] [pointeekind=FunctionProto] -// CHECK: ParmDecl=(unnamed variable at {{.*}}:3:62 of type int):3:62 (Definition) [type=int] [typekind=Int] [isPOD=1] +// CHECK: ParmDecl=(unnamed parameter at {{.*}}:3:62 of type int):3:62 (Definition) [type=int] [typekind=Int] [isPOD=1] // CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0] // CHECK: CallExpr=fn:3:55 [type=void] [typekind=Void] [args= [int] [Int]] [isPOD=0] // CHECK: DeclRefExpr=fn:3:55 [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=void (int)] [pointeekind=FunctionProto] diff --git a/clang/test/Index/print-type.cpp b/clang/test/Index/print-type.cpp --- a/clang/test/Index/print-type.cpp +++ b/clang/test/Index/print-type.cpp @@ -142,17 +142,17 @@ // CHECK: FunctionTemplate=tbar:36:3 [type=T (int)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0] // CHECK: TemplateTypeParameter=T:35:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] // CHECK: TypeRef=T:35:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] -// CHECK: ParmDecl=(unnamed variable at {{.*}}:36:11 of type int):36:11 (Definition) [type=int] [typekind=Int] [isPOD=1] +// CHECK: ParmDecl=(unnamed parameter at {{.*}}:36:11 of type int):36:11 (Definition) [type=int] [typekind=Int] [isPOD=1] // CHECK: FunctionTemplate=tbar:39:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0] // CHECK: TemplateTypeParameter=T:38:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] // CHECK: TypeRef=T:38:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] -// CHECK: ParmDecl=(unnamed variable at {{.*}}:39:11 of type int *):39:11 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1] +// CHECK: ParmDecl=(unnamed parameter at {{.*}}:39:11 of type int *):39:11 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1] // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] // CHECK: FunctionTemplate=tbar:42:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0] // CHECK: TemplateTypeParameter=T:41:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] // CHECK: NonTypeTemplateParameter=size:41:27 (Definition) [type=int] [typekind=Int] [isPOD=1] // CHECK: TypeRef=T:41:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] -// CHECK: ParmDecl=(unnamed variable at {{.*}}:42:11 of type int *):42:11 (Definition) [type=int [size]] [typekind=DependentSizedArray] [isPOD=0] +// CHECK: ParmDecl=(unnamed parameter at {{.*}}:42:11 of type int *):42:11 (Definition) [type=int [size]] [typekind=DependentSizedArray] [isPOD=0] // CHECK: DeclRefExpr=size:41:27 [type=int] [typekind=Int] [isPOD=1] // CHECK: FunctionDecl=foo:44:6 (Definition) [type=void (int, int *)] [typekind=FunctionProto] [canonicaltype=void (int, int *)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [int] [Int] [int []] [IncompleteArray]] [isPOD=0] // CHECK: ParmDecl=i:44:14 (Definition) [type=int] [typekind=Int] [isPOD=1] diff --git a/clang/test/Index/recursive-cxx-member-calls.cpp b/clang/test/Index/recursive-cxx-member-calls.cpp --- a/clang/test/Index/recursive-cxx-member-calls.cpp +++ b/clang/test/Index/recursive-cxx-member-calls.cpp @@ -222,13 +222,13 @@ // CHECK-tokens: Keyword: "int" [7:3 - 7:6] FunctionDecl=memcmp:7:7 // CHECK-tokens: Identifier: "memcmp" [7:7 - 7:13] FunctionDecl=memcmp:7:7 // CHECK-tokens: Punctuation: "(" [7:13 - 7:14] FunctionDecl=memcmp:7:7 -// CHECK-tokens: Keyword: "const" [7:14 - 7:19] ParmDecl=(unnamed variable at {{.*}}:7:26 of type const void *):7:26 (Definition) -// CHECK-tokens: Keyword: "void" [7:20 - 7:24] ParmDecl=(unnamed variable at {{.*}}:7:26 of type const void *):7:26 (Definition) -// CHECK-tokens: Punctuation: "*" [7:25 - 7:26] ParmDecl=(unnamed variable at {{.*}}:7:26 of type const void *):7:26 (Definition) +// CHECK-tokens: Keyword: "const" [7:14 - 7:19] ParmDecl=(unnamed parameter at {{.*}}:7:26 of type const void *):7:26 (Definition) +// CHECK-tokens: Keyword: "void" [7:20 - 7:24] ParmDecl=(unnamed parameter at {{.*}}:7:26 of type const void *):7:26 (Definition) +// CHECK-tokens: Punctuation: "*" [7:25 - 7:26] ParmDecl=(unnamed parameter at {{.*}}:7:26 of type const void *):7:26 (Definition) // CHECK-tokens: Punctuation: "," [7:26 - 7:27] FunctionDecl=memcmp:7:7 -// CHECK-tokens: Keyword: "const" [7:28 - 7:33] ParmDecl=(unnamed variable at {{.*}}:7:40 of type const void *):7:40 (Definition) -// CHECK-tokens: Keyword: "void" [7:34 - 7:38] ParmDecl=(unnamed variable at {{.*}}:7:40 of type const void *):7:40 (Definition) -// CHECK-tokens: Punctuation: "*" [7:39 - 7:40] ParmDecl=(unnamed variable at {{.*}}:7:40 of type const void *):7:40 (Definition) +// CHECK-tokens: Keyword: "const" [7:28 - 7:33] ParmDecl=(unnamed parameter at {{.*}}:7:40 of type const void *):7:40 (Definition) +// CHECK-tokens: Keyword: "void" [7:34 - 7:38] ParmDecl=(unnamed parameter at {{.*}}:7:40 of type const void *):7:40 (Definition) +// CHECK-tokens: Punctuation: "*" [7:39 - 7:40] ParmDecl=(unnamed parameter at {{.*}}:7:40 of type const void *):7:40 (Definition) // CHECK-tokens: Punctuation: "," [7:40 - 7:41] FunctionDecl=memcmp:7:7 // CHECK-tokens: Identifier: "size_t" [7:42 - 7:48] TypeRef=size_t:2:25 // CHECK-tokens: Punctuation: ")" [7:48 - 7:49] FunctionDecl=memcmp:7:7 @@ -236,9 +236,9 @@ // CHECK-tokens: Identifier: "size_t" [8:3 - 8:9] TypeRef=size_t:2:25 // CHECK-tokens: Identifier: "strlen" [8:10 - 8:16] FunctionDecl=strlen:8:10 // CHECK-tokens: Punctuation: "(" [8:16 - 8:17] FunctionDecl=strlen:8:10 -// CHECK-tokens: Keyword: "const" [8:17 - 8:22] ParmDecl=(unnamed variable at {{.*}}:8:29 of type const char *):8:29 (Definition) -// CHECK-tokens: Keyword: "char" [8:23 - 8:27] ParmDecl=(unnamed variable at {{.*}}:8:29 of type const char *):8:29 (Definition) -// CHECK-tokens: Punctuation: "*" [8:28 - 8:29] ParmDecl=(unnamed variable at {{.*}}:8:29 of type const char *):8:29 (Definition) +// CHECK-tokens: Keyword: "const" [8:17 - 8:22] ParmDecl=(unnamed parameter at {{.*}}:8:29 of type const char *):8:29 (Definition) +// CHECK-tokens: Keyword: "char" [8:23 - 8:27] ParmDecl=(unnamed parameter at {{.*}}:8:29 of type const char *):8:29 (Definition) +// CHECK-tokens: Punctuation: "*" [8:28 - 8:29] ParmDecl=(unnamed parameter at {{.*}}:8:29 of type const char *):8:29 (Definition) // CHECK-tokens: Punctuation: ")" [8:29 - 8:30] FunctionDecl=strlen:8:10 // CHECK-tokens: Punctuation: ";" [8:30 - 8:31] // CHECK-tokens: Punctuation: "}" [9:1 - 9:2] @@ -1534,13 +1534,13 @@ // CHECK: 4:55: FieldDecl=second:4:55 (Definition) Extent=[4:51 - 4:61] // CHECK: 6:8: UnexposedDecl=:6:8 (Definition) Extent=[6:1 - 9:2] // CHECK: 7:7: FunctionDecl=memcmp:7:7 Extent=[7:3 - 7:49] -// CHECK: 7:26: ParmDecl=(unnamed variable at {{.*}}:7:26 of type const void *):7:26 (Definition) Extent=[7:14 - 7:26] -// CHECK: 7:40: ParmDecl=(unnamed variable at {{.*}}:7:40 of type const void *):7:40 (Definition) Extent=[7:28 - 7:40] -// CHECK: 7:48: ParmDecl=(unnamed variable at {{.*}}:7:48 of type size_t):7:48 (Definition) Extent=[7:42 - 7:48] +// CHECK: 7:26: ParmDecl=(unnamed parameter at {{.*}}:7:26 of type const void *):7:26 (Definition) Extent=[7:14 - 7:26] +// CHECK: 7:40: ParmDecl=(unnamed parameter at {{.*}}:7:40 of type const void *):7:40 (Definition) Extent=[7:28 - 7:40] +// CHECK: 7:48: ParmDecl=(unnamed parameter at {{.*}}:7:48 of type size_t):7:48 (Definition) Extent=[7:42 - 7:48] // CHECK: 7:42: TypeRef=size_t:2:25 Extent=[7:42 - 7:48] // CHECK: 8:10: FunctionDecl=strlen:8:10 Extent=[8:3 - 8:30] // CHECK: 8:3: TypeRef=size_t:2:25 Extent=[8:3 - 8:9] -// CHECK: 8:29: ParmDecl=(unnamed variable at {{.*}}:8:29 of type const char *):8:29 (Definition) Extent=[8:17 - 8:29] +// CHECK: 8:29: ParmDecl=(unnamed parameter at {{.*}}:8:29 of type const char *):8:29 (Definition) Extent=[8:17 - 8:29] // CHECK: 10:17: Namespace=clang:10:17 (Definition) Extent=[10:1 - 35:2] // CHECK: 11:9: ClassDecl=IdentifierInfo:11:9 Extent=[11:3 - 11:23] // CHECK: 12:9: ClassDecl=AttributeList:12:9 (Definition) Extent=[12:3 - 34:4] diff --git a/clang/test/Index/usrs.m b/clang/test/Index/usrs.m --- a/clang/test/Index/usrs.m +++ b/clang/test/Index/usrs.m @@ -281,9 +281,9 @@ // CHECK-source: usrs.m:69:23: UnexposedExpr= Extent=[69:23 - 69:24] // CHECK-source: usrs.m:69:23: IntegerLiteral= Extent=[69:23 - 69:24] // CHECK-source: usrs.m:72:6: FunctionDecl=aux_1:72:6 Extent=[72:1 - 72:26] -// CHECK-source: usrs.m:72:15: ParmDecl=(unnamed variable at {{.*}}:72:15 of type int):72:15 (Definition) Extent=[72:12 - 72:15] -// CHECK-source: usrs.m:72:20: ParmDecl=(unnamed variable at {{.*}}:72:20 of type int):72:20 (Definition) Extent=[72:17 - 72:20] -// CHECK-source: usrs.m:72:25: ParmDecl=(unnamed variable at {{.*}}:72:25 of type int):72:25 (Definition) Extent=[72:22 - 72:25] +// CHECK-source: usrs.m:72:15: ParmDecl=(unnamed parameter at {{.*}}:72:15 of type int):72:15 (Definition) Extent=[72:12 - 72:15] +// CHECK-source: usrs.m:72:20: ParmDecl=(unnamed parameter at {{.*}}:72:20 of type int):72:20 (Definition) Extent=[72:17 - 72:20] +// CHECK-source: usrs.m:72:25: ParmDecl=(unnamed parameter at {{.*}}:72:25 of type int):72:25 (Definition) Extent=[72:22 - 72:25] // CHECK-source: usrs.m:73:5: FunctionDecl=test_multi_declaration:73:5 (Definition) Extent=[73:1 - 77:2] // CHECK-source: usrs.m:73:34: CompoundStmt= Extent=[73:34 - 77:2] // CHECK-source: usrs.m:74:3: DeclStmt= Extent=[74:3 - 74:33] diff --git a/clang/test/Modules/module-private.cpp b/clang/test/Modules/module-private.cpp --- a/clang/test/Modules/module-private.cpp +++ b/clang/test/Modules/module-private.cpp @@ -86,7 +86,7 @@ typedef __module_private__ int local_typedef; // expected-error{{typedef 'local_typedef' cannot be declared __module_private__}} } -void param_private(__module_private__ int) {} // expected-error-re {{parameter '(unnamed variable at {{.*}}:89:42 of type int)' cannot be declared __module_private__}} +void param_private(__module_private__ int) {} // expected-error-re {{parameter '(unnamed parameter at {{.*}}:89:42 of type int)' cannot be declared __module_private__}} // Check struct size struct LikeVisibleStruct { diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -119,19 +119,18 @@ R &operator=(R&&) = delete; }; void g(P &p, Q &q, R &r) { - // FIXME: The note attached to the second error here is just amazingly bad. auto pp = [p] {}; // expected-error {{call to deleted constructor of 'SpecialMembers::P'}} - // expected-cxx14-error-re@-1 {{call to implicitly-deleted copy constructor of '(lambda at {{.*}}:123:15)'}} - // expected-cxx14-note-re@-2 {{copy constructor of '(unnamed class at {{.*}}:123:15)' is implicitly deleted because field '(unnamed field at {{.*}}:123:16 of type SpecialMembers::P)' has a deleted copy constructor}} + // expected-cxx14-error-re@-1 {{call to implicitly-deleted copy constructor of '(lambda at {{.*}}:122:15)'}} + // expected-cxx14-note-re@-2 {{copy constructor of '(lambda at {{.*}}:122:15)' is implicitly deleted because field 'p' has a deleted copy constructor}} auto qq = [q] {}; // expected-error {{attempt to use a deleted function}} - // expected-note-re@-1 {{destructor of '(unnamed class at {{.*}}:127:15)' is implicitly deleted because field '(unnamed field at {{.*}}:127:16 of type SpecialMembers::Q)' has a deleted destructor}} + // expected-note-re@-1 {{destructor of '(lambda at {{.*}}:126:15)' is implicitly deleted because field 'q' has a deleted destructor}} auto a = [r] {}; // expected-note 2{{lambda expression begins here}} decltype(a) b = a; decltype(a) c = static_cast(a); // ok, copies R - a = a; // expected-error-re {{object of type '(lambda at {{.*}}:130:14)' cannot be assigned because its copy assignment operator is implicitly deleted}} - a = static_cast(a); // expected-error-re {{object of type '(lambda at {{.*}}:130:14)' cannot be assigned because its copy assignment operator is implicitly deleted}} + a = a; // expected-error-re {{object of type '(lambda at {{.*}}:129:14)' cannot be assigned because its copy assignment operator is implicitly deleted}} + a = static_cast(a); // expected-error-re {{object of type '(lambda at {{.*}}:129:14)' cannot be assigned because its copy assignment operator is implicitly deleted}} } } @@ -655,10 +654,10 @@ namespace captured_name { void Test() { - union { // expected-note-re {{'(unnamed variable of type (anonymous union at {{.*}}:658:3))' declared here}} + union { // expected-note-re {{'(unnamed variable of type (anonymous union at {{.*}}:657:3))' declared here}} int i; }; - [] { return i; }; // expected-error-re {{variable '(unnamed variable of type (anonymous union at {{.*}}:658:3))' cannot be implicitly captured in a lambda with no capture-default specified}} + [] { return i; }; // expected-error-re {{variable '(unnamed variable of type (anonymous union at {{.*}}:657:3))' cannot be implicitly captured in a lambda with no capture-default specified}} // expected-note@-1 {{lambda expression begins here}} } -}; +} // namespace captured_name diff --git a/clang/test/SemaCXX/warn-large-by-value-copy.cpp b/clang/test/SemaCXX/warn-large-by-value-copy.cpp --- a/clang/test/SemaCXX/warn-large-by-value-copy.cpp +++ b/clang/test/SemaCXX/warn-large-by-value-copy.cpp @@ -16,13 +16,13 @@ S101 f101(S101 s) { return s; } // expected-warning {{return value of 'f101' is a large (101 bytes) pass-by-value object}} \ // expected-warning {{'s' is a large (101 bytes) pass-by-value argument}} -void f101_no_param_name(S101) {} // expected-warning-re {{'(unnamed variable at {{.*}}:19:29 of type rdar8548050::S101)' is a large (101 bytes) pass-by-value argument}} +void f101_no_param_name(S101) {} // expected-warning-re {{'(unnamed parameter at {{.*}}:19:29 of type rdar8548050::S101)' is a large (101 bytes) pass-by-value argument}} // FIXME: Don't warn when when the return value is subject to (N)RVO. template T foo_template(T); template <> S101 foo_template(S101) { return S101(); } // expected-warning {{return value of 'foo_template' is a large}} - // expected-warning-re@-1 {{'(unnamed variable at {{.*}}:24:35 of type rdar8548050::S101)' is a large (101 bytes) pass-by-value argument}} + // expected-warning-re@-1 {{'(unnamed parameter at {{.*}}:24:35 of type rdar8548050::S101)' is a large (101 bytes) pass-by-value argument}} typedef int Arr[200]; void farr(Arr a) { } diff --git a/clang/test/Tooling/clang-diff-ast.cpp b/clang/test/Tooling/clang-diff-ast.cpp --- a/clang/test/Tooling/clang-diff-ast.cpp +++ b/clang/test/Tooling/clang-diff-ast.cpp @@ -56,7 +56,7 @@ int not_initialized; // CHECK: CXXConstructorDecl: :X(void (char, int){{( __attribute__\(\(thiscall\)\))?}})( // CHECK-NEXT: ParmVarDecl: s(char) - // CHECK-NEXT: ParmVarDecl: (unnamed variable at {{.*}}:64:16 of type int)(int) + // CHECK-NEXT: ParmVarDecl: (unnamed parameter at {{.*}}:64:16 of type int)(int) // CHECK-NEXT: CXXCtorInitializer: Base // CHECK-NEXT: CXXConstructExpr // CHECK-NEXT: CXXCtorInitializer: m diff --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp --- a/clang/unittests/AST/ASTTraverserTest.cpp +++ b/clang/unittests/AST/ASTTraverserTest.cpp @@ -825,7 +825,7 @@ | |-FieldDecl '' | |-FieldDecl '' | |-FieldDecl '' -| `-CXXDestructorDecl '~(unnamed class at input.cc:9:3)' +| `-CXXDestructorDecl '~(lambda at input.cc:9:3)' |-ImplicitCastExpr | `-DeclRefExpr 'a' |-DeclRefExpr 'b' diff --git a/clang/unittests/AST/NamedDeclPrinterTest.cpp b/clang/unittests/AST/NamedDeclPrinterTest.cpp --- a/clang/unittests/AST/NamedDeclPrinterTest.cpp +++ b/clang/unittests/AST/NamedDeclPrinterTest.cpp @@ -6,7 +6,8 @@ // //===----------------------------------------------------------------------===// // -// This file contains tests for NamedDecl::printQualifiedName(). +// This file contains tests for NamedDecl::printName() +// and NamedDecl::printQualifiedName(). // // These tests have a coding convention: // * declaration to be printed is named 'A' unless it should have some special @@ -93,11 +94,10 @@ return ::testing::AssertionSuccess(); } -::testing::AssertionResult -PrintedNamedDeclMatches(StringRef Code, const std::vector &Args, - bool SuppressUnwrittenScope, - const DeclarationMatcher &NodeMatch, - StringRef ExpectedPrinted, StringRef FileName) { +::testing::AssertionResult PrintedQualifiedNamedDeclMatches( + StringRef Code, const std::vector &Args, + bool SuppressUnwrittenScope, const DeclarationMatcher &NodeMatch, + StringRef ExpectedPrinted, StringRef FileName) { return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, FileName, [=](llvm::raw_ostream &Out, const NamedDecl *ND) { auto Policy = @@ -108,34 +108,43 @@ }); } +::testing::AssertionResult PrintedUnqualifiedNamedDeclMatches( + StringRef Code, const std::vector &Args, + const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted, + StringRef FileName) { + return PrintedDeclMatches( + Code, Args, NodeMatch, ExpectedPrinted, FileName, + [=](llvm::raw_ostream &Out, const NamedDecl *ND) { ND->printName(Out); }); +} + ::testing::AssertionResult -PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName, - StringRef ExpectedPrinted) { +PrintedQualifiedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName, + StringRef ExpectedPrinted) { std::vector Args(1, "-std=c++98"); - return PrintedNamedDeclMatches(Code, Args, - /*SuppressUnwrittenScope*/ false, - namedDecl(hasName(DeclName)).bind("id"), - ExpectedPrinted, "input.cc"); + return PrintedQualifiedNamedDeclMatches( + Code, Args, + /*SuppressUnwrittenScope*/ false, namedDecl(hasName(DeclName)).bind("id"), + ExpectedPrinted, "input.cc"); } ::testing::AssertionResult -PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName, - StringRef ExpectedPrinted) { +PrintedWrittenQualifiedNamedDeclCXX11Matches(StringRef Code, StringRef DeclName, + StringRef ExpectedPrinted) { std::vector Args(1, "-std=c++11"); - return PrintedNamedDeclMatches(Code, Args, - /*SuppressUnwrittenScope*/ true, - namedDecl(hasName(DeclName)).bind("id"), - ExpectedPrinted, "input.cc"); + return PrintedQualifiedNamedDeclMatches( + Code, Args, + /*SuppressUnwrittenScope*/ true, namedDecl(hasName(DeclName)).bind("id"), + ExpectedPrinted, "input.cc"); } -::testing::AssertionResult -PrintedWrittenPropertyDeclObjCMatches(StringRef Code, StringRef DeclName, - StringRef ExpectedPrinted) { +::testing::AssertionResult PrintedWrittenQualifiedPropertyDeclObjCMatches( + StringRef Code, StringRef DeclName, StringRef ExpectedPrinted) { std::vector Args{"-std=c++11", "-xobjective-c++"}; - return PrintedNamedDeclMatches(Code, Args, - /*SuppressUnwrittenScope*/ true, - objcPropertyDecl(hasName(DeclName)).bind("id"), - ExpectedPrinted, "input.m"); + return PrintedQualifiedNamedDeclMatches( + Code, Args, + /*SuppressUnwrittenScope*/ true, + objcPropertyDecl(hasName(DeclName)).bind("id"), ExpectedPrinted, + "input.m"); } ::testing::AssertionResult @@ -149,69 +158,60 @@ }); } +::testing::AssertionResult +PrintedUnqualifiedNamedDeclCXX20Matches(StringRef Code, + const DeclarationMatcher &NodeMatcher, + StringRef ExpectedPrinted) { + std::vector Args{"-std=c++20", "-fno-delayed-template-parsing"}; + return PrintedUnqualifiedNamedDeclMatches(Code, Args, NodeMatcher, + ExpectedPrinted, "input.cc"); +} + } // unnamed namespace TEST(NamedDeclPrinter, TestNamespace1) { - ASSERT_TRUE(PrintedNamedDeclCXX98Matches( - "namespace { int A; }", - "A", - "(anonymous namespace)::A")); + ASSERT_TRUE(PrintedQualifiedNamedDeclCXX98Matches( + "namespace { int A; }", "A", "(anonymous namespace)::A")); } TEST(NamedDeclPrinter, TestNamespace2) { - ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( - "inline namespace Z { namespace { int A; } }", - "A", - "A")); + ASSERT_TRUE(PrintedWrittenQualifiedNamedDeclCXX11Matches( + "inline namespace Z { namespace { int A; } }", "A", "A")); } TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) { - ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( - "enum { A };", - "A", - "A")); + ASSERT_TRUE( + PrintedWrittenQualifiedNamedDeclCXX11Matches("enum { A };", "A", "A")); } TEST(NamedDeclPrinter, TestNamedEnum) { - ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( - "enum X { A };", - "A", - "A")); + ASSERT_TRUE( + PrintedWrittenQualifiedNamedDeclCXX11Matches("enum X { A };", "A", "A")); } TEST(NamedDeclPrinter, TestScopedNamedEnum) { - ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( - "enum class X { A };", - "A", - "X::A")); + ASSERT_TRUE(PrintedWrittenQualifiedNamedDeclCXX11Matches( + "enum class X { A };", "A", "X::A")); } TEST(NamedDeclPrinter, TestClassWithUnscopedUnnamedEnum) { - ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( - "class X { enum { A }; };", - "A", - "X::A")); + ASSERT_TRUE(PrintedWrittenQualifiedNamedDeclCXX11Matches( + "class X { enum { A }; };", "A", "X::A")); } TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnum) { - ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( - "class X { enum Y { A }; };", - "A", - "X::A")); + ASSERT_TRUE(PrintedWrittenQualifiedNamedDeclCXX11Matches( + "class X { enum Y { A }; };", "A", "X::A")); } TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) { - ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( - "class X { enum class Y { A }; };", - "A", - "X::Y::A")); + ASSERT_TRUE(PrintedWrittenQualifiedNamedDeclCXX11Matches( + "class X { enum class Y { A }; };", "A", "X::Y::A")); } TEST(NamedDeclPrinter, TestLinkageInNamespace) { - ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( - "namespace X { extern \"C\" { int A; } }", - "A", - "X::A")); + ASSERT_TRUE(PrintedWrittenQualifiedNamedDeclCXX11Matches( + "namespace X { extern \"C\" { int A; } }", "A", "X::A")); } TEST(NamedDeclPrinter, TestObjCClassExtension) { @@ -224,10 +224,8 @@ @property(nonatomic) int property; @end )"; - ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches( - Code, - "property", - "Obj::property")); + ASSERT_TRUE(PrintedWrittenQualifiedPropertyDeclObjCMatches(Code, "property", + "Obj::property")); } TEST(NamedDeclPrinter, TestInstanceObjCClassExtension) { @@ -244,11 +242,11 @@ std::vector Args{ "-std=c++11", "-xobjective-c++", "-fobjc-runtime=macosx" /*force to use non-fragile ABI*/}; - ASSERT_TRUE(PrintedNamedDeclMatches(Code, Args, - /*SuppressUnwrittenScope*/ true, - namedDecl(hasName("data")).bind("id"), - // not "::data" - "ObjC::data", "input.mm")); + ASSERT_TRUE(PrintedQualifiedNamedDeclMatches( + Code, Args, + /*SuppressUnwrittenScope*/ true, namedDecl(hasName("data")).bind("id"), + // not "::data" + "ObjC::data", "input.mm")); } TEST(NamedDeclPrinter, TestObjCClassExtensionWithGetter) { @@ -261,10 +259,8 @@ @property(nonatomic, getter=myPropertyGetter) int property; @end )"; - ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches( - Code, - "property", - "Obj::property")); + ASSERT_TRUE(PrintedWrittenQualifiedPropertyDeclObjCMatches(Code, "property", + "Obj::property")); } TEST(NamedDeclPrinter, NestedNameSpecifierSimple) { @@ -284,3 +280,188 @@ ASSERT_TRUE( PrintedNestedNameSpecifierMatches(Code, "method", "vector::")); } + +TEST(NamedDeclPrinter, TestLambdaImplicitCapture1) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { int A; float X, Y; [=, &X, &Y] { return A; }; }", + fieldDecl(allOf(isImplicit(), + unless(hasType( + referenceType(pointee(realFloatingPointType())))), + hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "A")); +} + +TEST(NamedDeclPrinter, TestLambdaImplicitCapture2) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { int A; float X, Y; [&, X, Y] { return A; }; }", + fieldDecl(allOf(isImplicit(), unless(hasType(realFloatingPointType())), + hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "A")); +} + +TEST(NamedDeclPrinter, TestLambdaImplicitCapture3) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "struct X { int A; void Test() const; };" + "void X::Test() const { float X; [=] { return A + X; }; }", + fieldDecl(allOf(isImplicit(), unless(hasType(realFloatingPointType())), + hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "this")); +} + +TEST(NamedDeclPrinter, TestLambdaImplicitCapture4) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "struct X { int A; void Test() const; };" + "void X::Test() const { float X; [&] { return A + X; }; }", + fieldDecl(allOf(isImplicit(), + unless(hasType( + referenceType(pointee(realFloatingPointType())))), + hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "this")); +} + +TEST(NamedDeclPrinter, TestLambdaExplicitCapture1) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { int A; float X, Y; [X, A, Y] { return A; }; }", + fieldDecl(allOf(isImplicit(), unless(hasType(realFloatingPointType())), + hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "A")); +} + +TEST(NamedDeclPrinter, TestLambdaExplicitCapture2) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { int A; float X, Y; [X, &A, Y] { return A; }; }", + fieldDecl(allOf(isImplicit(), unless(hasType(realFloatingPointType())), + hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "A")); +} + +TEST(NamedDeclPrinter, TestLambdaExplicitCapture3) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "struct X { int A; void Test() const; };" + "void X::Test() const { float X, Y; [X, this, Y] { return A; }; }", + fieldDecl(allOf(isImplicit(), unless(hasType(realFloatingPointType())), + hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "this")); +} + +TEST(NamedDeclPrinter, TestLambdaExplicitCapture4) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "struct X { int A; void Test() const; };" + "void X::Test() const { float X, Y; [X, *this, Y] { return A; }; }", + fieldDecl(allOf(isImplicit(), unless(hasType(realFloatingPointType())), + hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "*this")); +} + +TEST(NamedDeclPrinter, TestLambdaInitCapture1) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { int X; [A=X] { return A; }; }", + fieldDecl(allOf(isImplicit(), hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "A")); +} + +TEST(NamedDeclPrinter, TestLambdaInitCapture2) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { int X; [&A=X] { return A; }; }", + fieldDecl(allOf(isImplicit(), hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "A")); +} + +TEST(NamedDeclPrinter, TestLambdaVLA) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test(int n) { int A[n]; [&A] { return A[0]; }; }", + fieldDecl(allOf(isImplicit(), hasType(references(variableArrayType())))) + .bind("id"), + "A")); +} + +TEST(NamedDeclPrinter, TestLambdaPack1) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "template void Test(Ts... ts) {" + "[ts...] { return (ts + ...); }; }", + fieldDecl(allOf(isImplicit(), hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "ts")); +} + +TEST(NamedDeclPrinter, TestLambdaPack2) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "template void Test(Ts... ts) {" + "[&ts...] { return (ts + ...); }; }", + fieldDecl(allOf(isImplicit(), hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "ts")); +} + +TEST(NamedDeclPrinter, TestLambdaPack3) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "template void Test(Ts... ts) {" + "[...vs=ts] { return (vs + ...); }; }", + fieldDecl(allOf(isImplicit(), hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "vs")); +} + +TEST(NamedDeclPrinter, TestLambdaPack4) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "template void Test(Ts... ts) {" + "[&...vs=ts] { return (vs + ...); }; }", + fieldDecl(allOf(isImplicit(), hasParent(cxxRecordDecl(isLambda())))) + .bind("id"), + "vs")); +} + +TEST(NamedDeclPrinter, TestUnnamedParameter1) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test(int, float);", + functionDecl( + allOf(hasName("Test"), hasParameter(1, varDecl().bind("id")))), + "(unnamed parameter at input.cc:1:21 of type float)")); +} + +TEST(NamedDeclPrinter, TestUnnamedParameter2) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "struct {} X;" + "void Test(decltype(X) &);", + functionDecl( + allOf(hasName("Test"), hasParameter(0, varDecl().bind("id")))), + "(unnamed parameter at input.cc:1:36 of type decltype(X) &)")); +} + +TEST(NamedDeclPrinter, TestAnonymousUnion) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { union { int X; }; }", + varDecl(hasType(recordType(hasDeclaration(tagDecl(isUnion()))))) + .bind("id"), + "(unnamed variable of type (anonymous union at input.cc:1:15))")); +} + +TEST(NamedDeclPrinter, TestUnnamedStruct) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { struct { int X; } Y; }", + cxxRecordDecl(has(fieldDecl(hasName("X")))).bind("id"), + "(unnamed struct at input.cc:1:15)")); +} + +TEST(NamedDeclPrinter, TestLambdaClass) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "void Test() { [] {}; }", cxxRecordDecl(isLambda()).bind("id"), + "(lambda at input.cc:1:15)")); +} + +TEST(NamedDeclPrinter, TestUnnamedField) { + ASSERT_TRUE(PrintedUnqualifiedNamedDeclCXX20Matches( + "struct X { struct { int Y; }; };", + cxxRecordDecl(has(fieldDecl(hasType(recordType())).bind("id"))), + "(unnamed field of type X::(anonymous struct at input.cc:1:12))")); +}