Turns out we didn't have correct location and range for class template friend.
The same was true for case where friend is not the first token as in Richard's
inline example.
Manuel:
Are my constructor/destructor matchers good?
Richard:
1. What's the TypeSourceInfo case in FriendDecl::getSourceRange?
2. I couldn't find a way to hit the first call to FriendDecl::Create inside
Sema::ActOnTemplatedFriendTag (some kind of explicit specialization case). I
tried issuing a random diagnostic from there hoping it would break something in
the test suite but it seems we don't have any coverage for this?
http://reviews.llvm.org/D3906
Files:
include/clang/AST/DeclFriend.h
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplate.cpp
unittests/AST/SourceLocationTest.cpp
Index: include/clang/AST/DeclFriend.h
===================================================================
--- include/clang/AST/DeclFriend.h
+++ include/clang/AST/DeclFriend.h
@@ -137,11 +137,16 @@
if (NamedDecl *ND = getFriendDecl()) {
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
return FTD->getSourceRange();
+ if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND))
+ return CTD->getSourceRange();
if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(ND)) {
if (DD->getOuterLocStart() != DD->getInnerLocStart())
return DD->getSourceRange();
}
- return SourceRange(getFriendLoc(), ND->getLocEnd());
+ SourceLocation FriendLoc = getFriendLoc();
+ SourceLocation DeclLoc = ND->getLocStart();
+ return SourceRange(FriendLoc < DeclLoc ? FriendLoc : DeclLoc,
+ ND->getLocEnd());
}
else if (TypeSourceInfo *TInfo = getFriendType()) {
SourceLocation StartL = (NumTPLists == 0)
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5240,6 +5240,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
@@ -10654,6 +10654,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
@@ -11549,11 +11549,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);
}
@@ -6119,6 +6118,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<FriendDecl> Verifier;
Verifier.expectLocation(2, 13);
EXPECT_TRUE(Verifier.match("struct A {\n"
@@ -272,7 +272,7 @@
friendDecl()));
}
-TEST(FriendDecl, FriendFunctionRange) {
+TEST(FriendDecl, FriendNonMemberFunctionRange) {
RangeVerifier<FriendDecl> 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<FriendDecl> Verifier;
+ Verifier.expectLocation(2, 12);
+ EXPECT_TRUE(Verifier.match("struct A {\n"
+ "friend int f() { return 0; }\n"
+ "};\n",
+ friendDecl()));
+}
+
+TEST(FriendDecl, FriendNonMemberFunctionDefinitionRange) {
+ RangeVerifier<FriendDecl> 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<FriendDecl> Verifier;
Verifier.expectLocation(2, 8);
EXPECT_TRUE(Verifier.match("struct A {\n"
@@ -290,7 +308,7 @@
friendDecl()));
}
-TEST(FriendDecl, FriendClassRange) {
+TEST(FriendDecl, FriendElaboratedTypeRange) {
RangeVerifier<FriendDecl> Verifier;
Verifier.expectRange(2, 1, 2, 14);
EXPECT_TRUE(Verifier.match("struct A {\n"
@@ -299,6 +317,26 @@
friendDecl()));
}
+TEST(FriendDecl, FriendSimpleTypeLocation) {
+ LocationVerifier<FriendDecl> 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<FriendDecl> 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<FriendDecl> 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<FriendDecl> ConstructorVerifier;
+ ConstructorVerifier.expectLocation(6, 11);
+ EXPECT_TRUE(ConstructorVerifier.match(
+ Code, friendDecl(has(constructorDecl(ofClass(hasName("B")))))));
+ LocationVerifier<FriendDecl> 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<FriendDecl> ConstructorVerifier;
+ ConstructorVerifier.expectRange(6, 1, 6, 13);
+ EXPECT_TRUE(ConstructorVerifier.match(
+ Code, friendDecl(has(constructorDecl(ofClass(hasName("B")))))));
+ RangeVerifier<FriendDecl> DestructorVerifier;
+ DestructorVerifier.expectRange(6, 1, 6, 22);
+ EXPECT_TRUE(DestructorVerifier.match(
+ Code, friendDecl(has(destructorDecl(ofClass(hasName("B")))))));
+}
+
+TEST(FriendDecl, FriendTemplateFunctionLocation) {
+ LocationVerifier<FriendDecl> Verifier;
+ Verifier.expectLocation(3, 13);
+ EXPECT_TRUE(Verifier.match("struct A {\n"
+ "template <typename T>\n"
+ "friend void f();\n"
+ "};\n",
+ friendDecl()));
+}
+
+TEST(FriendDecl, FriendTemplateFunctionRange) {
+ RangeVerifier<FriendDecl> Verifier;
+ Verifier.expectRange(2, 1, 3, 15);
+ EXPECT_TRUE(Verifier.match("struct A {\n"
+ "template <typename T>\n"
+ "friend void f();\n"
+ "};\n",
+ friendDecl()));
+}
+
+TEST(FriendDecl, FriendTemplateClassLocation) {
+ LocationVerifier<FriendDecl> Verifier;
+ Verifier.expectLocation(3, 14);
+ EXPECT_TRUE(Verifier.match("struct A {\n"
+ "template <typename T>\n"
+ "friend class B;\n"
+ "};\n",
+ friendDecl()));
+}
+
+TEST(FriendDecl, FriendTemplateClassRange) {
+ RangeVerifier<FriendDecl> Verifier;
+ Verifier.expectRange(2, 1, 3, 14);
+ EXPECT_TRUE(Verifier.match("struct A {\n"
+ "template <typename T>\n"
+ "friend class B;\n"
+ "};\n",
+ friendDecl()));
+}
+
+TEST(FriendDecl, FriendInlineFunctionLocation) {
+ LocationVerifier<FriendDecl> Verifier;
+ Verifier.expectLocation(2, 19);
+ EXPECT_TRUE(Verifier.match("struct A {\n"
+ "int inline friend f() { return 0; }"
+ "};\n",
+ friendDecl()));
+}
+
+TEST(FriendDecl, FriendInlineFunctionRange) {
+ RangeVerifier<FriendDecl> 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<FriendDecl> Verifier;
Verifier.expectRange(4, 3, 4, 35);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits