balazske created this revision.
Herald added subscribers: cfe-commits, martong.
Herald added a reviewer: a.sidorin.

Repository:
  rC Clang

https://reviews.llvm.org/D49798

Files:
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===================================================================
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -2241,6 +2241,217 @@
   EXPECT_EQ(ImportedD1->getPreviousDecl(), ImportedD);
 }
 
+TEST_P(ImportFriendFunctions, Lookup) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU =
+      getTuDecl("struct X { friend void f(); };", Lang_CXX, "input0.cc");
+  auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  ASSERT_TRUE(FromD->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  ASSERT_TRUE(!FromD->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  auto FromName = FromD->getDeclName();
+  {
+    CXXRecordDecl *Class =
+        FirstDeclMatcher<CXXRecordDecl>().match(FromTU, cxxRecordDecl());
+    auto lookup_res = Class->noload_lookup(FromName);
+    ASSERT_EQ(lookup_res.size(), 0u);
+    lookup_res = cast<TranslationUnitDecl>(FromTU)->noload_lookup(FromName);
+    ASSERT_EQ(lookup_res.size(), 1u);
+  }
+
+  auto ToD = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  auto ToName = ToD->getDeclName();
+
+  {
+    Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+    CXXRecordDecl *Class =
+        FirstDeclMatcher<CXXRecordDecl>().match(ToTU, cxxRecordDecl());
+    auto lookup_res = Class->noload_lookup(ToName);
+    EXPECT_EQ(lookup_res.size(), 0u);
+    lookup_res = cast<TranslationUnitDecl>(ToTU)->noload_lookup(ToName);
+    EXPECT_EQ(lookup_res.size(), 1u);
+  }
+
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(To0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  EXPECT_TRUE(!To0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+}
+
+TEST_P(ImportFriendFunctions, DISABLED_LookupWithProto) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU =
+      getTuDecl("struct X { friend void f(); };"
+                // This proto decl makes f available to normal
+                // lookup, otherwise it is hidden.
+                // Normal C++ lookup (implemented in
+                // `clang::Sema::CppLookupName()` and in `LookupDirect()`)
+                // returns the found `NamedDecl` only if the set IDNS is matched
+                "void f();",
+                Lang_CXX, "input0.cc");
+  auto From0 = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  auto From1 = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  ASSERT_TRUE(From0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  ASSERT_TRUE(!From0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  ASSERT_TRUE(!From1->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  ASSERT_TRUE(From1->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  auto FromName = From0->getDeclName();
+  {
+    CXXRecordDecl *Class =
+        FirstDeclMatcher<CXXRecordDecl>().match(FromTU, cxxRecordDecl());
+    auto lookup_res = Class->noload_lookup(FromName);
+    ASSERT_EQ(lookup_res.size(), 0u);
+    lookup_res = cast<TranslationUnitDecl>(FromTU)->noload_lookup(FromName);
+    ASSERT_EQ(lookup_res.size(), 1u);
+  }
+
+  auto To0 = cast<FunctionDecl>(Import(From0, Lang_CXX));
+  auto ToName = To0->getDeclName();
+
+  {
+    auto ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+    CXXRecordDecl *Class =
+        FirstDeclMatcher<CXXRecordDecl>().match(ToTU, cxxRecordDecl());
+    auto lookup_res = Class->noload_lookup(ToName);
+    EXPECT_EQ(lookup_res.size(), 0u);
+    lookup_res = ToTU->noload_lookup(ToName);
+    EXPECT_EQ(lookup_res.size(), 1u);
+  }
+
+  auto ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(To0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  EXPECT_TRUE(!To0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  EXPECT_TRUE(!To1->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  EXPECT_TRUE(To1->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+}
+
+TEST_P(ImportFriendFunctions, LookupWithProtoFirst) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU =
+      getTuDecl("void f();"
+                "struct X { friend void f(); };",
+                Lang_CXX, "input0.cc");
+  auto From0 = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  auto From1 = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  ASSERT_TRUE(!From0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  ASSERT_TRUE(From0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  ASSERT_TRUE(From1->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  ASSERT_TRUE(From1->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  auto FromName = From0->getDeclName();
+  {
+    CXXRecordDecl *Class =
+        FirstDeclMatcher<CXXRecordDecl>().match(FromTU, cxxRecordDecl());
+    auto lookup_res = Class->noload_lookup(FromName);
+    ASSERT_EQ(lookup_res.size(), 0u);
+    lookup_res = cast<TranslationUnitDecl>(FromTU)->noload_lookup(FromName);
+    ASSERT_EQ(lookup_res.size(), 1u);
+  }
+
+  auto To0 = cast<FunctionDecl>(Import(From0, Lang_CXX));
+  auto ToName = To0->getDeclName();
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+  {
+    CXXRecordDecl *Class =
+        FirstDeclMatcher<CXXRecordDecl>().match(ToTU, cxxRecordDecl());
+    auto lookup_res = Class->noload_lookup(ToName);
+    EXPECT_EQ(lookup_res.size(), 0u);
+    lookup_res = cast<TranslationUnitDecl>(ToTU)->noload_lookup(ToName);
+    EXPECT_EQ(lookup_res.size(), 1u);
+  }
+
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(!To0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  EXPECT_TRUE(To0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  EXPECT_TRUE(To1->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  EXPECT_TRUE(To1->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+}
+
+TEST_P(ImportFriendFunctions, ImportFriendChangesLookup) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU0 = getTuDecl("void f();", Lang_CXX, "input0.cc");
+  FunctionDecl *FromD0 =
+      FirstDeclMatcher<FunctionDecl>().match(FromTU0, Pattern);
+  Decl *FromTU1 =
+      getTuDecl("class X { friend void f(); };", Lang_CXX, "input1.cc");
+  FunctionDecl *FromD1 =
+      FirstDeclMatcher<FunctionDecl>().match(FromTU1, Pattern);
+  auto FromName0 = FromD0->getDeclName();
+  auto FromName1 = FromD1->getDeclName();
+
+  ASSERT_TRUE(FromD0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  ASSERT_TRUE(!FromD0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  ASSERT_TRUE(!FromD1->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  ASSERT_TRUE(FromD1->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  auto lookup_res = cast<TranslationUnitDecl>(FromTU0)->noload_lookup(FromName0);
+  ASSERT_EQ(lookup_res.size(), 1u);
+  lookup_res = cast<TranslationUnitDecl>(FromTU1)->noload_lookup(FromName1);
+  ASSERT_EQ(lookup_res.size(), 1u);
+
+  FunctionDecl *ToD0 = cast<FunctionDecl>(Import(FromD0, Lang_CXX));
+  auto ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  auto ToName = ToD0->getDeclName();
+  EXPECT_TRUE(ToD0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  EXPECT_TRUE(!ToD0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  lookup_res = cast<TranslationUnitDecl>(ToTU)->noload_lookup(ToName);
+  EXPECT_EQ(lookup_res.size(), 1u);
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
+  
+  FunctionDecl *ToD1 = cast<FunctionDecl>(Import(FromD1, Lang_CXX));
+  lookup_res = cast<TranslationUnitDecl>(ToTU)->noload_lookup(ToName);
+  EXPECT_EQ(lookup_res.size(), 1u);
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+
+  EXPECT_TRUE(ToD0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  EXPECT_TRUE(!ToD0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+  
+  EXPECT_TRUE(ToD1->isInIdentifierNamespace(Decl::IDNS_Ordinary));
+  EXPECT_TRUE(ToD1->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
+}
+
+TEST_P(ImportFriendFunctions, ImportFriendList) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU = getTuDecl("struct X { friend void f(); };"
+                           "void f();",
+                           Lang_CXX,
+                           "input0.cc");
+  auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  {
+    auto *Class = FirstDeclMatcher<CXXRecordDecl>().match(
+        FromTU, cxxRecordDecl(hasName("X")));
+    auto *Friend = FirstDeclMatcher<FriendDecl>().match(FromTU, friendDecl());
+    auto Friends = Class->friends();
+    unsigned int FrN = 0;
+    for (auto Fr : Friends) {
+      ASSERT_EQ(Fr, Friend);
+      ++FrN;
+    }
+    ASSERT_EQ(FrN, 1u);
+  }
+  Import(FromD, Lang_CXX);
+  auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  auto *Class = FirstDeclMatcher<CXXRecordDecl>().match(
+      ToTU, cxxRecordDecl(hasName("X")));
+  auto *Friend = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
+  auto Friends = Class->friends();
+  unsigned int FrN = 0;
+  for (auto Fr : Friends) {
+    EXPECT_EQ(Fr, Friend);
+    ++FrN;
+  }
+  ASSERT_EQ(FrN, 1u);
+}
+
 AST_MATCHER_P(TagDecl, hasTypedefForAnonDecl, Matcher<TypedefNameDecl>,
               InnerMatcher) {
   if (auto *Typedef = Node.getTypedefNameForAnonDecl())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to