All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.org.eclipse.jdt.internal.compiler.ast.YieldStatement Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2019 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.compiler.ast;

import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.aspectj.org.eclipse.jdt.internal.compiler.flow.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;

public class YieldStatement extends BranchStatement {

	public Expression expression;
	public SwitchExpression switchExpression;
	public TryStatement tryStatement;
	/**
	 * @noreference This field is not intended to be referenced by clients.
	 */
	public boolean isImplicit;
	static final char[] SECRET_YIELD_RESULT_VALUE_NAME = " secretYieldValue".toCharArray(); //$NON-NLS-1$
	private LocalVariableBinding secretYieldResultValue = null;

public YieldStatement(Expression exp, int sourceStart, int sourceEnd) {
	super(null, sourceStart, sourceEnd);
	this.expression = exp;
}
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
	// this.switchExpression != null && this.expression != null true here.

	// here requires to generate a sequence of finally blocks invocations depending corresponding
	// to each of the traversed try statements, so that execution will terminate properly.


	// lookup the null label, this should answer the returnContext - for implicit yields, the nesting
	// doesn't occur since it immediately follow '->' and hence identical to default break - ie the
	// immediate breakable context is guaranteed to be the one intended;
	// while explicit yield should move up the parent to the switch expression.
	FlowContext targetContext = flowContext.getTargetContextForYield(!this.isImplicit);

	flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo);
	this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo);
	if (flowInfo.reachMode() == FlowInfo.REACHABLE && currentScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled)
		checkAgainstNullAnnotation(currentScope, flowContext, flowInfo, this.expression);

	targetContext.recordAbruptExit();
	targetContext.expireNullCheckedFieldInfo();

	this.initStateIndex =
		currentScope.methodScope().recordInitializationStates(flowInfo);

	this.targetLabel = targetContext.breakLabel();
	FlowContext traversedContext = flowContext;
	int subCount = 0;
	this.subroutines = new SubRoutineStatement[5];

	do {
		SubRoutineStatement sub;
		if ((sub = traversedContext.subroutine()) != null) {
			if (subCount == this.subroutines.length) {
				System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount*2]), 0, subCount); // grow
			}
			this.subroutines[subCount++] = sub;
			if (sub.isSubRoutineEscaping()) {
				break;
			}
		}
		traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
		traversedContext.recordBreakTo(targetContext);

		if (traversedContext instanceof InsideSubRoutineFlowContext) {
			ASTNode node = traversedContext.associatedNode;
			if (node instanceof TryStatement) {
				flowInfo.addInitializationsFrom(((TryStatement) node).subRoutineInits); // collect inits
			}
		} else if (traversedContext == targetContext) {
			// only record break info once accumulated through subroutines, and only against target context
			targetContext.recordBreakFrom(flowInfo);
			break;
		}
	} while ((traversedContext = traversedContext.getLocalParent()) != null);

	// resize subroutines
	if (subCount != this.subroutines.length) {
		System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount);
	}
	return FlowInfo.DEAD_END;
}
@Override
protected void setSubroutineSwitchExpression(SubRoutineStatement sub) {
	sub.setSwitchExpression(this.switchExpression);
}
protected void addSecretYieldResultValue(BlockScope scope) {
	SwitchExpression se = this.switchExpression;
	if (se == null || !se.containsTry)
		return;
	LocalVariableBinding local = new LocalVariableBinding(
			YieldStatement.SECRET_YIELD_RESULT_VALUE_NAME,
			se.resolvedType,
			ClassFileConstants.AccDefault,
			false);
	local.setConstant(Constant.NotAConstant);
	local.useFlag = LocalVariableBinding.USED;
	local.declaration = new LocalDeclaration(YieldStatement.SECRET_YIELD_RESULT_VALUE_NAME, 0, 0);
	assert se.yieldResolvedPosition >= 0;
	local.resolvedPosition = se.yieldResolvedPosition;
	assert local.resolvedPosition < scope.maxOffset;
	scope.addLocalVariable(local);
	this.secretYieldResultValue = local;
}

@Override
protected void restartExceptionLabels(CodeStream codeStream) {
	SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream);
}
protected void generateExpressionResultCodeExpanded(BlockScope currentScope, CodeStream codeStream) {
	SwitchExpression se = this.switchExpression;
	addSecretYieldResultValue(currentScope);
	assert this.secretYieldResultValue != null;
	codeStream.record(this.secretYieldResultValue);
	SingleNameReference lhs = new SingleNameReference(this.secretYieldResultValue.name, 0);
	lhs.binding = this.secretYieldResultValue;
	lhs.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
	lhs.bits |= Binding.LOCAL;
	lhs.bits |= ASTNode.IsSecretYieldValueUsage;
	((LocalVariableBinding) lhs.binding).markReferenced(); // TODO : Can be skipped?
	Assignment assignment = new Assignment(lhs, this.expression, 0);
	assignment.generateCode(currentScope, codeStream);

	int pc = codeStream.position;
	// generation of code responsible for invoking the finally
	// blocks in sequence
	if (this.subroutines != null){
		for (int i = 0, max = this.subroutines.length; i < max; i++){
			SubRoutineStatement sub = this.subroutines[i];
			SwitchExpression se1 = sub.getSwitchExpression();
			setSubroutineSwitchExpression(sub);
			boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null);
			sub.setSwitchExpression(se1);
			if (didEscape) {
				codeStream.removeVariable(this.secretYieldResultValue);
					codeStream.recordPositionsFrom(pc, this.sourceStart);
					SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream);
					if (this.initStateIndex != -1) {
						codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex);
						codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex);
					}
					restartExceptionLabels(codeStream);
					return;
			}
		}
	}
	se.loadStoredTypesAndKeep(codeStream);
	codeStream.load(this.secretYieldResultValue);
	codeStream.removeVariable(this.secretYieldResultValue);

	codeStream.goto_(this.targetLabel);
	codeStream.recordPositionsFrom(pc, this.sourceStart);
	SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream);
	if (this.initStateIndex != -1) {
		codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex);
		codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex);
	}
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
	if ((this.bits & ASTNode.IsReachable) == 0) {
		return;
	}
	if (this.switchExpression != null && this.switchExpression.containsTry && this.switchExpression.resolvedType != null ) {
		generateExpressionResultCodeExpanded(currentScope, codeStream);
		return;
	}
	this.expression.generateCode(currentScope, codeStream, this.switchExpression != null);
	int pc = codeStream.position;

	// generation of code responsible for invoking the finally
	// blocks in sequence
	if (this.subroutines != null){
		for (int i = 0, max = this.subroutines.length; i < max; i++){
			SubRoutineStatement sub = this.subroutines[i];
			SwitchExpression se = sub.getSwitchExpression();
			setSubroutineSwitchExpression(sub);
			boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null);
			sub.setSwitchExpression(se);
			if (didEscape) {
					codeStream.recordPositionsFrom(pc, this.sourceStart);
					SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream);
					if (this.initStateIndex != -1) {
						codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex);
						codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex);
					}
					restartExceptionLabels(codeStream);
					return;
			}
		}
	}
	codeStream.goto_(this.targetLabel);
	codeStream.recordPositionsFrom(pc, this.sourceStart);
	SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream);
	if (this.initStateIndex != -1) {
		codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex);
		codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex);
	}
}
@Override
public void resolve(BlockScope scope) {
	super.resolve(scope);
	if (this.expression == null) {
		return;

	}
	if (this.switchExpression != null || this.isImplicit) {
		if (this.switchExpression == null && this.isImplicit && !this.expression.statementExpression()) {
			if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) {
				/* JLS 13 14.11.2
				Switch labeled rules in switch statements differ from those in switch expressions (15.28).
				In switch statements they must be switch labeled statement expressions, ... */
				scope.problemReporter().invalidExpressionAsStatement(this.expression);
				return;
			}
		}
	} else {
		if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) {
			scope.problemReporter().switchExpressionsYieldOutsideSwitchExpression(this);
		}
	}
	TypeBinding type = this.expression.resolveType(scope);
	if (this.switchExpression != null && type != null)
		this.switchExpression.originalTypeMap.put(this.expression, type);
}

@Override
public TypeBinding resolveExpressionType(BlockScope scope1) {
	return this.expression != null ? this.expression.resolveType(scope1) : null;
}

@Override
public StringBuilder printStatement(int tab, StringBuilder output) {
	if (!this.isImplicit)
		printIndent(tab, output).append("yield"); //$NON-NLS-1$
	if (this.expression != null) {
		if (this.isImplicit) {
			this.expression.print(tab, output);
		} else {
			output.append(' ');
			this.expression.printExpression(tab, output);
		}
	}
	return output.append(';');
}

@Override
public void traverse(ASTVisitor visitor, BlockScope blockscope) {
	if (visitor.visit(this, blockscope)) {
		if (this.expression != null)
			this.expression.traverse(visitor, blockscope);
	}
	visitor.endVisit(this, blockscope);
}
@Override
public boolean doesNotCompleteNormally() {
	return true;
}

@Override
public boolean canCompleteNormally() {
	return false;
}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy