1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 22:22:11 +02:00

Bug 419938 - [fp] Pure virtual implementation not recognized if only one

path implements it

Change-Id: I90732a87d8d6b4ad2a84aa3c8b09b10727afa994
Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
Reviewed-on: https://git.eclipse.org/r/19823
Tested-by: Hudson CI
Reviewed-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
IP-Clean: Sergey Prigogin <eclipse.sprigogin@gmail.com>
Tested-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
This commit is contained in:
Nathan Ridge 2013-12-13 21:44:22 -05:00 committed by Sergey Prigogin
parent 09773cc341
commit c126fade3d
3 changed files with 67 additions and 24 deletions

View file

@ -313,6 +313,24 @@ public class AbstractClassInstantiationCheckerTest extends CheckerTestCase {
checkErrorLine(13);
}
// struct MyInterface {
// virtual void doIt() = 0;
// };
//
// struct Empty: virtual public MyInterface {};
//
// struct Implementer: virtual public MyInterface {
// virtual void doIt();
// };
//
// struct Multiple: virtual public Implementer, virtual public Empty {};
//
// static Multiple sharedMultiple;
public void testDiamondInheritanceWithOneImplementor_bug419938() {
loadCodeAndRun(getAboveComment());
checkNoErrors();
}
// struct A {
// virtual void test(int) = 0;
// virtual ~A();

View file

@ -23,6 +23,7 @@ import java.util.Set;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.parser.util.CollectionUtils;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
@ -107,51 +108,57 @@ public class SemanticQueries {
* can contain multiple subobjects of the same type (if multiple, non-virtual
* inheritance is used), and the pure virtual methods of each subobject must
* be implemented independently, we give each subobject of a given type a
* number, and for each method we keep track of the final overrider for each
* subobject number.
* number, and for each method we keep track of the final overriders for each
* subobject number. Generally, there should be only one final overrider per
* subobject (in fact the program is ill-formed if there is more than one),
* but to accurately detect pure virtual methods that haven't been overridden,
* we need to be able to keep track of more than one at a time.
*/
private static class FinalOverriderMap {
private Map<ICPPMethod, Map<Integer, ICPPMethod>> fMap = new HashMap<ICPPMethod, Map<Integer, ICPPMethod>>();
private Map<ICPPMethod, Map<Integer, List<ICPPMethod>>> fMap
= new HashMap<ICPPMethod, Map<Integer, List<ICPPMethod>>>();
/**
* Record 'overrider' as being the final ovverider of 'method' in subobject
* 'subobjectNumber'.
* Add 'overrider' as a final ovverider of 'method' in subobject
* 'subobjectNumber'.
*/
public void add(ICPPMethod method, int subobjectNumber, ICPPMethod overrider) {
Map<Integer, ICPPMethod> overriders = fMap.get(method);
Map<Integer, List<ICPPMethod>> overriders = fMap.get(method);
if (overriders == null) {
overriders = new HashMap<Integer, ICPPMethod>();
overriders = new HashMap<Integer, List<ICPPMethod>>();
fMap.put(method, overriders);
}
overriders.put(subobjectNumber, overrider);
CollectionUtils.listMapGet(overriders, subobjectNumber).add(overrider);
}
/**
* For each subobject for which 'method' has been overridden, update
* its final overrider to 'overrider'.
* For each subobject for which 'method' has been overridden, set
* 'overrider' to be its (only) final overrider.
*/
public void replaceForAllSubobjects(ICPPMethod method, ICPPMethod overrider) {
Map<Integer, ICPPMethod> overriders = fMap.get(method);
Map<Integer, List<ICPPMethod>> overriders = fMap.get(method);
if (overriders == null)
return;
for (Integer i : overriders.keySet())
overriders.put(i, overrider);
for (Integer i : overriders.keySet()) {
List<ICPPMethod> overridersForSubobject = CollectionUtils.listMapGet(overriders, i);
overridersForSubobject.clear();
overridersForSubobject.add(overrider);
}
}
/**
* Merge the final overriders from another FinalOverriderMap into this one.
* Merge the final overriders from another FinalOverriderMap into this one.
*/
public void addOverriders(FinalOverriderMap other) {
for (ICPPMethod method : other.fMap.keySet()) {
Map<Integer, ICPPMethod> overriders = fMap.get(method);
Map<Integer, List<ICPPMethod>> overriders = fMap.get(method);
if (overriders == null) {
overriders = new HashMap<Integer, ICPPMethod>();
overriders = new HashMap<Integer, List<ICPPMethod>>();
fMap.put(method, overriders);
}
Map<Integer, ICPPMethod> otherOverriders = other.fMap.get(method);
Map<Integer, List<ICPPMethod>> otherOverriders = other.fMap.get(method);
for (Integer i : otherOverriders.keySet()) {
ICPPMethod overrider = otherOverriders.get(i);
overriders.put(i, overrider);
CollectionUtils.listMapGet(overriders, i).addAll(otherOverriders.get(i));
}
}
}
@ -159,17 +166,17 @@ public class SemanticQueries {
/**
* Go through the final overrider map and find functions which are
* pure virtual in the hierarchy's root. These are functions which
* are declared pure virtual, and whose final overrider is themself,
* meaning they have not been overridden.
* are declared pure virtual, and which have a single final overrider
* which is themself, meaning they have not been overridden.
*/
public ICPPMethod[] collectPureVirtualMethods() {
List<ICPPMethod> pureVirtualMethods = new ArrayList<ICPPMethod>();
for (ICPPMethod method : fMap.keySet()) {
if (method.isPureVirtual()) {
Map<Integer, ICPPMethod> finalOverriders = fMap.get(method);
Map<Integer, List<ICPPMethod>> finalOverriders = fMap.get(method);
for (Integer subobjectNumber : finalOverriders.keySet()) {
ICPPMethod finalOverrider = finalOverriders.get(subobjectNumber);
if (finalOverrider == method) {
List<ICPPMethod> overridersForSubobject = finalOverriders.get(subobjectNumber);
if (overridersForSubobject.size() == 1 && overridersForSubobject.get(0) == method) {
pureVirtualMethods.add(method);
}
}
@ -237,6 +244,7 @@ public class SemanticQueries {
baseOverriderMap = virtualBaseCache.get(baseType);
if (baseOverriderMap == null) {
baseOverriderMap = collectFinalOverriders(baseType, true, inheritanceChain, point);
virtualBaseCache.put(baseType, baseOverriderMap);
}
} else {
baseOverriderMap = collectFinalOverriders(baseType, false, inheritanceChain, point);

View file

@ -11,10 +11,12 @@
*******************************************************************************/
package org.eclipse.cdt.core.parser.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
/**
* Useful utility methods for dealing with Collections.
@ -133,4 +135,19 @@ public final class CollectionUtils {
c1.addAll(c2);
return c1;
}
/**
* Gets a List<U> corresponding to a T in a Map<T, List<U>>.
* If the mapping doesn't exist, create it, with the empty
* list as the initial value.
* @since 5.6
*/
static public <T, U> List<U> listMapGet(Map<T, List<U>> m, T t) {
List<U> result = m.get(t);
if (result == null) {
result = new ArrayList<U>();
m.put(t, result);
}
return result;
}
}