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:
parent
5fb92e3cf8
commit
d5f3272f20
5 changed files with 199 additions and 187 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue