polyglot.visit
Class InitChecker

java.lang.Object
  extended by polyglot.visit.NodeVisitor
      extended by polyglot.visit.HaltingVisitor
          extended by polyglot.visit.ErrorHandlingVisitor
              extended by polyglot.visit.DataFlow
                  extended by polyglot.visit.InitChecker
All Implemented Interfaces:
java.lang.Cloneable, Copy

public class InitChecker
extends DataFlow

Visitor which checks that all local variables must be defined before use, and that final variables and fields are initialized correctly. The checking of the rules is implemented in the methods leaveCall(Node) and check(FlowGraph, Term, Item, Item).


Nested Class Summary
protected static class InitChecker.ClassBodyInfo
          This class is just a data structure containing relevant information needed for performing initialization checking of a class declaration.
protected static class InitChecker.InitCount
          Class representing the initialization counts of variables.
protected static class InitChecker.MinMaxInitCount
          Class to record counts of the minimum and maximum number of times a variable or field has been initialized or assigned to.
 
Nested classes/interfaces inherited from class polyglot.visit.DataFlow
DataFlow.BoolItem, DataFlow.ConditionNavigator, DataFlow.FlowGraphSource, DataFlow.Item
 
Field Summary
protected static DataFlow.Item BOTTOM
           
protected  InitChecker.ClassBodyInfo currCBI
           
 
Fields inherited from class polyglot.visit.DataFlow
dataflowOnEntry, flowCounter, flowgraphStack, forward
 
Fields inherited from class polyglot.visit.ErrorHandlingVisitor
error, job, nf, ts
 
Constructor Summary
InitChecker(Job job, TypeSystem ts, NodeFactory nf)
           
 
Method Summary
 void check(FlowGraph graph, Term n, DataFlow.Item inItem, java.util.Map outItems)
          Check that the conditions of initialization are not broken.
protected  void checkFieldAssign(FlowGraph graph, FieldAssign a, polyglot.visit.InitChecker.DataFlowItem dfIn, polyglot.visit.InitChecker.DataFlowItem dfOut)
          Check that the assignment to a field is correct.
protected  void checkLocal(FlowGraph graph, Local l, polyglot.visit.InitChecker.DataFlowItem dfIn, polyglot.visit.InitChecker.DataFlowItem dfOut)
          Check that the local variable l is used correctly.
protected  void checkLocalAssign(FlowGraph graph, LocalAssign a, polyglot.visit.InitChecker.DataFlowItem dfIn, polyglot.visit.InitChecker.DataFlowItem dfOut)
          Check that the assignment to a local variable is correct.
protected  void checkLocalsUsedByInnerClass(FlowGraph graph, ClassBody cb, java.util.Set localsUsed, polyglot.visit.InitChecker.DataFlowItem dfIn, polyglot.visit.InitChecker.DataFlowItem dfOut)
          Check that the set of LocalInstances localsUsed, which is the set of locals used in the inner class declared by cb are initialized before the class declaration.
protected  void checkNonStaticFinalFieldsInit(ClassBody cb)
          Check that each non static final field has been initialized exactly once, taking into account the fact that constructors may call other constructors.
protected  void checkStaticFinalFieldsInit(ClassBody cb)
          Check that each static final field is initialized exactly once.
protected  DataFlow.Item confluence(java.util.List items, java.util.List itemKeys, Term node, FlowGraph graph)
          The confluence operator for Initializers and Constructors needs to be a little special, as we are only concerned with non-exceptional flows in these cases.
 DataFlow.Item confluence(java.util.List inItems, Term node, FlowGraph graph)
          The confluence operator is essentially the union of all of the inItems.
 DataFlow.Item createInitialItem(FlowGraph graph, Term node)
          The initial item to be given to the entry point of the dataflow contains the init counts for the final fields.
protected  void dataflow(Expr root)
          Construct a flow graph for the Expr provided, and call dataflow(FlowGraph).
protected  NodeVisitor enterCall(Node n)
          Overridden superclass method.
protected  void finishConstructorDecl(FlowGraph graph, ConstructorDecl cd, polyglot.visit.InitChecker.DataFlowItem dfIn, polyglot.visit.InitChecker.DataFlowItem dfOut)
          Perform necessary actions upon seeing the ConstructorDecl cd.
protected  void finishInitializer(FlowGraph graph, Initializer initializer, polyglot.visit.InitChecker.DataFlowItem dfIn, polyglot.visit.InitChecker.DataFlowItem dfOut)
          Perform necessary actions upon seeing the Initializer initializer.
 java.util.Map flow(DataFlow.Item trueItem, DataFlow.Item falseItem, DataFlow.Item otherItem, FlowGraph graph, Term n, java.util.Set succEdgeKeys)
          Perform the appropriate flow operations for the Terms.
protected  java.util.Map flow(java.util.List inItems, java.util.List inItemKeys, FlowGraph graph, Term n, java.util.Set edgeKeys)
          Produce new Items as appropriate for the Term n and the input Items.
protected  java.util.Map flowConstructorCall(polyglot.visit.InitChecker.DataFlowItem inItem, FlowGraph graph, ConstructorCall cc, java.util.Set succEdgeKeys)
          Perform the appropriate flow operations for a constructor call
protected  java.util.Map flowFieldAssign(polyglot.visit.InitChecker.DataFlowItem inItem, FlowGraph graph, FieldAssign a, java.util.Set succEdgeKeys)
          Perform the appropriate flow operations for assignment to a field
protected  java.util.Map flowFormal(polyglot.visit.InitChecker.DataFlowItem inItem, FlowGraph graph, Formal f, java.util.Set succEdgeKeys)
          Perform the appropriate flow operations for declaration of a formal parameter
protected  java.util.Map flowLocalAssign(polyglot.visit.InitChecker.DataFlowItem inItem, FlowGraph graph, LocalAssign a, java.util.Set succEdgeKeys)
          Perform the appropriate flow operations for assignment to a local variable
protected  java.util.Map flowLocalDecl(polyglot.visit.InitChecker.DataFlowItem inItem, FlowGraph graph, LocalDecl ld, java.util.Set succEdgeKeys)
          Perform the appropriate flow operations for declaration of a local variable
protected  FlowGraph initGraph(CodeDecl code, Term root)
          Initialise the FlowGraph to be used in the dataflow analysis.
protected  boolean isFieldsTargetAppropriate(Field f)
          Determine if we are interested in this field on the basis of the target of the field.
 Node leaveCall(Node n)
          Postpone the checking of constructors until the end of the class declaration is encountered, to ensure that all initializers are processed first.
protected  void setupClassBody(ClassBody n)
           
 
Methods inherited from class polyglot.visit.DataFlow
constructItemsFromCondition, createCFGBuilder, currentFlowGraph, dataflow, dataflow, dumpFlowGraph, filterItems, filterItemsExceptionSubclass, filterItemsNonError, filterItemsNonException, findSCCs, flow, flowBooleanConditions, flowToBooleanFlow, hasTrueFalseBranches, itemsToMap, itemToMap, leave, post, safeConfluence, safeConfluence, safeConfluence
 
Methods inherited from class polyglot.visit.ErrorHandlingVisitor
begin, catchErrors, enter, enterCall, enterError, errorQueue, job, leaveCall, nodeFactory, typeSystem
 
Methods inherited from class polyglot.visit.HaltingVisitor
bypass, bypass, bypassChildren, copy, override, visitChildren
 
Methods inherited from class polyglot.visit.NodeVisitor
enter, finish, finish, leave, override, toString, visitEdge
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

currCBI

protected InitChecker.ClassBodyInfo currCBI

BOTTOM

protected static final DataFlow.Item BOTTOM
Constructor Detail

InitChecker

public InitChecker(Job job,
                   TypeSystem ts,
                   NodeFactory nf)
Method Detail

initGraph

protected FlowGraph initGraph(CodeDecl code,
                              Term root)
Initialise the FlowGraph to be used in the dataflow analysis.

Overrides:
initGraph in class DataFlow
Returns:
null if no dataflow analysis should be performed for this code declaration; otherwise, an apropriately initialized FlowGraph.

enterCall

protected NodeVisitor enterCall(Node n)
                         throws SemanticException
Overridden superclass method. Set up the state that must be tracked during a Class Declaration.

Overrides:
enterCall in class DataFlow
Throws:
SemanticException

leaveCall

public Node leaveCall(Node n)
               throws SemanticException
Postpone the checking of constructors until the end of the class declaration is encountered, to ensure that all initializers are processed first. Also, at the end of the class declaration, check that all static final fields have been initialized at least once, and that for each constructor all non-static final fields must have been initialized at least once, taking into account the constructor calls.

Overrides:
leaveCall in class DataFlow
Throws:
SemanticException

setupClassBody

protected void setupClassBody(ClassBody n)
                       throws SemanticException
Throws:
SemanticException

checkStaticFinalFieldsInit

protected void checkStaticFinalFieldsInit(ClassBody cb)
                                   throws SemanticException
Check that each static final field is initialized exactly once.

Parameters:
cb - The ClassBody of the class declaring the fields to check.
Throws:
SemanticException

checkNonStaticFinalFieldsInit

protected void checkNonStaticFinalFieldsInit(ClassBody cb)
                                      throws SemanticException
Check that each non static final field has been initialized exactly once, taking into account the fact that constructors may call other constructors.

Parameters:
cb - The ClassBody of the class declaring the fields to check.
Throws:
SemanticException

dataflow

protected void dataflow(Expr root)
                 throws SemanticException
Construct a flow graph for the Expr provided, and call dataflow(FlowGraph). Is also responsible for calling post(FlowGraph, Term) after dataflow(FlowGraph) has been called. There is no need to push a CFG onto the stack, as dataflow is not performed on entry in this analysis.

Throws:
SemanticException

createInitialItem

public DataFlow.Item createInitialItem(FlowGraph graph,
                                       Term node)
The initial item to be given to the entry point of the dataflow contains the init counts for the final fields.

Specified by:
createInitialItem in class DataFlow
Returns:
a (possibly null) Item.

confluence

protected DataFlow.Item confluence(java.util.List items,
                                   java.util.List itemKeys,
                                   Term node,
                                   FlowGraph graph)
The confluence operator for Initializers and Constructors needs to be a little special, as we are only concerned with non-exceptional flows in these cases. This method ensures that a slightly different confluence is performed for these Terms, otherwise confluence(List, Term) is called instead.

Overrides:
confluence in class DataFlow
Parameters:
items - List of Items that flow into node. This method will only be called if the list has at least 2 elements.
itemKeys - List of FlowGraph.ExceptionEdgeKeys for the edges that the corresponding Items in items flowed from.
node - Term for which the items are flowing into.
Returns:
a non-null Item.

confluence

public DataFlow.Item confluence(java.util.List inItems,
                                Term node,
                                FlowGraph graph)
The confluence operator is essentially the union of all of the inItems. However, if two or more of the initCount maps from the inItems each have a MinMaxInitCounts entry for the same VarInstance, the conflict must be resolved, by using the minimum of all mins and the maximum of all maxs.

Specified by:
confluence in class DataFlow
Parameters:
inItems - List of Items that flow into node. this method will only be called if the list has at least 2 elements.
node - Term for which the items are flowing into.
Returns:
a non-null Item.

flow

protected java.util.Map flow(java.util.List inItems,
                             java.util.List inItemKeys,
                             FlowGraph graph,
                             Term n,
                             java.util.Set edgeKeys)
Description copied from class: DataFlow
Produce new Items as appropriate for the Term n and the input Items. The default implementation of this method is simply to call confluence for the list of inItems, and pass the result to flow(Item, FlowGraph, Term, Set). Subclasses may want to override this method if a finer grain dataflow is required. Some subclasses may wish to override this method to call flowToBooleanFlow.

Overrides:
flow in class DataFlow
Parameters:
inItems - all the Items flowing into the node.
inItemKeys - the FlowGraph.EdgeKeys for the items in the list inItems
graph - the FlowGraph which the dataflow is operating on
n - the Term which this method must calculate the flow for.
edgeKeys - a set of FlowGraph.EdgeKeys, being all the EdgeKeys of the edges leaving this node. The returned Map must have mappings for all objects in this set.
Returns:
a Map from FlowGraph.EdgeKeys to Items. The map must have entries for all EdgeKeys in edgeKeys.

flow

public java.util.Map flow(DataFlow.Item trueItem,
                          DataFlow.Item falseItem,
                          DataFlow.Item otherItem,
                          FlowGraph graph,
                          Term n,
                          java.util.Set succEdgeKeys)
Perform the appropriate flow operations for the Terms. This method delegates to other appropriate methods in this class, for modularity. To summarize: - Formals: declaration of a Formal param, just insert a new MinMaxInitCount for the LocalInstance. - LocalDecl: a declaration of a local variable, just insert a new MinMaxInitCount for the LocalInstance as appropriate based on whether the declaration has an initializer or not. - Assign: if the LHS of the assign is a local var or a field that we are interested in, then increment the min and max counts for that local var or field.

Overrides:
flow in class DataFlow

flowFormal

protected java.util.Map flowFormal(polyglot.visit.InitChecker.DataFlowItem inItem,
                                   FlowGraph graph,
                                   Formal f,
                                   java.util.Set succEdgeKeys)
Perform the appropriate flow operations for declaration of a formal parameter


flowLocalDecl

protected java.util.Map flowLocalDecl(polyglot.visit.InitChecker.DataFlowItem inItem,
                                      FlowGraph graph,
                                      LocalDecl ld,
                                      java.util.Set succEdgeKeys)
Perform the appropriate flow operations for declaration of a local variable


flowLocalAssign

protected java.util.Map flowLocalAssign(polyglot.visit.InitChecker.DataFlowItem inItem,
                                        FlowGraph graph,
                                        LocalAssign a,
                                        java.util.Set succEdgeKeys)
Perform the appropriate flow operations for assignment to a local variable


flowFieldAssign

protected java.util.Map flowFieldAssign(polyglot.visit.InitChecker.DataFlowItem inItem,
                                        FlowGraph graph,
                                        FieldAssign a,
                                        java.util.Set succEdgeKeys)
Perform the appropriate flow operations for assignment to a field


flowConstructorCall

protected java.util.Map flowConstructorCall(polyglot.visit.InitChecker.DataFlowItem inItem,
                                            FlowGraph graph,
                                            ConstructorCall cc,
                                            java.util.Set succEdgeKeys)
Perform the appropriate flow operations for a constructor call


isFieldsTargetAppropriate

protected boolean isFieldsTargetAppropriate(Field f)
Determine if we are interested in this field on the basis of the target of the field. To wit, if the field is static, then the target of the field must be the current class; if the field is not static then the target must be "this".


check

public void check(FlowGraph graph,
                  Term n,
                  DataFlow.Item inItem,
                  java.util.Map outItems)
           throws SemanticException
Check that the conditions of initialization are not broken. To summarize the conditions: - Local variables must be initialized before use, (i.e. min count > 0) - Final local variables (including Formals) cannot be assigned to more than once (i.e. max count <= 1) - Final non-static fields whose target is this cannot be assigned to more than once - Final static fields whose target is the current class cannot be assigned to more than once This method is also responsible for maintaining state between the dataflows over Initializers, by copying back the appropriate MinMaxInitCounts to the map currClassFinalFieldInitCounts.

Specified by:
check in class DataFlow
Throws:
SemanticException

finishInitializer

protected void finishInitializer(FlowGraph graph,
                                 Initializer initializer,
                                 polyglot.visit.InitChecker.DataFlowItem dfIn,
                                 polyglot.visit.InitChecker.DataFlowItem dfOut)
Perform necessary actions upon seeing the Initializer initializer.


finishConstructorDecl

protected void finishConstructorDecl(FlowGraph graph,
                                     ConstructorDecl cd,
                                     polyglot.visit.InitChecker.DataFlowItem dfIn,
                                     polyglot.visit.InitChecker.DataFlowItem dfOut)
Perform necessary actions upon seeing the ConstructorDecl cd.


checkLocal

protected void checkLocal(FlowGraph graph,
                          Local l,
                          polyglot.visit.InitChecker.DataFlowItem dfIn,
                          polyglot.visit.InitChecker.DataFlowItem dfOut)
                   throws SemanticException
Check that the local variable l is used correctly.

Throws:
SemanticException

checkLocalAssign

protected void checkLocalAssign(FlowGraph graph,
                                LocalAssign a,
                                polyglot.visit.InitChecker.DataFlowItem dfIn,
                                polyglot.visit.InitChecker.DataFlowItem dfOut)
                         throws SemanticException
Check that the assignment to a local variable is correct.

Throws:
SemanticException

checkFieldAssign

protected void checkFieldAssign(FlowGraph graph,
                                FieldAssign a,
                                polyglot.visit.InitChecker.DataFlowItem dfIn,
                                polyglot.visit.InitChecker.DataFlowItem dfOut)
                         throws SemanticException
Check that the assignment to a field is correct.

Throws:
SemanticException

checkLocalsUsedByInnerClass

protected void checkLocalsUsedByInnerClass(FlowGraph graph,
                                           ClassBody cb,
                                           java.util.Set localsUsed,
                                           polyglot.visit.InitChecker.DataFlowItem dfIn,
                                           polyglot.visit.InitChecker.DataFlowItem dfOut)
                                    throws SemanticException
Check that the set of LocalInstances localsUsed, which is the set of locals used in the inner class declared by cb are initialized before the class declaration.

Throws:
SemanticException