diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h index 97741c1c37f6..12b93b408a70 100644 --- a/clang/include/clang/AST/DeclFriend.h +++ b/clang/include/clang/AST/DeclFriend.h @@ -135,8 +135,12 @@ public: /// Retrieves the source range for the friend declaration. SourceRange getSourceRange() const override LLVM_READONLY { if (NamedDecl *ND = getFriendDecl()) { + if (FunctionDecl *FD = dyn_cast(ND)) + return FD->getSourceRange(); if (FunctionTemplateDecl *FTD = dyn_cast(ND)) return FTD->getSourceRange(); + if (ClassTemplateDecl *CTD = dyn_cast(ND)) + return CTD->getSourceRange(); if (DeclaratorDecl *DD = dyn_cast(ND)) { if (DD->getOuterLocStart() != DD->getInnerLocStart()) return DD->getSourceRange(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 88bcab88016b..8ff4ec02b166 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5254,6 +5254,7 @@ public: TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList **OuterTemplateParamLists); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 042fe2645262..a7018cd78263 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10817,6 +10817,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SS, Name, NameLoc, Attr, TemplateParams, AS, ModulePrivateLoc, + /*FriendLoc*/SourceLocation(), TemplateParameterLists.size()-1, TemplateParameterLists.data()); return Result.get(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 99eedf34872f..281241ba7535 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11626,11 +11626,10 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (Invalid) return nullptr; - return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, - SS, Name, NameLoc, Attr, - TemplateParams, AS_public, + return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name, + NameLoc, Attr, TemplateParams, AS_public, /*ModulePrivateLoc=*/SourceLocation(), - TempParamLists.size() - 1, + FriendLoc, TempParamLists.size() - 1, TempParamLists.data()).get(); } else { // The "template<>" header is extraneous. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5a188453b4fe..509103e2b5d5 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -838,6 +838,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, AttributeList *Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList** OuterTemplateParamLists) { assert(TemplateParams && TemplateParams->size() > 0 && @@ -1123,10 +1124,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, /* AddToContext = */ false); } - FriendDecl *Friend = FriendDecl::Create(Context, CurContext, - NewClass->getLocation(), - NewTemplate, - /*FIXME:*/NewClass->getLocation()); + FriendDecl *Friend = FriendDecl::Create( + Context, CurContext, NewClass->getLocation(), NewTemplate, FriendLoc); Friend->setAccess(AS_public); CurContext->addDecl(Friend); } @@ -6123,6 +6122,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Attr, TemplateParams, AS_none, /*ModulePrivateLoc=*/SourceLocation(), + /*FriendLoc*/SourceLocation(), TemplateParameterLists.size() - 1, TemplateParameterLists.data()); } diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp index dc00b86fc2c4..82bba64334b9 100644 --- a/clang/unittests/AST/SourceLocationTest.cpp +++ b/clang/unittests/AST/SourceLocationTest.cpp @@ -263,7 +263,7 @@ TEST(UnresolvedUsingValueDecl, SourceRange) { unresolvedUsingValueDecl())); } -TEST(FriendDecl, FriendFunctionLocation) { +TEST(FriendDecl, FriendNonMemberFunctionLocation) { LocationVerifier Verifier; Verifier.expectLocation(2, 13); EXPECT_TRUE(Verifier.match("struct A {\n" @@ -272,7 +272,7 @@ TEST(FriendDecl, FriendFunctionLocation) { friendDecl())); } -TEST(FriendDecl, FriendFunctionRange) { +TEST(FriendDecl, FriendNonMemberFunctionRange) { RangeVerifier Verifier; Verifier.expectRange(2, 1, 2, 15); EXPECT_TRUE(Verifier.match("struct A {\n" @@ -281,7 +281,25 @@ TEST(FriendDecl, FriendFunctionRange) { friendDecl())); } -TEST(FriendDecl, FriendClassLocation) { +TEST(FriendDecl, FriendNonMemberFunctionDefinitionLocation) { + LocationVerifier Verifier; + Verifier.expectLocation(2, 12); + EXPECT_TRUE(Verifier.match("struct A {\n" + "friend int f() { return 0; }\n" + "};\n", + friendDecl())); +} + +TEST(FriendDecl, FriendNonMemberFunctionDefinitionRange) { + RangeVerifier Verifier; + Verifier.expectRange(2, 1, 2, 28); + EXPECT_TRUE(Verifier.match("struct A {\n" + "friend int f() { return 0; }\n" + "};\n", + friendDecl())); +} + +TEST(FriendDecl, FriendElaboratedTypeLocation) { LocationVerifier Verifier; Verifier.expectLocation(2, 8); EXPECT_TRUE(Verifier.match("struct A {\n" @@ -290,7 +308,7 @@ TEST(FriendDecl, FriendClassLocation) { friendDecl())); } -TEST(FriendDecl, FriendClassRange) { +TEST(FriendDecl, FriendElaboratedTypeRange) { RangeVerifier Verifier; Verifier.expectRange(2, 1, 2, 14); EXPECT_TRUE(Verifier.match("struct A {\n" @@ -299,6 +317,26 @@ TEST(FriendDecl, FriendClassRange) { friendDecl())); } +TEST(FriendDecl, FriendSimpleTypeLocation) { + LocationVerifier Verifier; + Verifier.expectLocation(3, 8); + EXPECT_TRUE(Verifier.match("class B;\n" + "struct A {\n" + "friend B;\n" + "};\n", + friendDecl(), Lang_CXX11)); +} + +TEST(FriendDecl, FriendSimpleTypeRange) { + RangeVerifier Verifier; + Verifier.expectRange(3, 1, 3, 8); + EXPECT_TRUE(Verifier.match("class B;\n" + "struct A {\n" + "friend B;\n" + "};\n", + friendDecl(), Lang_CXX11)); +} + TEST(FriendDecl, FriendTemplateParameterLocation) { LocationVerifier Verifier; Verifier.expectLocation(3, 8); @@ -341,6 +379,100 @@ TEST(FriendDecl, FriendDecltypeRange) { friendDecl(), Lang_CXX11)); } +TEST(FriendDecl, FriendConstructorDestructorLocation) { + const std::string Code = "struct B {\n" + "B();\n" + "~B();\n" + "};\n" + "struct A {\n" + "friend B::B(), B::~B();\n" + "};\n"; + LocationVerifier ConstructorVerifier; + ConstructorVerifier.expectLocation(6, 11); + EXPECT_TRUE(ConstructorVerifier.match( + Code, friendDecl(has(constructorDecl(ofClass(hasName("B"))))))); + LocationVerifier DestructorVerifier; + DestructorVerifier.expectLocation(6, 19); + EXPECT_TRUE(DestructorVerifier.match( + Code, friendDecl(has(destructorDecl(ofClass(hasName("B"))))))); +} + +TEST(FriendDecl, FriendConstructorDestructorRange) { + const std::string Code = "struct B {\n" + "B();\n" + "~B();\n" + "};\n" + "struct A {\n" + "friend B::B(), B::~B();\n" + "};\n"; + RangeVerifier ConstructorVerifier; + ConstructorVerifier.expectRange(6, 1, 6, 13); + EXPECT_TRUE(ConstructorVerifier.match( + Code, friendDecl(has(constructorDecl(ofClass(hasName("B"))))))); + RangeVerifier DestructorVerifier; + DestructorVerifier.expectRange(6, 1, 6, 22); + EXPECT_TRUE(DestructorVerifier.match( + Code, friendDecl(has(destructorDecl(ofClass(hasName("B"))))))); +} + +TEST(FriendDecl, FriendTemplateFunctionLocation) { + LocationVerifier Verifier; + Verifier.expectLocation(3, 13); + EXPECT_TRUE(Verifier.match("struct A {\n" + "template \n" + "friend void f();\n" + "};\n", + friendDecl())); +} + +TEST(FriendDecl, FriendTemplateFunctionRange) { + RangeVerifier Verifier; + Verifier.expectRange(2, 1, 3, 15); + EXPECT_TRUE(Verifier.match("struct A {\n" + "template \n" + "friend void f();\n" + "};\n", + friendDecl())); +} + +TEST(FriendDecl, FriendTemplateClassLocation) { + LocationVerifier Verifier; + Verifier.expectLocation(3, 14); + EXPECT_TRUE(Verifier.match("struct A {\n" + "template \n" + "friend class B;\n" + "};\n", + friendDecl())); +} + +TEST(FriendDecl, FriendTemplateClassRange) { + RangeVerifier Verifier; + Verifier.expectRange(2, 1, 3, 14); + EXPECT_TRUE(Verifier.match("struct A {\n" + "template \n" + "friend class B;\n" + "};\n", + friendDecl())); +} + +TEST(FriendDecl, FriendInlineFunctionLocation) { + LocationVerifier Verifier; + Verifier.expectLocation(2, 19); + EXPECT_TRUE(Verifier.match("struct A {\n" + "int inline friend f() { return 0; }" + "};\n", + friendDecl())); +} + +TEST(FriendDecl, FriendInlineFunctionRange) { + RangeVerifier Verifier; + Verifier.expectRange(2, 1, 2, 35); + EXPECT_TRUE(Verifier.match("struct A {\n" + "int inline friend f() { return 0; }" + "};\n", + friendDecl(), Lang_CXX11)); +} + TEST(FriendDecl, InstantiationSourceRange) { RangeVerifier Verifier; Verifier.expectRange(4, 3, 4, 35);