From 83bd6f7ed4b7af7d1880fcd93132d87571ab1e29 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Mon, 28 Nov 2016 21:03:09 -0800 Subject: [PATCH] Bug 508338 - Friend class declaration hides the real one in outer namespace Change-Id: I3808c74b5b64505b07b8bb1e1a482d7a4c292dfe --- .../tests/IndexCPPBindingResolutionTest.java | 10 ++++++ .../index/tests/IndexMultiFileTest.java | 36 +++++++++++++++++++ .../internal/core/dom/parser/ASTInternal.java | 12 +++++++ .../dom/parser/cpp/semantics/CPPVisitor.java | 30 ++++++++++++++-- .../core/pdom/dom/cpp/PDOMCPPLinkage.java | 18 ++++++++-- 5 files changed, 100 insertions(+), 6 deletions(-) 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 8cb670840c9..28c7b0ab55d 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 @@ public abstract class IndexCPPBindingResolutionTest extends IndexBindingResoluti 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 4824a655688..f224ed07a3c 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 class IndexMultiFileTest extends IndexBindingResolutionTestBase { 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 29845b5d6d5..29a712d8acf 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.ICInternalBinding; 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 @@ public class ASTInternal { } 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 71d6ae1fe60..677e62555f7 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 @@ public class CPPVisitor extends ASTQueries { 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 @@ public class CPPVisitor extends ASTQueries { 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 6b0231ebdb7..c3d50691479 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.CPPUnknownMember; 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 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { } } } - } 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) {