1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 08:55:25 +02:00

Bug 86654 - During binding resolution, replace virtual methods with

their final overrider where appropriate

Change-Id: I5d6ef9ca5cf8dd4461255ef59ee3384f5060ee4e
Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
Nathan Ridge 2015-07-19 02:17:15 -04:00 committed by Gerrit Code Review @ Eclipse.org
parent cb7f0f3462
commit b82275a4c0
3 changed files with 95 additions and 2 deletions

View file

@ -9235,6 +9235,35 @@ public class AST2CPPTests extends AST2TestBase {
assertEquals(0, ors.length);
}
// struct A {
// virtual void f(); // A
// };
//
// struct B : virtual A {
// virtual void f(); // B
// };
//
// struct C : B , virtual A {
// using A::f;
// };
//
// void foo() {
// C c;
// c.f();
// c.C::f();
// }
public void testResolutionToFinalOverrider_86654() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ICPPMethod actual = helper.assertNonProblem("c.f()", "f");
ICPPMethod expected = helper.assertNonProblem("virtual void f(); // B", "f");
assertEquals(expected, actual);
actual = helper.assertNonProblem("c.C::f()", "f");
expected = helper.assertNonProblem("virtual void f(); // A", "f");
assertEquals(expected, actual);
}
// struct X {
// X();
// };

View file

@ -7,6 +7,7 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -89,10 +90,30 @@ public class CPPInheritance {
}
Map<Integer, List<ICPPMethod>> otherOverriders = other.fMap.get(method);
for (Integer i : otherOverriders.keySet()) {
CollectionUtils.listMapGet(overriders, i).addAll(otherOverriders.get(i));
mergeOverriders(CollectionUtils.listMapGet(overriders, i), otherOverriders.get(i));
}
}
}
/**
* Merges the overriders from 'source' into 'target'.
* Excludes methods in 'source' which themselves have an overrider in 'target'.
*/
private void mergeOverriders(List<ICPPMethod> target, List<ICPPMethod> source) {
List<ICPPMethod> toAdd = new ArrayList<>();
for (ICPPMethod candidate : source) {
boolean superseded = false;
for (ICPPMethod existing : target) {
if (existing != candidate && ClassTypeHelper.isOverrider(existing, candidate)) {
superseded = true;
}
}
if (!superseded) {
toAdd.add(candidate);
}
}
target.addAll(toAdd);
}
}
/**
@ -116,12 +137,34 @@ public class CPPInheritance {
if (result == null) {
result = FinalOverriderAnalysis.computeFinalOverriderMap(classType, point);
}
if (result != null && cache != null) {
if (cache != null) {
cache.put(classType, result);
}
return result;
}
/**
* If a given virtual method has a unique final overrider in the class hierarchy rooted at the
* given class, returns that final overrider. Otherwise, returns null.
* @param point The point of template instantiation, if applicable.
* Also used to access the final overrider map cache in the AST.
*/
public static ICPPMethod getFinalOverrider(ICPPMethod method, ICPPClassType hierarchyRoot,
IASTNode point) {
FinalOverriderMap map = getFinalOverriderMap(hierarchyRoot, point);
Map<Integer, List<ICPPMethod>> finalOverriders = map.getMap().get(method);
if (finalOverriders != null && finalOverriders.size() == 1) {
for (Integer subobjectNumber : finalOverriders.keySet()) {
List<ICPPMethod> overridersForSubobject = finalOverriders.get(subobjectNumber);
if (overridersForSubobject.size() == 1) {
return overridersForSubobject.get(0);
}
}
}
return null;
}
private static class FinalOverriderAnalysis {
/**
* Computes the final overrider map for a class hierarchy.
@ -207,6 +250,12 @@ public class CPPInheritance {
// Go through our own methods.
for (ICPPMethod method : ClassTypeHelper.getOwnMethods(classType, point)) {
// Skip methods that don't actually belong to us, such as methods brought
// into scope via a using-declaration.
if (method.getOwner() != classType) {
continue;
}
// For purposes of this computation, every virtual method is
// deemed for override itself.
result.add(method, subobjectNumber, method);

View file

@ -559,6 +559,21 @@ public class CPPSemantics {
}
}
}
// If the result is a virtual method called without explicit qualification, and we can determine a
// unique final overrider for it in the hierarchy of the method call's implied object type, replace
// the method with its final overrider.
if (!(lookupName.getParent() instanceof ICPPASTQualifiedName) && binding instanceof ICPPMethod &&
((ICPPMethod) binding).isVirtual()) {
IType impliedObjectType = data.getImpliedObjectType();
if (impliedObjectType instanceof ICPPClassType) {
ICPPMethod finalOverrider = CPPInheritance.getFinalOverrider((ICPPMethod) binding,
(ICPPClassType) impliedObjectType, lookupName);
if (finalOverrider != null) {
binding = finalOverrider;
}
}
}
// If we're still null...
if (binding == null) {