Bug 508338 - Friend class declaration hides the real one in outer
namespace
Change-Id: I3808c74b5b64505b07b8bb1e1a482d7a4c292dfe
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java
index 8cb6708..28c7b0a 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java
@@ -2320,4 +2320,14 @@
ICPPMethod[] pureVirtuals = SemanticQueries.getPureVirtualMethods((ICPPClassType) type, null);
assertEquals(0, pureVirtuals.length);
}
+
+
+ // class A {
+ // friend class B;
+ // };
+
+ // B* b;
+ public void testFriendClassDeclaration_508338() throws Exception {
+ getProblemFromFirstIdentifier("B*");
+ }
}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexMultiFileTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexMultiFileTest.java
index 4824a65..f224ed0 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexMultiFileTest.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexMultiFileTest.java
@@ -163,4 +163,40 @@
public void testExplicitSpecialization_494359() throws Exception {
checkBindings();
}
+
+ // test1.h
+ // namespace ns {
+ //
+ // struct C {
+ // friend class B;
+ // };
+ //
+ // }
+
+ // test2.h
+ // class B {};
+ //
+ // namespace ns {
+ //
+ // struct A {
+ // operator B();
+ // };
+ //
+ // }
+ //
+ // void waldo(B);
+
+ // confuser.cpp
+ // #include "test1.h"
+
+ // test.cpp *
+ // #include "test1.h"
+ // #include "test2.h"
+ //
+ // void test(ns::A a) {
+ // waldo(a);
+ // }
+ public void testFriendClassDeclaration_508338() throws Exception {
+ checkBindings();
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTInternal.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTInternal.java
index 29845b5..29a712d 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTInternal.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTInternal.java
@@ -28,6 +28,7 @@
import org.eclipse.cdt.internal.core.dom.parser.c.ICInternalFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalFunction;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IndexFileSet;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
@@ -263,4 +264,15 @@
}
return binding != null;
}
+
+ public static boolean hasNonFriendDeclaration(ICPPInternalBinding binding) {
+ if (binding.getDefinition() != null)
+ return true;
+ for (IASTNode node : binding.getDeclarations()) {
+ if (!CPPVisitor.isNameOfFriendDeclaration(node))
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
index 71d6ae1..677e625 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
@@ -463,10 +463,11 @@
name = name.getLastName();
}
if (parent instanceof IASTSimpleDeclaration) {
- IASTDeclarator[] dtors = ((IASTSimpleDeclaration) parent).getDeclarators();
- ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration) parent).getDeclSpecifier();
+ IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) parent;
+ ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier();
+ IASTDeclarator[] dtors = simpleDeclaration.getDeclarators();
isFriend = declSpec.isFriend() && dtors.length == 0;
- if (dtors.length > 0 || isFriend) {
+ if (dtors.length != 0 || isFriend) {
binding = CPPSemantics.resolveBinding(name);
mustBeSimple = !isFriend;
} else {
@@ -558,6 +559,29 @@
return binding;
}
+ /**
+ * Checks if the given name is the name of a friend declaration.
+ *
+ * @param name the name to check
+ * @return {@code true} if {@code name} is the name of a friend declaration
+ */
+ public static boolean isNameOfFriendDeclaration(IASTNode name) {
+ if (name.getPropertyInParent() == ICPPASTQualifiedName.SEGMENT_NAME) {
+ ICPPASTQualifiedName qName = (ICPPASTQualifiedName) name.getParent();
+ if (name != qName.getLastName())
+ return false;
+ name = qName;
+ }
+ if (name.getPropertyInParent() != ICPPASTElaboratedTypeSpecifier.TYPE_NAME)
+ return false;
+ ICPPASTElaboratedTypeSpecifier typeSpec = (ICPPASTElaboratedTypeSpecifier) name.getParent();
+ if (typeSpec.getPropertyInParent() != IASTSimpleDeclaration.DECL_SPECIFIER)
+ return false;
+ IASTSimpleDeclaration declaration = (IASTSimpleDeclaration) typeSpec.getParent();
+ ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) declaration.getDeclSpecifier();
+ return declSpec.isFriend() && declaration.getDeclarators().length == 0;
+ }
+
public static void markRedeclaration(final ICPPInternalBinding ib) {
// Mark the other declarations as problem and create the binding
final IASTNode[] decls = ib.getDeclarations();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
index 6b0231e..c3d5069 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
@@ -109,6 +109,7 @@
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalEnumerator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
@@ -699,10 +700,21 @@
}
}
}
- } else if (binding instanceof ICPPClassTemplate) {
- pdomBinding= new PDOMCPPClassTemplate(this, parent, (ICPPClassTemplate) binding);
} else if (binding instanceof ICPPClassType) {
- pdomBinding= new PDOMCPPClassType(this, parent, (ICPPClassType) binding);
+ // 11.3-11 [class.friend]
+ // For a friend class declaration, if there is no prior declaration, the class that is specified
+ // belongs to the innermost enclosing non-class scope, but if it is subsequently referenced, its
+ // name is not found by name lookup until a matching declaration is provided in the innermost
+ // enclosing nonclass scope.
+ // See http://bugs.eclipse.org/508338
+ if (!(binding instanceof ICPPInternalBinding)
+ || ASTInternal.hasNonFriendDeclaration((ICPPInternalBinding) binding)) {
+ if (binding instanceof ICPPClassTemplate) {
+ pdomBinding= new PDOMCPPClassTemplate(this, parent, (ICPPClassTemplate) binding);
+ } else {
+ pdomBinding= new PDOMCPPClassType(this, parent, (ICPPClassType) binding);
+ }
+ }
} else if (binding instanceof ICPPVariableTemplate) {
pdomBinding = new PDOMCPPVariableTemplate(this, parent, (ICPPVariableTemplate) binding);
} else if (binding instanceof ICPPVariable) {