View Javadoc

    1   /**
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.lang.dfa;
    5
    6   import java.util.ArrayList;
    7   import java.util.BitSet;
    8   import java.util.HashMap;
    9   import java.util.List;
    10  import java.util.Map;
    11  import java.util.StringTokenizer;
    12
    13  import net.sourceforge.pmd.lang.ast.Node;
    14
    15  /**
    16   * @author raik
    17   *         <p/>
    18   *         Each data flow contains a set of DataFlowNodes.
    19   */
    20  public abstract class AbstractDataFlowNode implements DataFlowNode {
    21
    22      protected Node node;
    23      protected Map<Integer, String> typeMap = new HashMap<Integer, String>();
    24
    25      protected List<DataFlowNode> parents = new ArrayList<DataFlowNode>();
    26      protected List<DataFlowNode> children = new ArrayList<DataFlowNode>();
    27      protected BitSet type = new BitSet();
    28      protected List<VariableAccess> variableAccess = new ArrayList<VariableAccess>();
    29      protected List<DataFlowNode> dataFlow;
    30      protected int line;
    31
    32      public AbstractDataFlowNode(List<DataFlowNode> dataFlow) {
    33  	this.dataFlow = dataFlow;
    34  	if (!this.dataFlow.isEmpty()) {
    35  	    DataFlowNode parent = this.dataFlow.get(this.dataFlow.size() - 1);
    36  	    parent.addPathToChild(this);
    37  	}
    38  	this.dataFlow.add(this);
    39      }
    40
    41      public AbstractDataFlowNode(List<DataFlowNode> dataFlow, Node node) {
    42  	this(dataFlow);
    43
    44  	this.node = node;
    45  	node.setDataFlowNode(this);
    46  	this.line = node.getBeginLine();
    47      }
    48
    49      public void addPathToChild(DataFlowNode child) {
    50  	DataFlowNode thisChild = child;
    51  	// TODO - throw an exception if already contained in children list?
    52  	if (!this.children.contains(thisChild) || this.equals(thisChild)) {
    53  	    this.children.add(thisChild);
    54  	    thisChild.getParents().add(this);
    55  	}
    56      }
    57
    58      public boolean removePathToChild(DataFlowNode child) {
    59  	DataFlowNode thisChild = child;
    60  	thisChild.getParents().remove(this);
    61  	return this.children.remove(thisChild);
    62      }
    63
    64      public void reverseParentPathsTo(DataFlowNode destination) {
    65  	while (!parents.isEmpty()) {
    66  	    DataFlowNode parent = parents.get(0);
    67  	    parent.removePathToChild(this);
    68  	    parent.addPathToChild(destination);
    69  	}
    70      }
    71
    72      public int getLine() {
    73  	return this.line;
    74      }
    75
    76      public void setType(int type) {
    77  	this.type.set(type);
    78      }
    79
    80      public boolean isType(int intype) {
    81  	try {
    82  	    return type.get(intype);
    83  	} catch (IndexOutOfBoundsException e) {
    84  	    e.printStackTrace();
    85  	}
    86  	return false;
    87      }
    88
    89      public Node getNode() {
    90  	return this.node;
    91      }
    92
    93      public List<DataFlowNode> getChildren() {
    94  	return this.children;
    95      }
    96
    97      public List<DataFlowNode> getParents() {
    98  	return this.parents;
    99      }
    100
    101     public List<DataFlowNode> getFlow() {
    102 	return this.dataFlow;
    103     }
    104
    105     public int getIndex() {
    106 	return this.dataFlow.indexOf(this);
    107     }
    108
    109     public void setVariableAccess(List<VariableAccess> variableAccess) {
    110 	if (this.variableAccess.isEmpty()) {
    111 	    this.variableAccess = variableAccess;
    112 	} else {
    113 	    this.variableAccess.addAll(variableAccess);
    114 	}
    115     }
    116
    117     public List<VariableAccess> getVariableAccess() {
    118 	return this.variableAccess;
    119     }
    120
    121     @Override
    122     public String toString() {
    123 	String res = "DataFlowNode: line " + this.getLine() + ", ";
    124 	String tmp = type.toString();
    125 	String newTmp = "";
    126 	for (char c : tmp.toCharArray()) {
    127 	    if (c != '{' && c != '}' && c != ' ') {
    128 		newTmp += c;
    129 	    }
    130 	}
    131 	for (StringTokenizer st = new StringTokenizer(newTmp, ","); st.hasMoreTokens();) {
    132 	    int newTmpInt = Integer.parseInt(st.nextToken());
    133 	    res += "(" + stringFromType(newTmpInt) + ")";
    134 	}
    135 	res += ", " + this.node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.') + 1);
    136 	res += node.getImage() == null ? "" : "(" + this.node.getImage() + ")";
    137 	return res;
    138     }
    139
    140     private String stringFromType(int intype) {
    141 	if (typeMap.isEmpty()) {
    142 	    typeMap.put(NodeType.IF_EXPR, "IF_EXPR");
    143 	    typeMap.put(NodeType.IF_LAST_STATEMENT, "IF_LAST_STATEMENT");
    144 	    typeMap.put(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, "IF_LAST_STATEMENT_WITHOUT_ELSE");
    145 	    typeMap.put(NodeType.ELSE_LAST_STATEMENT, "ELSE_LAST_STATEMENT");
    146 	    typeMap.put(NodeType.WHILE_LAST_STATEMENT, "WHILE_LAST_STATEMENT");
    147 	    typeMap.put(NodeType.WHILE_EXPR, "WHILE_EXPR");
    148 	    typeMap.put(NodeType.SWITCH_START, "SWITCH_START");
    149 	    typeMap.put(NodeType.CASE_LAST_STATEMENT, "CASE_LAST_STATEMENT");
    150 	    typeMap.put(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, "SWITCH_LAST_DEFAULT_STATEMENT");
    151 	    typeMap.put(NodeType.SWITCH_END, "SWITCH_END");
    152 	    typeMap.put(NodeType.FOR_INIT, "FOR_INIT");
    153 	    typeMap.put(NodeType.FOR_EXPR, "FOR_EXPR");
    154 	    typeMap.put(NodeType.FOR_UPDATE, "FOR_UPDATE");
    155 	    typeMap.put(NodeType.FOR_BEFORE_FIRST_STATEMENT, "FOR_BEFORE_FIRST_STATEMENT");
    156 	    typeMap.put(NodeType.FOR_END, "FOR_END");
    157 	    typeMap.put(NodeType.DO_BEFORE_FIRST_STATEMENT, "DO_BEFORE_FIRST_STATEMENT");
    158 	    typeMap.put(NodeType.DO_EXPR, "DO_EXPR");
    159 	    typeMap.put(NodeType.RETURN_STATEMENT, "RETURN_STATEMENT");
    160 	    typeMap.put(NodeType.BREAK_STATEMENT, "BREAK_STATEMENT");
    161 	    typeMap.put(NodeType.CONTINUE_STATEMENT, "CONTINUE_STATEMENT");
    162 	    typeMap.put(NodeType.LABEL_STATEMENT, "LABEL_STATEMENT");
    163 	    typeMap.put(NodeType.LABEL_LAST_STATEMENT, "LABEL_END");
    164 	    typeMap.put(NodeType.THROW_STATEMENT, "THROW_STATEMENT");
    165 	}
    166 	if (!typeMap.containsKey(intype)) {
    167 	    throw new RuntimeException("Couldn't find type id " + intype);
    168 	}
    169 	return typeMap.get(intype);
    170     }
    171
    172 }