blob: 750798b09ac72e2ee022e42c95f1ebe7296e4884 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization;
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.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
/**
* Base class for all specialization scopes
* For safe usage in index bindings, all fields need to be final or volatile.
*/
public class AbstractCPPClassSpecializationScope implements ICPPClassSpecializationScope {
private final ICPPClassSpecialization specialClass;
// The following fields are used by the PDOM bindings and need to be volatile.
private volatile ICPPBase[] fBases;
private volatile ICPPMethod[] ownInheritedConstructors;
private final ThreadLocal<Boolean> fComputingBases = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
public AbstractCPPClassSpecializationScope(ICPPClassSpecialization specialization) {
this.specialClass= specialization;
}
@Override
public ICPPClassType getOriginalClassType() {
return specialClass.getSpecializedBinding();
}
@Override
public final IBinding getBinding(IASTName name, boolean resolve) {
return getBinding(name, resolve, IIndexFileSet.EMPTY);
}
@Override
public final IBinding[] getBindings(IASTName name, boolean resolve, boolean prefix) {
return getBindings(new ScopeLookupData(name, resolve, prefix));
}
@Override
public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet fileSet) {
char[] c = name.getLookupKey();
if (CharArrayUtils.equals(c, specialClass.getNameCharArray())
&& !CPPClassScope.shallReturnConstructors(name, false)) {
return specialClass;
}
ICPPClassType specialized = specialClass.getSpecializedBinding();
IScope classScope = specialized.getCompositeScope();
IBinding[] bindings = classScope != null ?
classScope.getBindings(new ScopeLookupData(name, resolve, false)) : null;
if (bindings == null)
return null;
IBinding[] specs = IBinding.EMPTY_BINDING_ARRAY;
CPPSemantics.pushLookupPoint(name);
try {
for (IBinding binding : bindings) {
specs = ArrayUtil.append(specs, specialClass.specializeMember(binding));
}
} finally {
CPPSemantics.popLookupPoint();
}
specs = ArrayUtil.trim(specs);
return CPPSemantics.resolveAmbiguities(name, specs);
}
@Deprecated
@Override
final public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup,
IIndexFileSet fileSet) {
return getBindings(new ScopeLookupData(name, resolve, prefixLookup));
}
@Override
final public IBinding[] getBindings(ScopeLookupData lookup) {
ICPPClassType specialized = specialClass.getSpecializedBinding();
IScope classScope = specialized.getCompositeScope();
if (classScope == null)
return IBinding.EMPTY_BINDING_ARRAY;
IBinding[] bindings= classScope.getBindings(lookup);
IBinding[] result= IBinding.EMPTY_BINDING_ARRAY;
if (bindings == null) {
return result;
}
int n = 0;
for (IBinding binding : bindings) {
if (binding == specialized ||
(binding instanceof ICPPClassType && areSameTypesModuloPartialSpecialization(specialized, (IType) binding))) {
binding= specialClass;
} else {
binding= specialClass.specializeMember(binding);
}
if (binding != null)
result = ArrayUtil.appendAt(result, n++, binding);
}
return ArrayUtil.trim(result, n);
}
private static boolean areSameTypesModuloPartialSpecialization(IType type1, IType type2) {
while (type1 instanceof ICPPClassTemplatePartialSpecialization) {
type1 = ((ICPPClassTemplatePartialSpecialization) type1).getPrimaryClassTemplate();
}
while (type2 instanceof ICPPClassTemplatePartialSpecialization) {
type2 = ((ICPPClassTemplatePartialSpecialization) type2).getPrimaryClassTemplate();
}
return type1.isSameType(type2);
}
@Override
public ICPPClassSpecialization getClassType() {
return specialClass;
}
@Override
public ICPPBase[] getBases() {
if (fBases == null) {
if (fComputingBases.get()) {
return ICPPBase.EMPTY_BASE_ARRAY; // avoid recursion
}
fComputingBases.set(true);
try {
ICPPBase[] result = ICPPBase.EMPTY_BASE_ARRAY;
ICPPBase[] bases = specialClass.getSpecializedBinding().getBases();
if (bases.length == 0) {
fBases= bases;
} else {
final ICPPTemplateParameterMap tpmap = specialClass.getTemplateParameterMap();
for (ICPPBase base : bases) {
IType baseType = base.getBaseClassType();
if (baseType instanceof ICPPParameterPackType) {
IType[] specClasses= CPPTemplates.instantiateTypes(new IType[] { baseType },
new InstantiationContext(tpmap, specialClass));
if (specClasses.length == 1 && specClasses[0] instanceof ICPPParameterPackType) {
result= ArrayUtil.append(result, base);
} else {
for (IType specClass : specClasses) {
ICPPBase specBase = base.clone();
specClass = SemanticUtil.getUltimateType(specClass, false);
if (specClass instanceof IBinding && !(specClass instanceof IProblemBinding)) {
specBase.setBaseClass((IBinding) specClass);
result = ArrayUtil.append(result, specBase);
}
}
}
}
else if (baseType != null) {
ICPPBase specBase = base.clone();
ICPPClassSpecialization specializationContext = specialClass;
IBinding owner = specialClass.getOwner();
if (owner instanceof ICPPClassSpecialization) {
specializationContext = (ICPPClassSpecialization) owner;
}
IType specClass= CPPTemplates.instantiateType(baseType,
new InstantiationContext(tpmap, specializationContext));
specClass = SemanticUtil.getUltimateType(specClass, false);
if (specClass instanceof IBinding && !(specClass instanceof IProblemBinding)) {
specBase.setBaseClass((IBinding) specClass);
}
result = ArrayUtil.append(result, specBase);
}
}
result= ArrayUtil.trim(result);
fBases= result;
return result;
}
} finally {
fComputingBases.set(false);
}
}
return fBases;
}
@SuppressWarnings("unchecked")
private <T extends IBinding> T[] specializeMembers(T[] array) {
if (array == null || array.length == 0)
return array;
T[] newArray= array.clone();
for (int i = 0; i < newArray.length; i++) {
IBinding specializedMember = specialClass.specializeMember(array[i]);
newArray[i]= (T) specializedMember;
}
return newArray;
}
@Override
public ICPPField[] getDeclaredFields() {
ICPPField[] fields= specialClass.getSpecializedBinding().getDeclaredFields();
return specializeMembers(fields);
}
@Override
public ICPPMethod[] getImplicitMethods() {
ICPPClassType origClass = specialClass.getSpecializedBinding();
ICPPMethod[] methods= ClassTypeHelper.getImplicitMethods(origClass);
ICPPMethod[] specializedMembers = specializeMembers(methods);
// Add inherited constructors.
ICPPMethod[] inheritedConstructors = getOwnInheritedConstructors();
return ArrayUtil.addAll(specializedMembers, inheritedConstructors);
}
@Override
public IName getScopeName() {
if (specialClass instanceof ICPPInternalBinding)
return (IASTName) ((ICPPInternalBinding) specialClass).getDefinition();
return null;
}
@Override
public ICPPConstructor[] getConstructors() {
ICPPConstructor[] ctors= specialClass.getSpecializedBinding().getConstructors();
ICPPConstructor[] specializedCtors = specializeMembers(ctors);
// Add inherited constructors.
ICPPMethod[] inheritedConstructors = getOwnInheritedConstructors(specializedCtors);
return ArrayUtil.addAll(specializedCtors, inheritedConstructors);
}
/**
* Returns the inherited constructors that are not specializations of the inherited constructors
* of the specialized class.
*/
private ICPPMethod[] getOwnInheritedConstructors(ICPPConstructor[] existingConstructors) {
if (ownInheritedConstructors == null) {
if (!hasInheritedConstructorsSources())
return ICPPMethod.EMPTY_CPPMETHOD_ARRAY;
IType[][] existingConstructorParamTypes = new IType[existingConstructors.length][];
for (int i = 0; i < existingConstructors.length; i++) {
ICPPParameter[] params = existingConstructors[i].getParameters();
IType[] types = new IType[params.length];
for (int j = 0; j < params.length; j++) {
types[j] = params[j].getType();
}
existingConstructorParamTypes[i] = types;
}
ICPPMethod[] constructors = ClassTypeHelper.getInheritedConstructors(this, getBases(),
existingConstructorParamTypes);
ownInheritedConstructors = constructors;
}
return ownInheritedConstructors;
}
private ICPPMethod[] getOwnInheritedConstructors() {
if (ownInheritedConstructors != null)
return ownInheritedConstructors;
ICPPConstructor[] ctors= specialClass.getSpecializedBinding().getConstructors();
ICPPConstructor[] specializedCtors = specializeMembers(ctors);
return getOwnInheritedConstructors(specializedCtors);
}
private boolean hasInheritedConstructorsSources() {
for (ICPPBase base : getBases()) {
if (base.isInheritedConstructorsSource())
return true;
}
return false;
}
@Override
public ICPPMethod[] getDeclaredMethods() {
ICPPMethod[] bindings = specialClass.getSpecializedBinding().getDeclaredMethods();
return specializeMembers(bindings);
}
@Override
public ICPPClassType[] getNestedClasses() {
ICPPClassType[] bindings = specialClass.getSpecializedBinding().getNestedClasses();
return specializeMembers(bindings);
}
@Override
public ICPPUsingDeclaration[] getUsingDeclarations() {
ICPPUsingDeclaration[] bindings = specialClass.getSpecializedBinding().getUsingDeclarations();
return specializeMembers(bindings);
}
@Override
public IBinding[] getFriends() {
IBinding[] friends = specialClass.getSpecializedBinding().getFriends();
return specializeMembers(friends);
}
@Override
public IScope getParent() throws DOMException {
IBinding binding= specialClass.getOwner();
if (binding instanceof ICPPClassType) {
return ((ICPPClassType) binding).getCompositeScope();
}
if (binding instanceof ICPPNamespace) {
return ((ICPPNamespace) binding).getNamespaceScope();
}
return getOriginalClassType().getScope();
}
@Override
public IBinding[] find(String name, IASTTranslationUnit tu) {
return find(name);
}
@Override
public IBinding[] find(String name) {
return CPPSemantics.findBindings(this, name, false);
}
@Override
public EScopeKind getKind() {
return EScopeKind.eClassType;
}
@Override
public String toString() {
IName name = getScopeName();
return name != null ? name.toString() : String.valueOf(specialClass);
}
// Note: equals() and hashCode() are overridden because multiple instances
// of this class representing the same class specialization scope
// may be created, but scopes are sometimes stored in hash maps
// under the assumption that two objects representing the same
// scope will compare equal().
@Override
public boolean equals(Object other) {
if (other instanceof ICPPClassSpecializationScope) {
return getClassType().equals(((ICPPClassSpecializationScope) other).getClassType());
}
return false;
}
@Override
public int hashCode() {
return specialClass.hashCode();
}
}