summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Ridge2013-12-13 21:44:22 (EST)
committerSergey Prigogin2013-12-16 00:40:02 (EST)
commitc126fade3dda65e54ec6ca13750218fb023b1410 (patch)
treeb1e2ab03c17f5b1b2f8d8a98d38bf68d0578f530
parent09773cc3411d26476b2bfb4ca45539834cb796f5 (diff)
downloadorg.eclipse.cdt-c126fade3dda65e54ec6ca13750218fb023b1410.zip
org.eclipse.cdt-c126fade3dda65e54ec6ca13750218fb023b1410.tar.gz
org.eclipse.cdt-c126fade3dda65e54ec6ca13750218fb023b1410.tar.bz2
Bug 419938 - [fp] Pure virtual implementation not recognized if only onerefs/changes/23/19823/2
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>
-rw-r--r--codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AbstractClassInstantiationCheckerTest.java18
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/SemanticQueries.java56
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CollectionUtils.java17
3 files changed, 67 insertions, 24 deletions
diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AbstractClassInstantiationCheckerTest.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AbstractClassInstantiationCheckerTest.java
index aa705df..8833857 100644
--- a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AbstractClassInstantiationCheckerTest.java
+++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AbstractClassInstantiationCheckerTest.java
@@ -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();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/SemanticQueries.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/SemanticQueries.java
index 18e0af6..7d39702 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/SemanticQueries.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/SemanticQueries.java
@@ -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);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CollectionUtils.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CollectionUtils.java
index 9f879d8..c4df0f6 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CollectionUtils.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CollectionUtils.java
@@ -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;
+ }
}