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:
parent
791ff12fae
commit
02fee4a8d3
2 changed files with 88 additions and 11 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue