com.redhat.ceylon.compiler.java.codegen.DefiniteAssignmentVisitor Maven / Gradle / Ivy
package com.redhat.ceylon.compiler.java.codegen;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.model.typechecker.model.ControlBlock;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Value;
/**
* Visitor which adds information to the model needed for handling
* Values declared before a for/else loop, but whose value is specified
* within the loop.
* See #1227.
*/
public class DefiniteAssignmentVisitor extends Visitor {
private ControlBlock forBlock = null;
private ControlBlock elseBlock = null;
private HashMap tracked = new HashMap();
public void visit(Tree.AnyMethod that) {
ControlBlock prevControlBlock = forBlock;
forBlock = null;
super.visit(that);
forBlock = prevControlBlock;
}
public void visit(Tree.AnyAttribute that) {
ControlBlock prevControlBlock = forBlock;
forBlock = null;
super.visit(that);
forBlock = prevControlBlock;
}
public void visit(Tree.AnyClass that) {
ControlBlock prevControlBlock = forBlock;
forBlock = null;
super.visit(that);
forBlock = prevControlBlock;
}
public void visit(Tree.AttributeDeclaration that) {
// We're interested in non-variable, deferred AttributeDeclarations
// that are declared outside a for/else loop, but specified inside it
if (that.getSpecifierOrInitializerExpression() == null
&& !that.getDeclarationModel().isVariable()
&& !that.getDeclarationModel().isLate()) {
tracked.put(that.getDeclarationModel(), forBlock);
}
}
public void visit(Tree.SpecifierStatement stmt) {
Tree.Term bme = stmt.getBaseMemberExpression();
if (bme instanceof Tree.MemberOrTypeExpression) {
Declaration decl = ((Tree.MemberOrTypeExpression)bme).getDeclaration();
if (tracked.containsKey(decl) // non-variable and deferred
&& forBlock != null // specification is in a for/else
&& !forBlock.equals(tracked.get(decl))) { // not declared in *this* for/else
if (elseBlock == null) {
((Value)decl).setSpecifiedInForElse(true);
}
ControlBlock assigningBlock = elseBlock != null ? elseBlock : forBlock;
addSpecified(decl, assigningBlock);
}
}
super.visit(stmt);
}
protected void addSpecified(Declaration decl, ControlBlock assigningBlock) {
Set assigned = assigningBlock.getSpecifiedValues();
if (assigned == null) {
assigned = new HashSet(1);
assigningBlock.setSpecifiedValues(assigned);
}
assigned.add((Value)decl);
}
public void visit(Tree.ForStatement that) {
ControlBlock prevControlBlock = forBlock;
forBlock = that.getForClause().getControlBlock();
that.getForClause().visit(this);
if (that.getElseClause() != null) {
elseBlock = that.getElseClause().getControlBlock();
that.getElseClause().visit(this);
elseBlock = null;
}
if (prevControlBlock != null) {
Set specifiedValues = forBlock.getSpecifiedValues();
if (specifiedValues != null) {
for (Declaration decl : new ArrayList(specifiedValues)) {
if (!prevControlBlock.equals(tracked.get(decl))) {
addSpecified(decl, prevControlBlock);
specifiedValues.remove(decl);
}
}
}
}
forBlock = prevControlBlock;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy