1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Bug 508338 - Friend class declaration hides the real one in outer

namespace

Change-Id: I3808c74b5b64505b07b8bb1e1a482d7a4c292dfe
This commit is contained in:
Sergey Prigogin 2016-11-28 21:03:09 -08:00
parent 2236ada9fd
commit 83bd6f7ed4
5 changed files with 100 additions and 6 deletions

View file

@ -2320,4 +2320,14 @@ public abstract class IndexCPPBindingResolutionTest extends IndexBindingResoluti
ICPPMethod[] pureVirtuals = SemanticQueries.getPureVirtualMethods((ICPPClassType) type, null); ICPPMethod[] pureVirtuals = SemanticQueries.getPureVirtualMethods((ICPPClassType) type, null);
assertEquals(0, pureVirtuals.length); assertEquals(0, pureVirtuals.length);
} }
// class A {
// friend class B;
// };
// B* b;
public void testFriendClassDeclaration_508338() throws Exception {
getProblemFromFirstIdentifier("B*");
}
} }

View file

@ -163,4 +163,40 @@ public class IndexMultiFileTest extends IndexBindingResolutionTestBase {
public void testExplicitSpecialization_494359() throws Exception { public void testExplicitSpecialization_494359() throws Exception {
checkBindings(); 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();
}
} }

View file

@ -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.c.ICInternalFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; 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.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.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IndexFileSet; import org.eclipse.cdt.internal.core.index.IndexFileSet;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
@ -263,4 +264,15 @@ public class ASTInternal {
} }
return binding != null; 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;
}
} }

View file

@ -463,10 +463,11 @@ public class CPPVisitor extends ASTQueries {
name = name.getLastName(); name = name.getLastName();
} }
if (parent instanceof IASTSimpleDeclaration) { if (parent instanceof IASTSimpleDeclaration) {
IASTDeclarator[] dtors = ((IASTSimpleDeclaration) parent).getDeclarators(); IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) parent;
ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration) parent).getDeclSpecifier(); ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier();
IASTDeclarator[] dtors = simpleDeclaration.getDeclarators();
isFriend = declSpec.isFriend() && dtors.length == 0; isFriend = declSpec.isFriend() && dtors.length == 0;
if (dtors.length > 0 || isFriend) { if (dtors.length != 0 || isFriend) {
binding = CPPSemantics.resolveBinding(name); binding = CPPSemantics.resolveBinding(name);
mustBeSimple = !isFriend; mustBeSimple = !isFriend;
} else { } else {
@ -558,6 +559,29 @@ public class CPPVisitor extends ASTQueries {
return binding; 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) { public static void markRedeclaration(final ICPPInternalBinding ib) {
// Mark the other declarations as problem and create the binding // Mark the other declarations as problem and create the binding
final IASTNode[] decls = ib.getDeclarations(); final IASTNode[] decls = ib.getDeclarations();

View file

@ -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.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance; 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.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.ICPPInternalEnumerator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; 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) { } 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) { } else if (binding instanceof ICPPVariableTemplate) {
pdomBinding = new PDOMCPPVariableTemplate(this, parent, (ICPPVariableTemplate) binding); pdomBinding = new PDOMCPPVariableTemplate(this, parent, (ICPPVariableTemplate) binding);
} else if (binding instanceof ICPPVariable) { } else if (binding instanceof ICPPVariable) {