1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 357256: Recursive inheritance causes a StackOverflowError.

This commit is contained in:
Markus Schorn 2011-09-19 11:23:27 +02:00
parent 7902fd1c77
commit 38c0bca120
2 changed files with 73 additions and 63 deletions

View file

@ -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);
}
}

View file

@ -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<Set<ICPPMethod>> result = collectPureVirtualMethods(classType).values();
Map<String, List<ICPPMethod>> result= collectPureVirtualMethods(classType,
new HashMap<ICPPClassType, Map<String, List<ICPPMethod>>>());
int resultArraySize = 0;
for (Set<ICPPMethod> set : result) {
resultArraySize += set.size();
for (List<ICPPMethod> methods : result.values()) {
resultArraySize += methods.size();
}
ICPPMethod[] resultArray = new ICPPMethod[resultArraySize];
int resultArrayIdx = 0;
for (Set<ICPPMethod> methodsSet : result) {
for (ICPPMethod method : methodsSet) {
resultArray[resultArrayIdx] = method;
++resultArrayIdx;
for (List<ICPPMethod> methods : result.values()) {
for (ICPPMethod method : methods) {
resultArray[resultArrayIdx++] = method;
}
}
return resultArray;
}
private static Map<String, List<ICPPMethod>> collectPureVirtualMethods(ICPPClassType classType,
Map<ICPPClassType, Map<String, List<ICPPMethod>>> cache) {
Map<String, List<ICPPMethod>> result = cache.get(classType);
if (result != null)
return result;
result= new HashMap<String, List<ICPPMethod>>();
cache.put(classType, result);
// Look at the pure virtual methods of the base classes
Set<IBinding> handledBaseClasses= new HashSet<IBinding>();
for (ICPPBase base : classType.getBases()) {
final IBinding baseClass = base.getBaseClass();
if (baseClass instanceof ICPPClassType && handledBaseClasses.add(baseClass)) {
Map<String, List<ICPPMethod>> pureVirtuals = collectPureVirtualMethods((ICPPClassType) baseClass, cache);
// Merge derived pure virtual methods
for (String key : pureVirtuals.keySet()) {
List<ICPPMethod> list = result.get(key);
if (list == null) {
list= new ArrayList<ICPPMethod>();
result.put(key, list);
}
list.addAll(pureVirtuals.get(key));
}
}
}
// Remove overridden pure-virtual methods and add in new pure virutals.
final ObjectSet<ICPPMethod> methods = getOwnMethods(classType);
for (int i=0; i<methods.size(); i++) {
ICPPMethod method= methods.keyAt(i);
String key= getMethodNameForOverrideKey(method);
List<ICPPMethod> list = result.get(key);
if (list != null) {
final ICPPFunctionType methodType = method.getType();
for (Iterator<ICPPMethod> 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<ICPPMethod>();
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<String, Set<ICPPMethod> > collectPureVirtualMethods(ICPPClassType classType) {
// Collect pure virtual functions from base classes
Map<String, Set<ICPPMethod>> pureVirtualMethods = new HashMap<String, Set<ICPPMethod>>();
for (ICPPBase base : classType.getBases()) {
if (base.getBaseClass() instanceof ICPPClassType) {
ICPPClassType baseClass = (ICPPClassType) base.getBaseClass();
Map<String, Set<ICPPMethod> > derivedPureVirtualMethods = collectPureVirtualMethods(baseClass);
// Merge derived pure virtual methods
for (Map.Entry<String, Set<ICPPMethod> > currMethodEntry : derivedPureVirtualMethods.entrySet()) {
Set<ICPPMethod> 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<ICPPMethod> methodsSet = pureVirtualMethods.get(getMethodNameForOverrideKey(declaredMethod));
if (methodsSet != null) {
for (Iterator<ICPPMethod> 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<ICPPMethod> methodsSet = pureVirtualMethods.get(getMethodNameForOverrideKey(method));
if (methodsSet == null) {
methodsSet = new HashSet<ICPPMethod>();
pureVirtualMethods.put(getMethodNameForOverrideKey(method), methodsSet);
}
methodsSet.add(method);
}
}
return pureVirtualMethods;
}
}