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) {