1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +02:00

Moved getPureVirtualMethods method to SemanticQueries.

This commit is contained in:
Sergey Prigogin 2013-07-28 13:00:59 -07:00
parent 5fb92e3cf8
commit d5f3272f20
5 changed files with 199 additions and 187 deletions

View file

@ -40,7 +40,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
/**
* Reports a problem if object of a class cannot be created because
@ -196,7 +196,7 @@ public class AbstractClassInstantiationChecker extends AbstractIndexAstChecker {
ICPPClassType classType = (ICPPClassType) unwindedType;
ICPPMethod[] pureVirtualMethods = pureVirtualMethodsCache.get(classType);
if (pureVirtualMethods == null) {
pureVirtualMethods = ClassTypeHelper.getPureVirtualMethods(classType, problemNode);
pureVirtualMethods = SemanticQueries.getPureVirtualMethods(classType, problemNode);
pureVirtualMethodsCache.put(classType, pureVirtualMethods);
}

View file

@ -127,6 +127,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator;
@ -9579,7 +9580,7 @@ public class AST2CPPTests extends AST2TestBase {
public void testRecursiveClassInheritance_Bug357256() throws Exception {
BindingAssertionHelper bh= getAssertionHelper();
ICPPClassType c= bh.assertNonProblem("A", 1);
assertEquals(0, ClassTypeHelper.getPureVirtualMethods(c, null).length);
assertEquals(0, SemanticQueries.getPureVirtualMethods(c, null).length);
}
// template <typename T> struct CT1 {};

View file

@ -13,7 +13,17 @@ package org.eclipse.cdt.core.dom.ast.cpp;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
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.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;
@ -71,4 +81,187 @@ public class SemanticQueries {
return function.getParameters().length >= numArguments
&& function.getRequiredArgumentCount() <= numArguments;
}
/**
* Returns all pure virtual methods of a class. Inherited pure virtual methods
* that have not been implemented are also returned.
*
* NOTE: The method produces complete results for template instantiations
* but doesn't take into account base classes and methods dependent on unspecified
* template parameters.
*
* @param classType the class whose pure virtual methods should be returned
* @param point the point of template instantiation, if applicable
* @return an array containing all pure virtual methods of the class
* @since 5.6
*/
public static ICPPMethod[] getPureVirtualMethods(ICPPClassType classType, IASTNode point) {
return new PureVirtualMethodCollector().collect(classType, point);
}
/** Helper class for {@link #getPureVirtualMethods(ICPPClassType, IASTNode)} */
private static class PureVirtualMethodCollector {
/**
* This class represents a mapping of virtual methods in a class hierarchy
* to their final overriders (see [class.virtual] p2). Since a class hierarchy
* 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.
*/
private static class FinalOverriderMap {
private Map<ICPPMethod, Map<Integer, ICPPMethod>> fMap = new HashMap<ICPPMethod, Map<Integer, ICPPMethod>>();
/**
* Record 'overrider' as being the final ovverider of 'method' in subobject
* 'subobjectNumber'.
*/
public void add(ICPPMethod method, int subobjectNumber, ICPPMethod overrider) {
Map<Integer, ICPPMethod> overriders = fMap.get(method);
if (overriders == null) {
overriders = new HashMap<Integer, ICPPMethod>();
fMap.put(method, overriders);
}
overriders.put(subobjectNumber, overrider);
}
/**
* For each subobject for which 'method' has been overridden, update
* its final overrider to 'overrider'.
*/
public void replaceForAllSubobjects(ICPPMethod method, ICPPMethod overrider) {
Map<Integer, ICPPMethod> overriders = fMap.get(method);
if (overriders == null)
return;
for (Integer i : overriders.keySet())
overriders.put(i, overrider);
}
/**
* 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);
if (overriders == null) {
overriders = new HashMap<Integer, ICPPMethod>();
fMap.put(method, overriders);
}
Map<Integer, ICPPMethod> otherOverriders = other.fMap.get(method);
for (Integer i : otherOverriders.keySet()) {
ICPPMethod overrider = otherOverriders.get(i);
overriders.put(i, overrider);
}
}
}
/**
* 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.
*/
public ICPPMethod[] collectPureVirtualMethods() {
List<ICPPMethod> pureVirtualMethods = new ArrayList<ICPPMethod>();
for (ICPPMethod method : fMap.keySet()) {
if (method.isPureVirtual()) {
Map<Integer, ICPPMethod> finalOverriders = fMap.get(method);
for (Integer subobjectNumber : finalOverriders.keySet()) {
ICPPMethod finalOverrider = finalOverriders.get(subobjectNumber);
if (finalOverrider == method) {
pureVirtualMethods.add(method);
}
}
}
}
return pureVirtualMethods.toArray(new ICPPMethod[pureVirtualMethods.size()]);
}
}
// The last subobject number used for each type in the hierarchy. This is used to
// assign subobject numbers to subobjects. Virtual subobjects get a subobject
// number of zero, while non-virtual subobjects are number starting from one.
private Map<ICPPClassType, Integer> subobjectNumbers = new HashMap<ICPPClassType, Integer>();
// Cache of final overrider maps for virtual base subobjects. Since such subobjects
// only occur once in the hierarchy, we can cache the final overrider maps we
// compute for them.
private Map<ICPPClassType, FinalOverriderMap> virtualBaseCache = new HashMap<ICPPClassType, FinalOverriderMap>();
public ICPPMethod[] collect(ICPPClassType root, IASTNode point) {
FinalOverriderMap finalOverriderMap = collectFinalOverriders(root, false, new HashSet<ICPPClassType>(), point);
return finalOverriderMap.collectPureVirtualMethods();
}
/**
* Compute the final overrider map for a subtree in a class hierarchy.
*
* @param classType the root of the subtree in question
* @param isVirtualBase whether 'classType' is inherited virtually
* @param inheritanceChain the chain of classes from the entire hierarchy's root to 'classType'.
* This is used to guard against circular inheritance.
* @param point the point of template instantiation, if applicable
* @return the computed final overrider map
*/
private FinalOverriderMap collectFinalOverriders(ICPPClassType classType, boolean isVirtualBase,
Set<ICPPClassType> inheritanceChain, IASTNode point) {
FinalOverriderMap result = new FinalOverriderMap();
inheritanceChain.add(classType);
// Determine the subobject number for the current class.
int subobjectNumber = 0;
if (!isVirtualBase) {
Integer lastNumber = subobjectNumbers.get(classType);
subobjectNumber = (lastNumber == null ? 0 : lastNumber) + 1;
subobjectNumbers.put(classType, subobjectNumber);
}
// Go through our base classes.
for (ICPPBase base : ClassTypeHelper.getBases(classType, point)) {
IBinding baseClass = base.getBaseClass();
if (!(baseClass instanceof ICPPClassType))
continue;
ICPPClassType baseType = (ICPPClassType) baseClass;
// Guard against circular inheritance.
if (inheritanceChain.contains(baseType))
continue;
// Collect final overrider information from the base class.
// If it's a virtual base class and we've already processed it
// in this class hierarchy, don't process it again.
FinalOverriderMap baseOverriderMap;
if (base.isVirtual()) {
baseOverriderMap = virtualBaseCache.get(baseType);
if (baseOverriderMap == null) {
baseOverriderMap = collectFinalOverriders(baseType, true, inheritanceChain, point);
}
} else {
baseOverriderMap = collectFinalOverriders(baseType, false, inheritanceChain, point);
}
// Merge final overrider information from base class into this class.
result.addOverriders(baseOverriderMap);
}
// Go through our own methods.
for (ICPPMethod method : ClassTypeHelper.getOwnMethods(classType, point)) {
// For purposes of this computation, every virtual method is
// deemed for override itself.
result.add(method, subobjectNumber, method);
// Find all methods overridden by this method, and set their final overrider
// to be this method.
ICPPMethod[] overriddenMethods = ClassTypeHelper.findOverridden(method, point);
for (ICPPMethod overriddenMethod : overriddenMethods)
result.replaceForAllSubobjects(overriddenMethod, method);
}
inheritanceChain.remove(classType);
return result;
}
}
}

View file

@ -1007,187 +1007,4 @@ public class ClassTypeHelper {
name = "<anonymous>"; //$NON-NLS-1$
return new IllegalArgumentException(name + " is not a member of " + classType.getName()); //$NON-NLS-1$
}
/**
* Gets all pure virtual methods of a class. Inherited pure virtual methods
* that have not been implemented are also returned.
*
* NOTE: The method produces complete results for template instantiations
* but doesn't take into account base classes and methods dependent on unspecified
* template parameters.
*
* @param classType the class whose pure virtual methods should be returned
* @param point the point of template instantiation, if applicable
* @return an array containing all pure virtual methods of the class
* @since 5.6
*/
public static ICPPMethod[] getPureVirtualMethods(ICPPClassType classType, IASTNode point) {
return new PureVirtualMethodCollector().collect(classType, point);
}
// Helper class for getPureVirtualMethods()
private static class PureVirtualMethodCollector {
/**
* This class represents a mapping of virtual methods in a class hierarchy
* to their final overriders (see [class.virtual] p2). Since a class hierarchy
* 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.
*/
private static class FinalOverriderMap {
private Map<ICPPMethod, Map<Integer, ICPPMethod>> fMap = new HashMap<ICPPMethod, Map<Integer, ICPPMethod>>();
/**
* Record 'overrider' as being the final ovverider of 'method' in subobject
* 'subobjectNumber'.
*/
public void add(ICPPMethod method, int subobjectNumber, ICPPMethod overrider) {
Map<Integer, ICPPMethod> overriders = fMap.get(method);
if (overriders == null) {
overriders = new HashMap<Integer, ICPPMethod>();
fMap.put(method, overriders);
}
overriders.put(subobjectNumber, overrider);
}
/**
* For each subobject for which 'method' has been overridden, update
* its final overrider to 'overrider'.
*/
public void replaceForAllSubobjects(ICPPMethod method, ICPPMethod overrider) {
Map<Integer, ICPPMethod> overriders = fMap.get(method);
if (overriders == null)
return;
for (Integer i : overriders.keySet())
overriders.put(i, overrider);
}
/**
* 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);
if (overriders == null) {
overriders = new HashMap<Integer, ICPPMethod>();
fMap.put(method, overriders);
}
Map<Integer, ICPPMethod> otherOverriders = other.fMap.get(method);
for (Integer i : otherOverriders.keySet()) {
ICPPMethod overrider = otherOverriders.get(i);
overriders.put(i, overrider);
}
}
}
/**
* 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.
*/
public ICPPMethod[] collectPureVirtualMethods() {
List<ICPPMethod> pureVirtualMethods = new ArrayList<ICPPMethod>();
for (ICPPMethod method : fMap.keySet()) {
if (method.isPureVirtual()) {
Map<Integer, ICPPMethod> finalOverriders = fMap.get(method);
for (Integer subobjectNumber : finalOverriders.keySet()) {
ICPPMethod finalOverrider = finalOverriders.get(subobjectNumber);
if (finalOverrider == method) {
pureVirtualMethods.add(method);
}
}
}
}
return pureVirtualMethods.toArray(new ICPPMethod[pureVirtualMethods.size()]);
}
}
// The last subobject number used for each type in the hierarchy. This is used to
// assign subobject numbers to subobjects. Virtual subobjects get a subobject
// number of zero, while non-virtual subobjects are number starting from one.
private Map<ICPPClassType, Integer> subobjectNumbers = new HashMap<ICPPClassType, Integer>();
// Cache of final overrider maps for virtual base subobjects. Since such subobjects
// only occur once in the hierarchy, we can cache the final overrider maps we
// compute for them.
private Map<ICPPClassType, FinalOverriderMap> virtualBaseCache = new HashMap<ICPPClassType, FinalOverriderMap>();
public ICPPMethod[] collect(ICPPClassType root, IASTNode point) {
FinalOverriderMap finalOverriderMap = collectFinalOverriders(root, false, new HashSet<ICPPClassType>(), point);
return finalOverriderMap.collectPureVirtualMethods();
}
/**
* Compute the final overrider map for a subtree in a class hierarchy.
*
* @param classType the root of the subtree in question
* @param isVirtualBase whether 'classType' is inherited virtually
* @param inheritanceChain the chain of classes from the entire hierarchy's root to 'classType'.
* This is used to guard against circular inheritance.
* @param point the point of template instantiation, if applicable
* @return the computed final overrider map
*/
private FinalOverriderMap collectFinalOverriders(ICPPClassType classType, boolean isVirtualBase,
Set<ICPPClassType> inheritanceChain, IASTNode point) {
FinalOverriderMap result = new FinalOverriderMap();
inheritanceChain.add(classType);
// Determine the subobject number for the current class.
int subobjectNumber = 0;
if (!isVirtualBase) {
Integer lastNumber = subobjectNumbers.get(classType);
subobjectNumber = (lastNumber == null ? 0 : lastNumber) + 1;
subobjectNumbers.put(classType, subobjectNumber);
}
// Go through our base classes.
for (ICPPBase base : ClassTypeHelper.getBases(classType, point)) {
IBinding baseClass = base.getBaseClass();
if (!(baseClass instanceof ICPPClassType))
continue;
ICPPClassType baseType = (ICPPClassType) baseClass;
// Guard against circular inheritance.
if (inheritanceChain.contains(baseType))
continue;
// Collect final overrider information from the base class.
// If it's a virtual base class and we've already processed it
// in this class hierarchy, don't process it again.
FinalOverriderMap baseOverriderMap;
if (base.isVirtual()) {
baseOverriderMap = virtualBaseCache.get(baseType);
if (baseOverriderMap == null) {
baseOverriderMap = collectFinalOverriders(baseType, true, inheritanceChain, point);
}
} else {
baseOverriderMap = collectFinalOverriders(baseType, false, inheritanceChain, point);
}
// Merge final overrider information from base class into this class.
result.addOverriders(baseOverriderMap);
}
// Go through our own methods.
for (ICPPMethod method : ClassTypeHelper.getOwnMethods(classType, point)) {
// For purposes of this computation, every virtual method is
// deemed for override itself.
result.add(method, subobjectNumber, method);
// Find all methods overridden by this method, and set their final overrider
// to be this method.
ICPPMethod[] overriddenMethods = ClassTypeHelper.findOverridden(method, point);
for (ICPPMethod overriddenMethod : overriddenMethods)
result.replaceForAllSubobjects(overriddenMethod, method);
}
inheritanceChain.remove(classType);
return result;
}
}
}

View file

@ -23,6 +23,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper.MethodKind;
@ -298,7 +299,7 @@ public class TypeTraits {
}
public static boolean isAbstract(ICPPClassType classType, IASTNode point) {
return ClassTypeHelper.getPureVirtualMethods(classType, point).length != 0;
return SemanticQueries.getPureVirtualMethods(classType, point).length != 0;
}
/**