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

Reply via email to