blob: 1ea1cdfb9d48d9b9d32ffa1a09d43c19716296b1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2015 Wind River Systems, Inc. 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:
* Markus Schorn - Initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.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 org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IArrayType;
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.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
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.DestructorCallCollector;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalUtil;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecRangeBasedFor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecSimpleDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
/**
* Range based 'for' loop in C++.
*/
public class CPPASTRangeBasedForStatement extends CPPASTAttributeOwner implements ICPPASTRangeBasedForStatement, ICPPExecutionOwner {
private IScope fScope;
private IASTDeclaration fDeclaration;
private IASTInitializerClause fInitClause;
private IASTStatement fBody;
private IASTImplicitName[] fImplicitNames;
private IASTImplicitDestructorName[] fImplicitDestructorNames;
public CPPASTRangeBasedForStatement() {
}
@Override
public CPPASTRangeBasedForStatement copy() {
return copy(CopyStyle.withoutLocations);
}
@Override
public CPPASTRangeBasedForStatement copy(CopyStyle style) {
CPPASTRangeBasedForStatement copy = new CPPASTRangeBasedForStatement();
copy.setDeclaration(fDeclaration == null ? null : fDeclaration.copy(style));
copy.setInitializerClause(fInitClause == null ? null : fInitClause.copy(style));
copy.setBody(fBody == null ? null : fBody.copy(style));
return copy(copy, style);
}
@Override
public IASTDeclaration getDeclaration() {
return fDeclaration;
}
@Override
public void setDeclaration(IASTDeclaration declaration) {
assertNotFrozen();
this.fDeclaration = declaration;
if (declaration != null) {
declaration.setParent(this);
declaration.setPropertyInParent(DECLARATION);
}
}
@Override
public IASTInitializerClause getInitializerClause() {
return fInitClause;
}
@Override
public void setInitializerClause(IASTInitializerClause initClause) {
assertNotFrozen();
fInitClause = initClause;
if (initClause != null) {
initClause.setParent(this);
initClause.setPropertyInParent(INITIALIZER);
}
}
@Override
public IASTStatement getBody() {
return fBody;
}
@Override
public void setBody(IASTStatement statement) {
assertNotFrozen();
fBody = statement;
if (statement != null) {
statement.setParent(this);
statement.setPropertyInParent(BODY);
}
}
@Override
public IScope getScope() {
if (fScope == null)
fScope = new CPPBlockScope(this);
return fScope;
}
@Override
public IASTImplicitName[] getImplicitNames() {
if (fImplicitNames == null) {
IASTInitializerClause forInit = getInitializerClause();
final ASTNode position = (ASTNode) forInit;
if (forInit instanceof IASTExpression) {
final IASTExpression forInitExpr = (IASTExpression) forInit;
IType type= SemanticUtil.getNestedType(forInitExpr.getExpressionType(), TDEF|CVTYPE);
if (type instanceof IArrayType) {
fImplicitNames= IASTImplicitName.EMPTY_NAME_ARRAY;
} else if (type instanceof ICPPClassType) {
ICPPClassType ct= (ICPPClassType) type;
CPPSemantics.pushLookupPoint(this);
try {
if (CPPSemantics.findBindings(ct.getCompositeScope(), CPPVisitor.BEGIN, true, this).length > 0) {
CPPASTName name = new CPPASTName(CPPVisitor.BEGIN);
name.setOffset(position.getOffset());
CPPASTFieldReference fieldRef = new CPPASTFieldReference(name, forInitExpr.copy());
IASTExpression expr= new CPPASTFunctionCallExpression(fieldRef, CPPVisitor.NO_ARGS);
expr.setParent(this);
expr.setPropertyInParent(ICPPASTRangeBasedForStatement.INITIALIZER);
CPPASTImplicitName begin= new CPPASTImplicitName(name.toCharArray(), this);
begin.setBinding(name.resolveBinding());
begin.setOffsetAndLength(position);
name = new CPPASTName(CPPVisitor.END);
name.setOffset(position.getOffset());
fieldRef.setFieldName(name);
CPPASTImplicitName end= new CPPASTImplicitName(name.toCharArray(), this);
end.setBinding(name.resolveBinding());
end.setOffsetAndLength(position);
fImplicitNames= new IASTImplicitName[] {begin, end};
}
} finally {
CPPSemantics.popLookupPoint();
}
}
}
if (fImplicitNames == null) {
CPPASTName name = new CPPASTName(CPPVisitor.BEGIN);
name.setOffset(position.getOffset());
CPPASTIdExpression fname = new CPPASTIdExpression(name);
IASTExpression expr= new CPPASTFunctionCallExpression(fname,
new IASTInitializerClause[] { forInit.copy() });
expr.setParent(this);
expr.setPropertyInParent(ICPPASTRangeBasedForStatement.INITIALIZER);
CPPASTImplicitName begin= new CPPASTImplicitName(name.toCharArray(), this);
begin.setBinding(name.resolveBinding());
begin.setOffsetAndLength(position);
name = new CPPASTName(CPPVisitor.END);
name.setOffset(position.getOffset());
fname.setName(name);
CPPASTImplicitName end= new CPPASTImplicitName(name.toCharArray(), this);
end.setBinding(name.resolveBinding());
end.setOffsetAndLength(position);
fImplicitNames= new IASTImplicitName[] {begin, end};
}
}
return fImplicitNames;
}
@Override
public IASTImplicitDestructorName[] getImplicitDestructorNames() {
if (fImplicitDestructorNames == null) {
fImplicitDestructorNames = DestructorCallCollector.getLocalVariablesDestructorCalls(this);
}
return fImplicitDestructorNames;
}
@Override
public boolean accept(ASTVisitor action) {
if (action.shouldVisitStatements) {
switch (action.visit(this)) {
case ASTVisitor.PROCESS_ABORT: return false;
case ASTVisitor.PROCESS_SKIP: return true;
default: break;
}
}
if (!acceptByAttributeSpecifiers(action)) return false;
if (fDeclaration != null && !fDeclaration.accept(action))
return false;
if (fInitClause != null && !fInitClause.accept(action))
return false;
IASTImplicitName[] implicits = action.shouldVisitImplicitNames ? getImplicitNames() : null;
if (implicits != null) {
for (IASTImplicitName implicit : implicits) {
if (!implicit.accept(action))
return false;
}
}
if (fBody != null && !fBody.accept(action))
return false;
if (action.shouldVisitImplicitDestructorNames && !acceptByNodes(getImplicitDestructorNames(), action))
return false;
if (action.shouldVisitStatements && action.leave(this) == ASTVisitor.PROCESS_ABORT)
return false;
return true;
}
@Override
public void replace(IASTNode child, IASTNode other) {
if (child == fDeclaration) {
setDeclaration((IASTDeclaration) other);
return;
} else if (child == fInitClause) {
setInitializerClause((IASTInitializerClause) other);
return;
} else if (child == fBody) {
setBody((IASTStatement) other);
return;
}
super.replace(child, other);
}
@Override
public ICPPExecution getExecution() {
ExecSimpleDeclaration declarationExec = (ExecSimpleDeclaration)((ICPPExecutionOwner) fDeclaration).getExecution();
ICPPEvaluation initClauseEval = ((ICPPASTInitializerClause) fInitClause).getEvaluation();
ICPPExecution bodyExec = EvalUtil.getExecutionFromStatement(fBody);
IASTImplicitName[] implicitNames = getImplicitNames();
ICPPFunction begin = null;
ICPPFunction end = null;
if (implicitNames.length == 2) {
IBinding beginBinding = implicitNames[0].resolveBinding();
IBinding endBinding = implicitNames[1].resolveBinding();
if (beginBinding instanceof ICPPFunction && endBinding instanceof ICPPFunction) {
begin = (ICPPFunction) beginBinding;
end = (ICPPFunction) endBinding;
}
}
return new ExecRangeBasedFor(declarationExec, initClauseEval, begin, end, bodyExec);
}
}