From 38c0bca1206e09c4f414ca3bb0aaee8733bb8dbf Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Mon, 19 Sep 2011 11:23:27 +0200 Subject: [PATCH] Bug 357256: Recursive inheritance causes a StackOverflowError. --- .../core/parser/tests/ast2/AST2CPPTests.java | 9 ++ .../core/dom/parser/cpp/ClassTypeHelper.java | 127 +++++++++--------- 2 files changed, 73 insertions(+), 63 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 69ccb31297d..c412dc469ab 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -9490,4 +9490,13 @@ public class AST2CPPTests extends AST2BaseTest { public void testAmbiguityResolution_Bug356268() throws Exception { parseAndCheckBindings(); } + + + // class A : A { + // }; + public void testRecursiveClassInheritance_Bug357256() throws Exception { + BindingAssertionHelper bh= getAssertionHelper(); + ICPPClassType c= bh.assertNonProblem("A", 1); + assertEquals(0, ClassTypeHelper.getPureVirtualMethods(c).length); + } } 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 3843a9d9318..b0147c4f0d6 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 @@ -16,7 +16,6 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -819,22 +818,79 @@ public class ClassTypeHelper { * template parameters. */ public static ICPPMethod[] getPureVirtualMethods(ICPPClassType classType) { - Collection> result = collectPureVirtualMethods(classType).values(); + Map> result= collectPureVirtualMethods(classType, + new HashMap>>()); + int resultArraySize = 0; - for (Set set : result) { - resultArraySize += set.size(); + for (List methods : result.values()) { + resultArraySize += methods.size(); } ICPPMethod[] resultArray = new ICPPMethod[resultArraySize]; int resultArrayIdx = 0; - for (Set methodsSet : result) { - for (ICPPMethod method : methodsSet) { - resultArray[resultArrayIdx] = method; - ++resultArrayIdx; + for (List methods : result.values()) { + for (ICPPMethod method : methods) { + resultArray[resultArrayIdx++] = method; } } return resultArray; } + private static Map> collectPureVirtualMethods(ICPPClassType classType, + Map>> cache) { + + Map> result = cache.get(classType); + if (result != null) + return result; + + result= new HashMap>(); + cache.put(classType, result); + + // Look at the pure virtual methods of the base classes + Set handledBaseClasses= new HashSet(); + for (ICPPBase base : classType.getBases()) { + final IBinding baseClass = base.getBaseClass(); + if (baseClass instanceof ICPPClassType && handledBaseClasses.add(baseClass)) { + Map> pureVirtuals = collectPureVirtualMethods((ICPPClassType) baseClass, cache); + // Merge derived pure virtual methods + for (String key : pureVirtuals.keySet()) { + List list = result.get(key); + if (list == null) { + list= new ArrayList(); + result.put(key, list); + } + list.addAll(pureVirtuals.get(key)); + } + } + } + + // Remove overridden pure-virtual methods and add in new pure virutals. + final ObjectSet methods = getOwnMethods(classType); + for (int i=0; i list = result.get(key); + if (list != null) { + final ICPPFunctionType methodType = method.getType(); + for (Iterator it= list.iterator(); it.hasNext(); ) { + ICPPMethod pureVirtual = it.next(); + if (functionTypesAllowOverride(methodType, pureVirtual.getType())) { + it.remove(); + } + } + } + if (method.isPureVirtual()) { + if (list == null) { + list= new ArrayList(); + result.put(key, list); + } + list.add(method); + } else if (list != null && list.isEmpty()) { + result.remove(key); + } + } + return result; + } + private static String getMethodNameForOverrideKey(ICPPMethod method) { if (method.isDestructor()) { // Destructor's names may differ but they will override each other. @@ -843,59 +899,4 @@ public class ClassTypeHelper { return method.getName(); } } - - /** - * Returns pure virtual methods of the given class grouped by their names. - * - * @param classType The class to obtain the pure virtual method for. - * @return pure virtual methods grouped by their names. - */ - private static Map > collectPureVirtualMethods(ICPPClassType classType) { - // Collect pure virtual functions from base classes - Map> pureVirtualMethods = new HashMap>(); - for (ICPPBase base : classType.getBases()) { - if (base.getBaseClass() instanceof ICPPClassType) { - ICPPClassType baseClass = (ICPPClassType) base.getBaseClass(); - Map > derivedPureVirtualMethods = collectPureVirtualMethods(baseClass); - // Merge derived pure virtual methods - for (Map.Entry > currMethodEntry : derivedPureVirtualMethods.entrySet()) { - Set methodsSet = pureVirtualMethods.get(currMethodEntry.getKey()); - if (methodsSet == null) { - pureVirtualMethods.put(currMethodEntry.getKey(), currMethodEntry.getValue()); - } else { - methodsSet.addAll(currMethodEntry.getValue()); - } - } - } - } - - // Remove overridden methods (even if they are pure virtual) - for (ICPPMethod declaredMethod : getOwnMethods(classType).toList()) { - Set methodsSet = pureVirtualMethods.get(getMethodNameForOverrideKey(declaredMethod)); - if (methodsSet != null) { - for (Iterator methodIt = methodsSet.iterator(); methodIt.hasNext();) { - ICPPMethod method = methodIt.next(); - if (functionTypesAllowOverride(declaredMethod.getType(), method.getType())) { - methodIt.remove(); - } - } - if (methodsSet.isEmpty()) { - pureVirtualMethods.remove(getMethodNameForOverrideKey(declaredMethod)); - } - } - } - - // Add pure virtual methods of current class - for (ICPPMethod method : classType.getDeclaredMethods()) { - if (method.isPureVirtual()) { - Set methodsSet = pureVirtualMethods.get(getMethodNameForOverrideKey(method)); - if (methodsSet == null) { - methodsSet = new HashSet(); - pureVirtualMethods.put(getMethodNameForOverrideKey(method), methodsSet); - } - methodsSet.add(method); - } - } - return pureVirtualMethods; - } }