From 0df4d6096f0ae1116a5b8e988f2e49a3efe86c46 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Sat, 30 Jul 2011 22:59:14 -0700 Subject: [PATCH] Bug 353360 - Bogus "type must implement the inherited pure virtual method" error. Fix and test case. --- .../AbstractClassInstantiationChecker.java | 6 +-- ...AbstractClassInstantiationCheckerTest.java | 16 ++++++- .../core/dom/parser/cpp/ClassTypeHelper.java | 48 ++++++++++++------- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/AbstractClassInstantiationChecker.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/AbstractClassInstantiationChecker.java index 33028a04ed6..41714eb89bc 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/AbstractClassInstantiationChecker.java +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/AbstractClassInstantiationChecker.java @@ -186,10 +186,8 @@ public class AbstractClassInstantiationChecker extends AbstractIndexAstChecker { IType unwindedType = CxxAstUtils.getInstance().unwindTypedef(typeToCheck); if (unwindedType instanceof ICPPClassType) { ICPPClassType classType = (ICPPClassType) unwindedType; - ICPPMethod[] pureVirtualMethods; - if (pureVirtualMethodsCache.containsKey(classType)) { - pureVirtualMethods = pureVirtualMethodsCache.get(classType); - } else { + ICPPMethod[] pureVirtualMethods = pureVirtualMethodsCache.get(classType); + if (pureVirtualMethods == null) { pureVirtualMethods = ClassTypeHelper.getPureVirtualMethods(classType); pureVirtualMethodsCache.put(classType, pureVirtualMethods); } 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 d9fda5899cd..207fa0f0220 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 @@ -240,7 +240,21 @@ public class AbstractClassInstantiationCheckerTest extends CheckerTestCase { // }; // // B b; - public void testPureVirtualDestructorOverride() { + public void testPureVirtualDestructorOverride_1() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class A { + // public: + // virtual ~A() = 0; + // }; + // + // class B : public A { + // }; + // + // B b; + public void testPureVirtualDestructorOverride_2() { loadCodeAndRun(getAboveComment()); checkNoErrors(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java index 49a790d715b..959ae708b81 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java @@ -76,10 +76,12 @@ import org.eclipse.core.runtime.CoreException; * Holds common implementation of methods for ICPPClassType implementations that have * a corresponding textual definition in the source code. * - * @see CPPClassType - * @see CPPClassTemplate + * @see CPPClassType + * @see CPPClassTemplate */ public class ClassTypeHelper { + private static final String DESTRUCTOR_OVERRIDE_KEY = "~"; //$NON-NLS-1$ + public static IBinding[] getFriends(ICPPInternalClassTypeMixinHost host) { if (host.getDefinition() == null) { host.checkForDefinition(); @@ -292,10 +294,7 @@ public class ClassTypeHelper { } public static ICPPMethod[] getMethods(ICPPClassType ct) { - ObjectSet set= new ObjectSet(4); - set.addAll(ct.getDeclaredMethods()); - ICPPClassScope scope= (ICPPClassScope) ct.getCompositeScope(); - set.addAll(scope.getImplicitMethods()); + ObjectSet set = getOwnMethods(ct); ICPPClassType[] bases= getAllBases(ct); for (ICPPClassType base : bases) { @@ -307,6 +306,20 @@ public class ClassTypeHelper { } return set.keyArray(ICPPMethod.class); } + + /** + * Returns methods either declared by the given class or generated by the compiler. Does not + * include methods declared in base classes. + * @param classType + * @return + */ + private static ObjectSet getOwnMethods(ICPPClassType classType) { + ObjectSet set= new ObjectSet(4); + set.addAll(classType.getDeclaredMethods()); + ICPPClassScope scope= (ICPPClassScope) classType.getCompositeScope(); + set.addAll(scope.getImplicitMethods()); + return set; + } public static ICPPMethod[] getDeclaredMethods(ICPPInternalClassTypeMixinHost host) { if (host.getDefinition() == null) { @@ -745,7 +758,7 @@ public class ClassTypeHelper { } private static ICPPMethod getMethodInClass(ICPPClassType ct, int kind) { - switch(kind) { + switch (kind) { case KIND_DEFAULT_CTOR: case KIND_COPY_CTOR: for (ICPPConstructor ctor : ct.getConstructors()) { @@ -805,8 +818,8 @@ public class ClassTypeHelper { * but doesn't take into account base classes and methods dependent on unspecified * template parameters. */ - public static ICPPMethod[] getPureVirtualMethods(ICPPClassType classTarget) { - Collection> result = collectPureVirtualMethods(classTarget).values(); + public static ICPPMethod[] getPureVirtualMethods(ICPPClassType classType) { + Collection> result = collectPureVirtualMethods(classType).values(); int resultArraySize = 0; for (Set set : result) { resultArraySize += set.size(); @@ -825,7 +838,7 @@ public class ClassTypeHelper { private static String getMethodNameForOverrideKey(ICPPMethod method) { if (method.isDestructor()) { // Destructor's names may differ but they will override each other. - return "~"; //$NON-NLS-1$ + return DESTRUCTOR_OVERRIDE_KEY; } else { return method.getName(); } @@ -834,13 +847,13 @@ public class ClassTypeHelper { /** * Returns pure virtual methods of the given class grouped by their names. * - * @param classTarget The class to obtain the pure virtual method for. + * @param classType The class to obtain the pure virtual method for. * @return pure virtual methods grouped by their names. */ - private static Map > collectPureVirtualMethods(ICPPClassType classTarget) { + private static Map > collectPureVirtualMethods(ICPPClassType classType) { // Collect pure virtual functions from base classes Map> pureVirtualMethods = new HashMap>(); - for (ICPPBase base : classTarget.getBases()) { + for (ICPPBase base : classType.getBases()) { if (base.getBaseClass() instanceof ICPPClassType) { ICPPClassType baseClass = (ICPPClassType) base.getBaseClass(); Map > derivedPureVirtualMethods = collectPureVirtualMethods(baseClass); @@ -849,15 +862,15 @@ public class ClassTypeHelper { Set methodsSet = pureVirtualMethods.get(currMethodEntry.getKey()); if (methodsSet == null) { pureVirtualMethods.put(currMethodEntry.getKey(), currMethodEntry.getValue()); - } - else { + } else { methodsSet.addAll(currMethodEntry.getValue()); } } } } + // Remove overridden methods (even if they are pure virtual) - for (ICPPMethod declaredMethod : classTarget.getDeclaredMethods()) { + for (ICPPMethod declaredMethod : getOwnMethods(classType).toList()) { Set methodsSet = pureVirtualMethods.get(getMethodNameForOverrideKey(declaredMethod)); if (methodsSet != null) { for (Iterator methodIt = methodsSet.iterator(); methodIt.hasNext();) { @@ -871,8 +884,9 @@ public class ClassTypeHelper { } } } + // Add pure virtual methods of current class - for (ICPPMethod method : classTarget.getDeclaredMethods()) { + for (ICPPMethod method : classType.getDeclaredMethods()) { if (method.isPureVirtual()) { Set methodsSet = pureVirtualMethods.get(getMethodNameForOverrideKey(method)); if (methodsSet == null) {