Index: include/clang/AST/DeclFriend.h =================================================================== --- include/clang/AST/DeclFriend.h +++ include/clang/AST/DeclFriend.h @@ -135,8 +135,12 @@ /// 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(); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5246,6 +5246,7 @@ TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList **OuterTemplateParamLists); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10699,6 +10699,7 @@ SS, Name, NameLoc, Attr, TemplateParams, AS, ModulePrivateLoc, + /*FriendLoc*/SourceLocation(), TemplateParameterLists.size()-1, TemplateParameterLists.data()); return Result.get(); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -11607,11 +11607,10 @@ 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. Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -838,6 +838,7 @@ AttributeList *Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList** OuterTemplateParamLists) { assert(TemplateParams && TemplateParams->size() > 0 && @@ -1123,10 +1124,8 @@ /* 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 @@ Attr, TemplateParams, AS_none, /*ModulePrivateLoc=*/SourceLocation(), + /*FriendLoc*/SourceLocation(), TemplateParameterLists.size() - 1, TemplateParameterLists.data()); } Index: unittests/AST/SourceLocationTest.cpp =================================================================== --- unittests/AST/SourceLocationTest.cpp +++ unittests/AST/SourceLocationTest.cpp @@ -263,7 +263,7 @@ unresolvedUsingValueDecl())); } -TEST(FriendDecl, FriendFunctionLocation) { +TEST(FriendDecl, FriendNonMemberFunctionLocation) { LocationVerifier Verifier; Verifier.expectLocation(2, 13); EXPECT_TRUE(Verifier.match("struct A {\n" @@ -272,7 +272,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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);