diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 78a01fe8cdd..2470ffc66b9 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -8600,5 +8600,53 @@ public class AST2CPPTests extends AST2BaseTest { IFunction fA= bh.assertNonProblem("f(A)", 1); IFunction f= bh.assertNonProblem("f(a= 1)", 1); assertSame(fA, f); - } + } + + + + +// struct X {}; +// struct Y : X {}; +// struct A { +// virtual X* m();//0 +// virtual X* m(X*);//1 +// }; +// struct B : A { +// Y* m();//2 +// Y* m(Y*);//3 +// }; + public void testOverrideSimpleCovariance_Bug321617() throws Exception { + BindingAssertionHelper helper= new BindingAssertionHelper(getAboveComment(), true); + ICPPMethod m0= helper.assertNonProblem("m();//0", 1, ICPPMethod.class); + ICPPMethod m1= helper.assertNonProblem("m(X*);//1", 1, ICPPMethod.class); + ICPPMethod m2= helper.assertNonProblem("m();//2", 1, ICPPMethod.class); + ICPPMethod m3= helper.assertNonProblem("m(Y*);//3", 1, ICPPMethod.class); + + assertTrue(ClassTypeHelper.isVirtual(m0)); + assertTrue(ClassTypeHelper.isVirtual(m1)); + assertTrue(ClassTypeHelper.isVirtual(m2)); + assertFalse(ClassTypeHelper.isVirtual(m3)); + + assertFalse(ClassTypeHelper.isOverrider(m0, m0)); + assertFalse(ClassTypeHelper.isOverrider(m0, m1)); + + assertFalse(ClassTypeHelper.isOverrider(m1, m0)); + assertFalse(ClassTypeHelper.isOverrider(m1, m1)); + + assertTrue(ClassTypeHelper.isOverrider(m2, m0)); + assertFalse(ClassTypeHelper.isOverrider(m2, m1)); + + assertFalse(ClassTypeHelper.isOverrider(m3, m0)); + assertFalse(ClassTypeHelper.isOverrider(m3, m1)); + + ICPPMethod[] ors= ClassTypeHelper.findOverridden(m0); + assertEquals(0, ors.length); + ors= ClassTypeHelper.findOverridden(m1); + assertEquals(0, ors.length); + ors= ClassTypeHelper.findOverridden(m2); + assertEquals(1, ors.length); + assertSame(ors[0], m0); + ors= ClassTypeHelper.findOverridden(m3); + assertEquals(0, ors.length); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java index 5c034c7f3b7..07dc5eda2a6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java @@ -38,6 +38,7 @@ import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; @@ -49,11 +50,11 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -444,10 +445,10 @@ public class ClassTypeHelper { final char[] mname= m.getNameCharArray(); final ICPPClassType mcl= m.getClassOwner(); if (mcl != null) { - final IFunctionType mft= m.getType(); + final ICPPFunctionType mft= m.getType(); ICPPMethod[] allMethods= mcl.getMethods(); for (ICPPMethod method : allMethods) { - if (CharArrayUtils.equals(mname, method.getNameCharArray()) && mft.isSameType(method.getType())) { + if (CharArrayUtils.equals(mname, method.getNameCharArray()) && functionTypesAllowOverride(mft, method.getType())) { if (method.isVirtual()) { return true; } @@ -457,6 +458,34 @@ public class ClassTypeHelper { return false; } + /** + * Checks if the function types are consistent enough to be considered overrides. + */ + private static boolean functionTypesAllowOverride(ICPPFunctionType a, ICPPFunctionType b) { + if (a.isConst() != b.isConst() || a.isVolatile() != b.isVolatile() || a.takesVarArgs() != b.takesVarArgs()) { + return false; + } + + IType[] paramsA = a.getParameterTypes(); + IType[] paramsB = b.getParameterTypes(); + + if (paramsA.length == 1 && paramsB.length == 0) { + if (!SemanticUtil.isVoidType(paramsA[0])) + return false; + } else if (paramsB.length == 1 && paramsA.length == 0) { + if (!SemanticUtil.isVoidType(paramsB[0])) + return false; + } else if (paramsA.length != paramsB.length) { + return false; + } else { + for (int i = 0; i < paramsA.length; i++) { + if (paramsA[i] == null || ! paramsA[i].isSameType(paramsB[i])) + return false; + } + } + return true; + } + /** * Returns {@code true} if {@code source} overrides {@code target}. * @throws DOMException @@ -466,9 +495,9 @@ public class ClassTypeHelper { return false; if (!isVirtual(target)) return false; - if (!source.getType().isSameType(target.getType())) + if (!functionTypesAllowOverride(source.getType(), target.getType())) return false; - + final ICPPClassType sourceClass= source.getClassOwner(); final ICPPClassType targetClass= target.getClassOwner(); if (sourceClass == null || targetClass == null) @@ -498,7 +527,7 @@ public class ClassTypeHelper { final ArrayList result= new ArrayList(); final HashMap virtualInClass= new HashMap(); - final IFunctionType mft= method.getType(); + final ICPPFunctionType mft= method.getType(); virtualInClass.put(mcl, method.isVirtual()); ICPPBase[] bases= mcl.getBases(); @@ -520,7 +549,7 @@ public class ClassTypeHelper { * method. * Returns whether {@code cl} contains an overridden method. */ - private static boolean findOverridden(ICPPClassType cl, char[] mname, IFunctionType mft, + private static boolean findOverridden(ICPPClassType cl, char[] mname, ICPPFunctionType mft, HashMap virtualInClass, ArrayList result) throws DOMException { Boolean visitedBefore= virtualInClass.get(cl); if (visitedBefore != null) @@ -530,7 +559,7 @@ public class ClassTypeHelper { ICPPMethod candidate= null; boolean hasOverridden= false; for (ICPPMethod method : methods) { - if (CharArrayUtils.equals(mname, method.getNameCharArray()) && mft.isSameType(method.getType())) { + if (CharArrayUtils.equals(mname, method.getNameCharArray()) && functionTypesAllowOverride(mft,method.getType())) { candidate= method; hasOverridden= method.isVirtual(); break; @@ -572,13 +601,13 @@ public class ClassTypeHelper { final ArrayList result= new ArrayList(); final char[] mname= method.getNameCharArray(); - final IFunctionType mft= method.getType(); + final ICPPFunctionType mft= method.getType(); ICPPClassType[] subclasses= getSubClasses(index, mcl); for (ICPPClassType subClass : subclasses) { ICPPMethod[] methods= subClass.getDeclaredMethods(); for (ICPPMethod candidate : methods) { if (CharArrayUtils.equals(mname, candidate.getNameCharArray()) && - mft.isSameType(candidate.getType())) { + functionTypesAllowOverride(mft, candidate.getType())) { result.add(candidate); } }