mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-24 01:15:29 +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 fA= bh.assertNonProblem("f(A)", 1);
|
||||||
IFunction f= bh.assertNonProblem("f(a= 1)", 1);
|
IFunction f= bh.assertNonProblem("f(a= 1)", 1);
|
||||||
assertSame(fA, f);
|
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.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.ITypedef;
|
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;
|
||||||
|
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.ICPPASTDeclSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
|
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.ICPPConstructor;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
|
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.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.ICPPMember;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
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.ICPPReferenceType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
|
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.IIndex;
|
||||||
import org.eclipse.cdt.core.index.IIndexName;
|
import org.eclipse.cdt.core.index.IIndexName;
|
||||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||||
|
@ -444,10 +445,10 @@ public class ClassTypeHelper {
|
||||||
final char[] mname= m.getNameCharArray();
|
final char[] mname= m.getNameCharArray();
|
||||||
final ICPPClassType mcl= m.getClassOwner();
|
final ICPPClassType mcl= m.getClassOwner();
|
||||||
if (mcl != null) {
|
if (mcl != null) {
|
||||||
final IFunctionType mft= m.getType();
|
final ICPPFunctionType mft= m.getType();
|
||||||
ICPPMethod[] allMethods= mcl.getMethods();
|
ICPPMethod[] allMethods= mcl.getMethods();
|
||||||
for (ICPPMethod method : allMethods) {
|
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()) {
|
if (method.isVirtual()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -457,6 +458,34 @@ public class ClassTypeHelper {
|
||||||
return false;
|
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}.
|
* Returns {@code true} if {@code source} overrides {@code target}.
|
||||||
* @throws DOMException
|
* @throws DOMException
|
||||||
|
@ -466,9 +495,9 @@ public class ClassTypeHelper {
|
||||||
return false;
|
return false;
|
||||||
if (!isVirtual(target))
|
if (!isVirtual(target))
|
||||||
return false;
|
return false;
|
||||||
if (!source.getType().isSameType(target.getType()))
|
if (!functionTypesAllowOverride(source.getType(), target.getType()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
final ICPPClassType sourceClass= source.getClassOwner();
|
final ICPPClassType sourceClass= source.getClassOwner();
|
||||||
final ICPPClassType targetClass= target.getClassOwner();
|
final ICPPClassType targetClass= target.getClassOwner();
|
||||||
if (sourceClass == null || targetClass == null)
|
if (sourceClass == null || targetClass == null)
|
||||||
|
@ -498,7 +527,7 @@ public class ClassTypeHelper {
|
||||||
|
|
||||||
final ArrayList<ICPPMethod> result= new ArrayList<ICPPMethod>();
|
final ArrayList<ICPPMethod> result= new ArrayList<ICPPMethod>();
|
||||||
final HashMap<ICPPClassType, Boolean> virtualInClass= new HashMap<ICPPClassType, Boolean>();
|
final HashMap<ICPPClassType, Boolean> virtualInClass= new HashMap<ICPPClassType, Boolean>();
|
||||||
final IFunctionType mft= method.getType();
|
final ICPPFunctionType mft= method.getType();
|
||||||
|
|
||||||
virtualInClass.put(mcl, method.isVirtual());
|
virtualInClass.put(mcl, method.isVirtual());
|
||||||
ICPPBase[] bases= mcl.getBases();
|
ICPPBase[] bases= mcl.getBases();
|
||||||
|
@ -520,7 +549,7 @@ public class ClassTypeHelper {
|
||||||
* method.
|
* method.
|
||||||
* Returns whether {@code cl} contains an overridden 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 {
|
HashMap<ICPPClassType, Boolean> virtualInClass, ArrayList<ICPPMethod> result) throws DOMException {
|
||||||
Boolean visitedBefore= virtualInClass.get(cl);
|
Boolean visitedBefore= virtualInClass.get(cl);
|
||||||
if (visitedBefore != null)
|
if (visitedBefore != null)
|
||||||
|
@ -530,7 +559,7 @@ public class ClassTypeHelper {
|
||||||
ICPPMethod candidate= null;
|
ICPPMethod candidate= null;
|
||||||
boolean hasOverridden= false;
|
boolean hasOverridden= false;
|
||||||
for (ICPPMethod method : methods) {
|
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;
|
candidate= method;
|
||||||
hasOverridden= method.isVirtual();
|
hasOverridden= method.isVirtual();
|
||||||
break;
|
break;
|
||||||
|
@ -572,13 +601,13 @@ public class ClassTypeHelper {
|
||||||
|
|
||||||
final ArrayList<ICPPMethod> result= new ArrayList<ICPPMethod>();
|
final ArrayList<ICPPMethod> result= new ArrayList<ICPPMethod>();
|
||||||
final char[] mname= method.getNameCharArray();
|
final char[] mname= method.getNameCharArray();
|
||||||
final IFunctionType mft= method.getType();
|
final ICPPFunctionType mft= method.getType();
|
||||||
ICPPClassType[] subclasses= getSubClasses(index, mcl);
|
ICPPClassType[] subclasses= getSubClasses(index, mcl);
|
||||||
for (ICPPClassType subClass : subclasses) {
|
for (ICPPClassType subClass : subclasses) {
|
||||||
ICPPMethod[] methods= subClass.getDeclaredMethods();
|
ICPPMethod[] methods= subClass.getDeclaredMethods();
|
||||||
for (ICPPMethod candidate : methods) {
|
for (ICPPMethod candidate : methods) {
|
||||||
if (CharArrayUtils.equals(mname, candidate.getNameCharArray()) &&
|
if (CharArrayUtils.equals(mname, candidate.getNameCharArray()) &&
|
||||||
mft.isSameType(candidate.getType())) {
|
functionTypesAllowOverride(mft, candidate.getType())) {
|
||||||
result.add(candidate);
|
result.add(candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue