/*******************************************************************************
* Copyright (c) 2004, 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:
* John Camelon (IBM) - Initial API and implementation
* Bryan Wilkinson (QNX)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.glvalueType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.prvalueType;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICPPASTCompletionContext;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
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.ICPPTemplateNonTypeParameter;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPFunctionSet;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
public class CPPASTIdExpression extends ASTNode implements IASTIdExpression, ICPPASTCompletionContext {
private static final ICPPASTFieldReference NOT_INITIALIZED = new CPPASTFieldReference();
private IASTName name;
private ICPPASTFieldReference fTransformedExpression= NOT_INITIALIZED;
public CPPASTIdExpression() {
}
public CPPASTIdExpression(IASTName name) {
setName(name);
}
public CPPASTIdExpression copy() {
return copy(CopyStyle.withoutLocations);
}
public CPPASTIdExpression copy(CopyStyle style) {
CPPASTIdExpression copy = new CPPASTIdExpression(name == null ? null : name.copy());
copy.setOffsetAndLength(this);
if (style == CopyStyle.withLocations) {
copy.setCopyLocation(this);
}
return copy;
}
public IASTName getName() {
return name;
}
public void setName(IASTName name) {
assertNotFrozen();
this.name = name;
if (name != null) {
name.setParent(this);
name.setPropertyInParent(ID_NAME);
}
}
@Override
public boolean accept(ASTVisitor action) {
if (action.shouldVisitExpressions) {
switch (action.visit(this)) {
case ASTVisitor.PROCESS_ABORT: return false;
case ASTVisitor.PROCESS_SKIP: return true;
default: break;
}
}
if (name != null && !name.accept(action)) return false;
if (action.shouldVisitExpressions) {
switch (action.leave(this)) {
case ASTVisitor.PROCESS_ABORT: return false;
case ASTVisitor.PROCESS_SKIP: return true;
default: break;
}
}
return true;
}
public int getRoleForName(IASTName n) {
if (name == n) return r_reference;
return r_unclear;
}
public IType getExpressionType() {
IBinding binding = name.resolvePreBinding();
if (binding instanceof CPPFunctionSet)
binding= name.resolveBinding();
if (checkForTransformation(binding)) {
return fTransformedExpression.getExpressionType();
}
try {
if (binding instanceof IProblemBinding) {
return new ProblemType(ISemanticProblem.TYPE_UNRESOLVED_NAME);
}
if (binding instanceof IType || binding instanceof ICPPConstructor) {
return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION);
}
if (binding instanceof IEnumerator) {
IType type= ((IEnumerator) binding).getType();
if (type instanceof ICPPEnumeration) {
ICPPEnumeration enumType= (ICPPEnumeration) type;
if (enumType.asScope() == CPPVisitor.getContainingScope(this)) {
// C++0x: 7.2-5
IType fixedType= enumType.getFixedType();
if (fixedType != null)
return fixedType;
// This is a simplification, the actual type is determined
// - in an implementation dependent manner - by the value
// of the enumerator.
return CPPSemantics.INT_TYPE;
}
}
return type;
}
if (binding instanceof IVariable) {
final IType t = glvalueType(((IVariable) binding).getType());
return SemanticUtil.mapToAST(t, this);
}
if (binding instanceof IFunction) {
return SemanticUtil.mapToAST(((IFunction) binding).getType(), this);
}
if (binding instanceof ICPPTemplateNonTypeParameter) {
return prvalueType(((ICPPTemplateNonTypeParameter) binding).getType());
}
if (binding instanceof ICPPUnknownBinding) {
// mstodo typeof unknown binding
return CPPUnknownClass.createUnnamedInstance();
}
} catch (DOMException e) {
return e.getProblem();
}
return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION);
}
/**
* 9.3.1-3 Transformation to class member access within the definition of a non-static
* member function.
*/
public boolean checkForTransformation(IBinding binding) {
if (fTransformedExpression == NOT_INITIALIZED) {
fTransformedExpression= null;
if (name instanceof ICPPASTQualifiedName) {
IASTNode parent= name.getParent();
if (parent instanceof ICPPASTUnaryExpression) {
if (((ICPPASTUnaryExpression) parent).getOperator() == IASTUnaryExpression.op_amper) {
return false;
}
}
}
if (binding instanceof ICPPMember && !(binding instanceof IType) && !(binding instanceof ICPPConstructor)
&&!((ICPPMember) binding).isStatic()) {
IASTNode parent= getParent();
while (parent != null && !(parent instanceof ICPPASTFunctionDefinition)) {
parent= parent.getParent();
}
if (parent instanceof ICPPASTFunctionDefinition) {
ICPPASTFunctionDefinition fdef= (ICPPASTFunctionDefinition) parent;
final IBinding methodBinding = fdef.getDeclarator().getName().resolvePreBinding();
if (methodBinding instanceof ICPPMethod && !((ICPPMethod) methodBinding).isStatic()) {
IASTName nameDummy= new CPPASTName();
nameDummy.setBinding(binding);
IASTExpression owner= new CPPASTLiteralExpression(IASTLiteralExpression.lk_this,
CharArrayUtils.EMPTY);
owner= new CPPASTUnaryExpression(IASTUnaryExpression.op_star, owner);
fTransformedExpression= new CPPASTFieldReference(nameDummy, owner);
fTransformedExpression.setParent(getParent());
fTransformedExpression.setPropertyInParent(getPropertyInParent());
}
}
}
}
return fTransformedExpression != null;
}
public boolean isLValue() {
return getValueCategory() == LVALUE;
}
public ValueCategory getValueCategory() {
IBinding binding = name.resolvePreBinding();
if (checkForTransformation(binding)) {
return fTransformedExpression.getValueCategory();
}
if (binding instanceof ICPPTemplateNonTypeParameter)
return ValueCategory.PRVALUE;
if (binding instanceof IVariable || binding instanceof IFunction) {
return ValueCategory.LVALUE;
}
return ValueCategory.PRVALUE;
}
public IBinding[] findBindings(IASTName n, boolean isPrefix, String[] namespaces) {
return CPPSemantics.findBindingsForContentAssist(n, isPrefix, namespaces);
}
@Override
public String toString() {
return name != null ? name.toString() : "<unnamed>"; //$NON-NLS-1$
}
public IBinding[] findBindings(IASTName n, boolean isPrefix) {
return findBindings(n, isPrefix, null);
}
}