blob: 155bb20913aba9cec3fd3bd9aab8dbe89ba52a31 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2010 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:
* Andrew Niefer (IBM Corporation) - initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* 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.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
/**
* Models the scope represented by an unknown type (e.g.: typeof(template type parameter)).
* Used within the context of templates, only. For safe usage in index bindings, all fields need
* to be final or used in a thread-safe manner otherwise.
*/
public class CPPUnknownTypeScope implements ICPPInternalUnknownScope {
private final IASTName fName;
private final IType fScopeType;
/**
* This field needs to be protected when used in PDOMCPPUnknownScope,
* don't use it outside of {@link #getOrCreateBinding(IASTName, int)}
*/
private CharArrayObjectMap<IBinding[]> map;
public CPPUnknownTypeScope(IType scopeType, IASTName name) {
fName= name;
fScopeType= scopeType;
}
@Override
public EScopeKind getKind() {
return EScopeKind.eClassType;
}
@Override
public IASTNode getPhysicalNode() {
return fName;
}
@Override
public IName getScopeName() {
return fName;
}
@Override
public IType getScopeType() {
return fScopeType;
}
@Override
public IScope getParent() throws DOMException {
if (fScopeType instanceof IBinding)
return ((IBinding) fScopeType).getScope();
return null;
}
@Override
public IBinding[] find(String name) {
return IBinding.EMPTY_BINDING_ARRAY;
}
@Override
public final IBinding getBinding(IASTName name, boolean resolve) {
return getBinding(name, resolve, IIndexFileSet.EMPTY);
}
@Override
public IBinding getBinding(final IASTName name, boolean resolve, IIndexFileSet fileSet) {
boolean type= false;
boolean function= false;
if (name.getPropertyInParent() == null) {
type= true;
} else {
IASTName n= name;
IASTNode parent= name.getParent();
if (parent instanceof ICPPASTTemplateId) {
n= (IASTName) parent;
parent= n.getParent();
}
if (parent instanceof ICPPASTQualifiedName) {
ICPPASTQualifiedName qname= (ICPPASTQualifiedName) parent;
if (qname.getLastName() != n) {
type= true;
} else {
parent= qname.getParent();
}
}
if (!type) {
if (parent instanceof ICPPASTBaseSpecifier ||
parent instanceof ICPPASTConstructorChainInitializer) {
type= true;
} else if (parent instanceof ICPPASTNamedTypeSpecifier) {
ICPPASTNamedTypeSpecifier nts= (ICPPASTNamedTypeSpecifier) parent;
type= nts.isTypename();
} else if (parent instanceof ICPPASTUsingDeclaration) {
ICPPASTUsingDeclaration ud= (ICPPASTUsingDeclaration) parent;
type= ud.isTypename();
function= true;
}
if (!type && parent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) {
function= true;
}
}
}
int idx= type ? 0 : function ? 1 : 2;
IBinding result = getOrCreateBinding(name.getSimpleID(), idx);
return result;
}
@Override @Deprecated
public final IBinding[] getBindings(IASTName name, boolean resolve, boolean prefix) {
return getBindings(name, resolve, prefix, IIndexFileSet.EMPTY);
}
@Override @Deprecated
public final IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup, IIndexFileSet fileSet) {
return getBindings(new ScopeLookupData(name, resolve, prefixLookup));
}
@Override
public final IBinding[] getBindings(ScopeLookupData lookup) {
if (lookup.isPrefixLookup()) {
// If name lookup is performed for the purpose of code completion in a dependent context,
// try to give some useful results heuristically.
IScope scope = CPPSemantics.heuristicallyFindConcreteScopeForType(fScopeType,
lookup.getLookupPoint());
if (scope != null) {
return scope.getBindings(lookup);
}
return IBinding.EMPTY_BINDING_ARRAY;
}
IASTName lookupName= lookup.getLookupName();
if (lookupName != null)
return new IBinding[] { getBinding(lookupName, lookup.isResolve(), lookup.getIncludedFiles()) };
// When dealing with dependent expressions we always create an unknown class. That is because
// unknown objects are not used within the expressions, they are attached to names only.
return new IBinding[] { getOrCreateBinding(lookup.getLookupKey(), 0) };
}
@Override
public String toString() {
return fName.toString();
}
@Override
public void addName(IASTName name) {
}
protected IBinding getOrCreateBinding(final char[] name, int idx) {
if (map == null)
map = new CharArrayObjectMap<>(2);
IBinding[] o = map.get(name);
if (o == null) {
o = new IBinding[3];
map.put(name, o);
}
IBinding result= o[idx];
if (result == null) {
switch (idx) {
case 0:
result= new CPPUnknownMemberClass(fScopeType, name);
break;
case 1:
result= new CPPUnknownMethod(fScopeType, name);
break;
case 2:
result= new CPPUnknownField(fScopeType, name);
break;
}
o[idx]= result;
}
return result;
}
@Override
public void addBinding(IBinding binding) {
// Do nothing, this is part of template magic and not a normal scope.
}
@Override
public void populateCache() {}
@Override
public void removeNestedFromCache(IASTNode container) {}
}