Fix FriendDecl source location and range for class templates and function declarations that don't start with 'friend' keyword. Add more unittests.

llvm-svn: 213220
This commit is contained in:
Nikola Smiljanic 2014-07-17 01:59:34 +00:00
parent 354e23b029
commit 4fc91538e9
6 changed files with 149 additions and 12 deletions

View File

@ -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<FunctionDecl>(ND))
return FD->getSourceRange();
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();

View File

@ -5254,6 +5254,7 @@ public:
TemplateParameterList *TemplateParams,
AccessSpecifier AS,
SourceLocation ModulePrivateLoc,
SourceLocation FriendLoc,
unsigned NumOuterTemplateParamLists,
TemplateParameterList **OuterTemplateParamLists);

View File

@ -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();

View File

@ -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.

View File

@ -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());
}

View File

@ -263,7 +263,7 @@ TEST(UnresolvedUsingValueDecl, SourceRange) {
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 @@ TEST(FriendDecl, FriendFunctionLocation) {
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 @@ TEST(FriendDecl, FriendFunctionRange) {
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 @@ TEST(FriendDecl, FriendClassLocation) {
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 @@ TEST(FriendDecl, FriendClassRange) {
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 @@ 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<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);