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:
parent
7902fd1c77
commit
38c0bca120
2 changed files with 73 additions and 63 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue