2007-04-19 13:48:01 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* 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;
|
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
import java.util.*;
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
import com.ibm.wala.cast.tree.*;
|
|
|
|
import com.ibm.wala.cast.util.*;
|
|
|
|
import com.ibm.wala.util.*;
|
|
|
|
import com.ibm.wala.util.collections.*;
|
|
|
|
import com.ibm.wala.util.debug.*;
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
public abstract class
|
|
|
|
CAstRewriter<C extends CAstRewriter.RewriteContext<K>,
|
|
|
|
K extends CAstRewriter.CopyKey<K>>
|
|
|
|
{
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
protected static final boolean DEBUG = false;
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
public interface CopyKey<Self extends CopyKey> {
|
|
|
|
|
|
|
|
int hashCode();
|
|
|
|
|
|
|
|
boolean equals(Object o);
|
|
|
|
|
|
|
|
Self parent();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
public interface RewriteContext<K extends CopyKey> {
|
|
|
|
|
|
|
|
K key();
|
|
|
|
|
|
|
|
};
|
2007-04-19 13:48:01 +00:00
|
|
|
|
|
|
|
public interface Rewrite {
|
|
|
|
|
|
|
|
CAstNode newRoot();
|
|
|
|
|
|
|
|
CAstControlFlowMap newCfg();
|
|
|
|
|
|
|
|
CAstSourcePositionMap newPos();
|
|
|
|
|
|
|
|
CAstNodeTypeMap newTypes();
|
|
|
|
|
2007-07-05 03:04:50 +00:00
|
|
|
Map<CAstNode, Collection<CAstEntity>> newChildren();
|
2007-04-19 13:48:01 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
protected final CAst Ast;
|
|
|
|
|
|
|
|
protected final boolean recursive;
|
|
|
|
|
|
|
|
protected final C rootContext;
|
|
|
|
|
|
|
|
public CAstRewriter(CAst Ast, boolean recursive, C rootContext) {
|
|
|
|
this.Ast = Ast;
|
|
|
|
this.recursive = recursive;
|
|
|
|
this.rootContext = rootContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected abstract CAstNode copyNodes(CAstNode root, C context, Map nodeMap);
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2007-07-05 03:04:50 +00:00
|
|
|
protected CAstNode flowOutTo(Map<CAstNode, CAstNode> nodeMap, CAstNode oldSource, Object label, CAstNode oldTarget,
|
|
|
|
CAstControlFlowMap orig, CAstSourcePositionMap src) {
|
2007-06-25 20:08:56 +00:00
|
|
|
return oldTarget;
|
|
|
|
}
|
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
private CAstControlFlowMap copyFlow(Map nodeMap,
|
|
|
|
CAstControlFlowMap orig,
|
|
|
|
CAstSourcePositionMap newSrc)
|
|
|
|
{
|
2007-07-11 21:07:32 +00:00
|
|
|
Set<CAstNode> mappedOutsideNodes = HashSetFactory.make(1);
|
2007-08-01 15:36:40 +00:00
|
|
|
CAstControlFlowRecorder newMap = new CAstControlFlowRecorder(newSrc);
|
|
|
|
Collection oldSources = orig.getMappedNodes();
|
|
|
|
|
|
|
|
for(Iterator NS = nodeMap.entrySet().iterator(); NS.hasNext(); ) {
|
|
|
|
Map.Entry entry = (Map.Entry) NS.next();
|
|
|
|
Pair N = (Pair)entry.getKey();
|
|
|
|
CAstNode oldSource = (CAstNode) N.fst;
|
|
|
|
CopyKey key = (CopyKey) N.snd;
|
|
|
|
|
|
|
|
CAstNode newSource = (CAstNode) entry.getValue();
|
|
|
|
Assertions._assert(newSource != null);
|
|
|
|
|
|
|
|
newMap.map(newSource, newSource);
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
Trace.println("\n\nlooking at "+key+":"+CAstPrinter.print(oldSource));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldSources.contains(oldSource)) {
|
|
|
|
Iterator LS = orig.getTargetLabels(oldSource).iterator();
|
|
|
|
if (orig.getTarget(oldSource, null) != null) {
|
|
|
|
LS = new IteratorPlusOne(LS, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (LS.hasNext()) {
|
|
|
|
Object label = LS.next();
|
|
|
|
CAstNode oldTarget = orig.getTarget(oldSource, label);
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
Trace.println("old: "+label+" --> "+CAstPrinter.print(oldTarget));
|
|
|
|
}
|
|
|
|
|
|
|
|
Pair targetKey;
|
|
|
|
CopyKey k = key;
|
|
|
|
do {
|
|
|
|
targetKey = new Pair(oldTarget, k);
|
|
|
|
if (k != null) {
|
|
|
|
k = k.parent();
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (! nodeMap.containsKey(targetKey));
|
|
|
|
|
|
|
|
CAstNode newTarget;
|
|
|
|
if (nodeMap.containsKey(targetKey)) {
|
|
|
|
newTarget = (CAstNode) nodeMap.get(targetKey);
|
|
|
|
newMap.add(newSource, newTarget, label);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
newTarget = flowOutTo(nodeMap, oldSource, label, oldTarget, orig, newSrc);
|
|
|
|
newMap.add(newSource, newTarget, label);
|
|
|
|
if (newTarget != CAstControlFlowMap.EXCEPTION_TO_EXIT
|
|
|
|
&&
|
|
|
|
!mappedOutsideNodes.contains(newTarget))
|
|
|
|
{
|
|
|
|
mappedOutsideNodes.add(newTarget);
|
|
|
|
newMap.map(newTarget, newTarget);
|
2007-07-05 03:04:50 +00:00
|
|
|
}
|
2007-08-01 15:36:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
Trace.println("mapping:old: " + CAstPrinter.print(oldSource) +
|
|
|
|
"-- " + label + " --> " + CAstPrinter.print(oldTarget));
|
|
|
|
Trace.println("mapping:new: " + CAstPrinter.print(newSource) +
|
|
|
|
"-- " + label + " --> " + CAstPrinter.print(newTarget));
|
|
|
|
}
|
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return newMap;
|
|
|
|
}
|
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
private CAstSourcePositionMap copySource(Map nodeMap, CAstSourcePositionMap orig) {
|
|
|
|
CAstSourcePositionRecorder newMap = new CAstSourcePositionRecorder();
|
|
|
|
for(Iterator NS = nodeMap.entrySet().iterator(); NS.hasNext(); ) {
|
|
|
|
Map.Entry entry = (Map.Entry)NS.next();
|
|
|
|
Pair N = (Pair)entry.getKey();
|
|
|
|
CAstNode oldNode = (CAstNode) N.fst;
|
|
|
|
|
|
|
|
CAstNode newNode = (CAstNode) entry.getValue();
|
|
|
|
|
|
|
|
if (orig.getPosition(oldNode) != null) {
|
|
|
|
newMap.setPosition(newNode, orig.getPosition(oldNode));
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-01 15:36:40 +00:00
|
|
|
|
|
|
|
return newMap;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private CAstNodeTypeMap copyTypes(Map nodeMap, CAstNodeTypeMap orig) {
|
|
|
|
if (orig != null) {
|
|
|
|
CAstNodeTypeMapRecorder newMap = new CAstNodeTypeMapRecorder();
|
2007-08-01 15:36:40 +00:00
|
|
|
for(Iterator NS = nodeMap.entrySet().iterator(); NS.hasNext(); ) {
|
|
|
|
Map.Entry entry = (Map.Entry) NS.next();
|
|
|
|
Pair N = (Pair)entry.getKey();
|
|
|
|
CAstNode oldNode = (CAstNode) N.fst;
|
|
|
|
|
|
|
|
CAstNode newNode = (CAstNode) entry.getValue();
|
|
|
|
|
|
|
|
if (orig.getNodeType(oldNode) != null) {
|
|
|
|
newMap.add(newNode, orig.getNodeType(oldNode));
|
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
2007-08-01 15:36:40 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
return newMap;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
private Map copyChildren(Map nodeMap, Map children) {
|
|
|
|
final Map newChildren = new LinkedHashMap();
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
for(Iterator NS = nodeMap.entrySet().iterator(); NS.hasNext(); ) {
|
|
|
|
Map.Entry entry = (Map.Entry)NS.next();
|
|
|
|
Pair N = (Pair)entry.getKey();
|
|
|
|
CAstNode oldNode = (CAstNode) N.fst;
|
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
CAstNode newNode = (CAstNode) entry.getValue();
|
2007-08-01 15:36:40 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
if (children.containsKey(oldNode)) {
|
2007-08-01 15:36:40 +00:00
|
|
|
Set newEntities = new LinkedHashSet();
|
|
|
|
newChildren.put(newNode, newEntities);
|
|
|
|
for(Iterator oldEntities = ((Collection)children.get(oldNode)).iterator();
|
|
|
|
oldEntities.hasNext(); )
|
|
|
|
{
|
|
|
|
newEntities.add( rewrite((CAstEntity)oldEntities.next() ) );
|
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-01 15:36:40 +00:00
|
|
|
|
|
|
|
for(Iterator keys = children.entrySet().iterator(); keys.hasNext();) {
|
|
|
|
Map.Entry entry = (Map.Entry) keys.next();
|
|
|
|
Object key = entry.getKey();
|
|
|
|
if (! (key instanceof CAstNode)) {
|
|
|
|
Set newEntities = new LinkedHashSet();
|
|
|
|
newChildren.put(key, newEntities);
|
|
|
|
for(Iterator oldEntities = ((Collection)entry.getValue()).iterator();
|
|
|
|
oldEntities.hasNext(); )
|
|
|
|
{
|
|
|
|
newEntities.add( rewrite((CAstEntity)oldEntities.next() ) );
|
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return newChildren;
|
|
|
|
}
|
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
public Rewrite rewrite(CAstNode root,
|
|
|
|
final CAstControlFlowMap cfg,
|
|
|
|
final CAstSourcePositionMap pos,
|
|
|
|
final CAstNodeTypeMap types,
|
|
|
|
final Map<CAstNode, Collection<CAstEntity>> children)
|
|
|
|
{
|
2007-07-11 21:07:32 +00:00
|
|
|
final Map<CAstNode, CAstNode> nodes = HashMapFactory.make();
|
2007-04-19 13:48:01 +00:00
|
|
|
final CAstNode newRoot = copyNodes(root, rootContext, nodes);
|
|
|
|
return new Rewrite() {
|
|
|
|
private CAstControlFlowMap theCfg = null;
|
2007-04-24 14:10:57 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
private CAstSourcePositionMap theSource = null;
|
2007-04-24 14:10:57 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
private CAstNodeTypeMap theTypes = null;
|
|
|
|
|
2007-07-05 03:04:50 +00:00
|
|
|
private Map<CAstNode, Collection<CAstEntity>> theChildren = null;
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstNode newRoot() {
|
|
|
|
return newRoot;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstControlFlowMap newCfg() {
|
|
|
|
if (theCfg == null)
|
2007-07-05 03:04:50 +00:00
|
|
|
theCfg = copyFlow(nodes, cfg, newPos());
|
2007-04-24 14:10:57 +00:00
|
|
|
return theCfg;
|
|
|
|
}
|
|
|
|
|
|
|
|
public CAstSourcePositionMap newPos() {
|
|
|
|
if (theSource == null)
|
|
|
|
theSource = copySource(nodes, pos);
|
|
|
|
return theSource;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public CAstNodeTypeMap newTypes() {
|
2007-04-24 14:10:57 +00:00
|
|
|
if (theTypes == null)
|
|
|
|
theTypes = copyTypes(nodes, types);
|
|
|
|
return theTypes;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
2007-07-05 03:04:50 +00:00
|
|
|
public Map<CAstNode, Collection<CAstEntity>> newChildren() {
|
2007-04-24 14:10:57 +00:00
|
|
|
if (theChildren == null)
|
|
|
|
theChildren = copyChildren(nodes, children);
|
|
|
|
return theChildren;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
public CAstEntity rewrite(final CAstEntity root) {
|
|
|
|
if (root.getAST() != null) {
|
2007-04-24 14:10:57 +00:00
|
|
|
final Rewrite rewrite = rewrite(root.getAST(), root.getControlFlow(), root.getSourceMap(), root.getNodeTypeMap(), root
|
|
|
|
.getAllScopedEntities());
|
2007-04-19 13:48:01 +00:00
|
|
|
|
|
|
|
return new DelegatingEntity(root) {
|
2007-04-24 14:10:57 +00:00
|
|
|
public String toString() {
|
|
|
|
return root.toString() + " (clone)";
|
|
|
|
}
|
|
|
|
|
|
|
|
public Iterator getScopedEntities(CAstNode construct) {
|
|
|
|
Map newChildren = getAllScopedEntities();
|
|
|
|
if (newChildren.containsKey(construct)) {
|
|
|
|
return ((Collection) newChildren.get(construct)).iterator();
|
|
|
|
} else {
|
|
|
|
return EmptyIterator.instance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
|
|
|
|
return rewrite.newChildren();
|
|
|
|
}
|
|
|
|
|
|
|
|
public CAstNode getAST() {
|
|
|
|
return rewrite.newRoot();
|
|
|
|
}
|
|
|
|
|
|
|
|
public CAstNodeTypeMap getNodeTypeMap() {
|
|
|
|
return rewrite.newTypes();
|
|
|
|
}
|
|
|
|
|
|
|
|
public CAstSourcePositionMap getSourceMap() {
|
|
|
|
return rewrite.newPos();
|
|
|
|
}
|
|
|
|
|
|
|
|
public CAstControlFlowMap getControlFlow() {
|
|
|
|
return rewrite.newCfg();
|
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
};
|
2007-04-24 14:10:57 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
} else if (recursive) {
|
|
|
|
|
2007-04-24 14:10:57 +00:00
|
|
|
Map<CAstNode, Collection<CAstEntity>> children = root.getAllScopedEntities();
|
2007-07-05 03:04:50 +00:00
|
|
|
final Map<CAstNode, Collection<CAstEntity>> newChildren = new LinkedHashMap<CAstNode, Collection<CAstEntity>>();
|
|
|
|
for (Iterator<Map.Entry<CAstNode, Collection<CAstEntity>>> keys = children.entrySet().iterator(); keys.hasNext();) {
|
|
|
|
Map.Entry<CAstNode, Collection<CAstEntity>> entry = keys.next();
|
2007-04-24 14:10:57 +00:00
|
|
|
CAstNode key = entry.getKey();
|
|
|
|
Set<CAstEntity> newValues = new LinkedHashSet<CAstEntity>();
|
|
|
|
newChildren.put(key, newValues);
|
2007-07-05 03:04:50 +00:00
|
|
|
for (Iterator es = entry.getValue().iterator(); es.hasNext();) {
|
2007-04-24 14:10:57 +00:00
|
|
|
newValues.add(rewrite((CAstEntity) es.next()));
|
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
2007-04-24 14:10:57 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
return new DelegatingEntity(root) {
|
2007-04-24 14:10:57 +00:00
|
|
|
public String toString() {
|
|
|
|
return root.toString() + " (clone)";
|
|
|
|
}
|
|
|
|
|
|
|
|
public Iterator getScopedEntities(CAstNode construct) {
|
|
|
|
if (newChildren.containsKey(construct)) {
|
2007-07-05 03:04:50 +00:00
|
|
|
return newChildren.get(construct).iterator();
|
2007-04-24 14:10:57 +00:00
|
|
|
} else {
|
|
|
|
return EmptyIterator.instance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-05 03:04:50 +00:00
|
|
|
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
|
2007-04-24 14:10:57 +00:00
|
|
|
return newChildren;
|
|
|
|
}
|
|
|
|
};
|
2007-04-19 13:48:01 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-24 14:10:57 +00:00
|
|
|
}
|