WALA/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstControlFlowRecorder.java

138 lines
4.3 KiB
Java

/******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* 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:
* IBM Corporation - initial API and implementation
*****************************************************************************/
package com.ibm.wala.cast.tree.impl;
import com.ibm.wala.cast.tree.*;
import com.ibm.wala.util.debug.Assertions;
import java.util.*;
/**
* An implementation of a CAstControlFlowMap that is designed to be
* used by producers of CAPA asts. In addition to implementing the
* control flow map, it additionally allows clients to record control
* flow mappings in terms of some arbitrary type object that are then
* mapped to CAstNodes by the client. These objects can be anything,
* but one common use is that some type of parse tree is walked to
* build a capa ast, with control flow being recorded in terms of
* parse tree nodes and then ast nodes being mapped to parse tree
* nodes.
*
* Note that, at present, support for mapping control flow on ast
* nodes directly is clunky. It is necessary to establish that an ast
* nodes maps to itself, i.e. call xx.map(node, node).
*
* @author Julian Dolby (dolby@us.ibm.com)
*/
public class CAstControlFlowRecorder implements CAstControlFlowMap {
private final Map CAstToNode = new LinkedHashMap();
private final Map nodeToCAst = new LinkedHashMap();
private final Map table = new LinkedHashMap();
private final Map labelMap = new LinkedHashMap();
private final Map sourceMap = new LinkedHashMap();
private class Key {
private final Object label;
private final Object from;
Key(Object label, Object from) {
this.from = from;
this.label = label;
}
Key(Object label, CAstNode from) {
this(label, CAstToNode.get(from));
Assertions._assert(CAstToNode.containsKey(from));
}
public int hashCode() {
if (label != null)
return from.hashCode()*label.hashCode();
else
return from.hashCode();
}
public boolean equals(Object o) {
return (o instanceof Key) &&
from == ((Key)o).from &&
((label==null)?
((Key)o).label == null:
label.equals( ((Key)o).label ));
}
}
public CAstControlFlowRecorder() {
map(EXCEPTION_TO_EXIT, EXCEPTION_TO_EXIT);
}
public CAstNode getTarget(CAstNode from, Object label) {
Key key = new Key(label, from);
if (table.containsKey(key))
return (CAstNode)nodeToCAst.get( table.get(key) );
else
return null;
}
public Collection getTargetLabels(CAstNode from) {
if (labelMap.containsKey( CAstToNode.get(from) )) {
return (Set) labelMap.get( CAstToNode.get(from) );
} else {
return Collections.EMPTY_SET;
}
}
public Collection getSourceNodes(CAstNode to) {
if (sourceMap.containsKey( CAstToNode.get(to) )) {
return (Set) sourceMap.get( CAstToNode.get(to) );
} else {
return Collections.EMPTY_SET;
}
}
public Collection getMappedNodes() {
Set nodes = new LinkedHashSet();
for(Iterator keys = table.keySet().iterator(); keys.hasNext(); ) {
nodes.add( (CAstNode) nodeToCAst.get( ((Key)keys.next()).from ) );
}
return nodes;
}
/**
* Add a control-flow edge from the `from' node to the `to' node
* with the (possibly null) label `label'. These nodes must be
* mapped by the client to CAstNodes using the `map' call; this mapping
* can happen before or after this add call.
*/
public void add(Object from, Object to, Object label) {
table.put(new Key(label, from), to);
Set ls = (Set)labelMap.get(from);
if (ls==null) labelMap.put(from, ls=new LinkedHashSet(2));
ls.add( label );
Set ss = (Set)sourceMap.get(to);
if (ss==null) sourceMap.put(to, ss=new LinkedHashSet(2));
ss.add( from );
}
/**
* Establish a mapping between some object `node' and the ast node
* `ast'. Objects used a endpoints in a control flow edge must be
* mapped to ast nodes using this call.
*/
public void map(Object node, CAstNode ast) {
nodeToCAst.put(node, ast);
CAstToNode.put(ast, node);
}
}