blob: 77aadcda2b9a882e157cfa666b3755d054049fc5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2011 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)
*******************************************************************************/
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.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.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
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.ICPPParameterPackType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
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 {
final private ICPPClassSpecialization specialClass;
private volatile ICPPBase[] fBases; // Used by the pdom bindings, needs to be volatile.
public AbstractCPPClassSpecializationScope(ICPPClassSpecialization specialization) {
this.specialClass= specialization;
}
public ICPPClassType getOriginalClassType() {
return specialClass.getSpecializedBinding();
}
public final IBinding getBinding(IASTName name, boolean resolve) {
return getBinding(name, resolve, IIndexFileSet.EMPTY);
}
public final IBinding[] getBindings(IASTName name, boolean resolve, boolean prefix) {
return getBindings(name, resolve, prefix, IIndexFileSet.EMPTY);
}
public IBinding getBinding(IASTName name, boolean forceResolve, 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(name, forceResolve, false) : null;
if (bindings == null)
return null;
IBinding[] specs = new IBinding[0];
for (IBinding binding : bindings) {
specs = (IBinding[]) ArrayUtil.append(IBinding.class, specs, specialClass.specializeMember(binding));
}
specs = (IBinding[]) ArrayUtil.trim(IBinding.class, specs);
return CPPSemantics.resolveAmbiguities(name, specs);
}
final public IBinding[] getBindings(IASTName name, boolean forceResolve, boolean prefixLookup,
IIndexFileSet fileSet) {
return getBindings(name, forceResolve, prefixLookup, fileSet, true);
}
public IBinding[] getBindings(IASTName name, boolean forceResolve, boolean prefixLookup,
IIndexFileSet fileSet, boolean checkPointOfDecl) {
ICPPClassType specialized = specialClass.getSpecializedBinding();
IScope classScope = specialized.getCompositeScope();
if (classScope == null)
return IBinding.EMPTY_BINDING_ARRAY;
IBinding[] bindings;
if (classScope instanceof ICPPASTInternalScope) {
bindings= ((ICPPASTInternalScope) classScope).getBindings(name, forceResolve, prefixLookup, fileSet, checkPointOfDecl);
} else {
bindings= classScope.getBindings(name, forceResolve, prefixLookup, fileSet);
}
IBinding[] result= null;
for (IBinding binding : bindings) {
if (binding == specialized) {
binding= specialClass;
} else {
binding= specialClass.specializeMember(binding);
}
result = (IBinding[]) ArrayUtil.append(IBinding.class, result, binding);
}
return (IBinding[]) ArrayUtil.trim(IBinding.class, result);
}
public ICPPClassSpecialization getClassType() {
return specialClass;
}
public ICPPBase[] getBases() {
if (fBases == null) {
ICPPBase[] result = null;
ICPPBase[] bases = specialClass.getSpecializedBinding().getBases();
if (bases.length == 0) {
fBases= bases;
} else {
final ICPPTemplateParameterMap tpmap = specialClass.getTemplateParameterMap();
for (ICPPBase base : bases) {
IBinding origClass = base.getBaseClass();
if (origClass instanceof ICPPTemplateParameter && ((ICPPTemplateParameter) origClass).isParameterPack()) {
IType[] specClasses= CPPTemplates.instantiateTypes(new IType[]{new CPPParameterPackType((IType) origClass)}, tpmap, -1, specialClass);
if (specClasses.length == 1 && specClasses[0] instanceof ICPPParameterPackType) {
result= (ICPPBase[]) ArrayUtil.append(ICPPBase.class, 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 = (ICPPBase[]) ArrayUtil.append(ICPPBase.class, result, specBase);
}
}
}
continue;
}
if (origClass instanceof IType) {
ICPPBase specBase = base.clone();
IType specClass= CPPTemplates.instantiateType((IType) origClass, tpmap, -1, specialClass);
specClass = SemanticUtil.getUltimateType(specClass, false);
if (specClass instanceof IBinding && !(specClass instanceof IProblemBinding)) {
specBase.setBaseClass((IBinding) specClass);
}
result = (ICPPBase[]) ArrayUtil.append(ICPPBase.class, result, specBase);
}
}
result= (ICPPBase[]) ArrayUtil.trim(ICPPBase.class, result);
fBases= result;
return result;
}
}
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++) {
newArray[i]= (T) specialClass.specializeMember(array[i]);
}
return newArray;
}
public ICPPField[] getDeclaredFields() {
ICPPField[] fields= specialClass.getSpecializedBinding().getDeclaredFields();
return specializeMembers(fields);
}
public ICPPMethod[] getImplicitMethods() {
ICPPClassScope origClassScope= (ICPPClassScope) specialClass.getSpecializedBinding().getCompositeScope();
if (origClassScope == null) {
return ICPPMethod.EMPTY_CPPMETHOD_ARRAY;
}
ICPPMethod[] methods= origClassScope.getImplicitMethods();
return specializeMembers(methods);
}
public IName getScopeName() {
if (specialClass instanceof ICPPInternalBinding)
return (IASTName) ((ICPPInternalBinding) specialClass).getDefinition();
return null;
}
public ICPPConstructor[] getConstructors() {
ICPPConstructor[] ctors= specialClass.getSpecializedBinding().getConstructors();
return specializeMembers(ctors);
}
public ICPPMethod[] getDeclaredMethods() {
ICPPMethod[] bindings = specialClass.getSpecializedBinding().getDeclaredMethods();
return specializeMembers(bindings);
}
public ICPPClassType[] getNestedClasses() {
ICPPClassType[] bindings = specialClass.getSpecializedBinding().getNestedClasses();
return specializeMembers(bindings);
}
public IBinding[] getFriends() {
// not yet supported
return IBinding.EMPTY_BINDING_ARRAY;
}
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();
}
public IBinding[] find(String name) {
return CPPSemantics.findBindings(this, name, false);
}
@Override
public String toString() {
IName name = getScopeName();
return name != null ? name.toString() : String.valueOf(specialClass);
}
public EScopeKind getKind() {
return EScopeKind.eClassType;
}
}