1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-01 06:05:24 +02:00

Bug 321617: Virtual overriders and covariant types.

This commit is contained in:
Markus Schorn 2010-08-04 14:07:15 +00:00
parent 791ff12fae
commit 02fee4a8d3
2 changed files with 88 additions and 11 deletions

View file

@ -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);
}
}

View file

@ -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<ICPPMethod> result= new ArrayList<ICPPMethod>();
final HashMap<ICPPClassType, Boolean> virtualInClass= new HashMap<ICPPClassType, Boolean>();
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<ICPPClassType, Boolean> virtualInClass, ArrayList<ICPPMethod> 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<ICPPMethod> result= new ArrayList<ICPPMethod>();
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);
}
}