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
|
|
|
|
*****************************************************************************/
|
2012-10-03 14:53:04 +00:00
|
|
|
package com.ibm.wala.cast.tree.rewrite;
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2007-11-16 20:57:45 +00:00
|
|
|
import java.util.Collection;
|
2012-01-06 21:18:20 +00:00
|
|
|
import java.util.HashSet;
|
2007-11-16 20:57:45 +00:00
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.LinkedHashSet;
|
|
|
|
import java.util.Map;
|
2011-04-22 22:59:13 +00:00
|
|
|
import java.util.Map.Entry;
|
2007-11-16 20:57:45 +00:00
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
import com.ibm.wala.cast.tree.CAst;
|
|
|
|
import com.ibm.wala.cast.tree.CAstControlFlowMap;
|
|
|
|
import com.ibm.wala.cast.tree.CAstEntity;
|
|
|
|
import com.ibm.wala.cast.tree.CAstNode;
|
|
|
|
import com.ibm.wala.cast.tree.CAstNodeTypeMap;
|
|
|
|
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
|
2012-10-03 14:53:04 +00:00
|
|
|
import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstNodeTypeMapRecorder;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder;
|
|
|
|
import com.ibm.wala.cast.tree.impl.DelegatingEntity;
|
2007-11-16 20:57:45 +00:00
|
|
|
import com.ibm.wala.cast.util.CAstPrinter;
|
|
|
|
import com.ibm.wala.util.collections.EmptyIterator;
|
|
|
|
import com.ibm.wala.util.collections.HashMapFactory;
|
|
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
|
|
|
import com.ibm.wala.util.collections.Pair;
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2011-04-22 22:59:44 +00:00
|
|
|
/**
|
|
|
|
* Abstract superclass for types performing a rewrite operation on a CAst. The
|
|
|
|
* CAst is not mutated; instead, a new CAst is created which delegates to the
|
|
|
|
* original CAst where no transformation was performed.
|
|
|
|
*
|
|
|
|
* @param <C>
|
|
|
|
* type of the RewriteContext used when traversing the original CAst
|
|
|
|
* during the rewrite operation
|
|
|
|
* @param <K>
|
2011-04-26 18:44:49 +00:00
|
|
|
* a key used to ease cloning of partial ASTs. When rewriting an AST,
|
|
|
|
* sub-classes maintain a mapping from (original node, key) pairs
|
|
|
|
* (where key is of type K) to new nodes; see
|
2017-03-22 23:24:59 +00:00
|
|
|
* {@link #copyNodes}
|
2011-04-22 22:59:44 +00:00
|
|
|
*/
|
2007-08-06 18:31:22 +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
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
/**
|
|
|
|
* interface to be implemented by keys used for cloning sub-trees during the
|
|
|
|
* rewrite
|
|
|
|
*/
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
public interface CopyKey<Self extends CopyKey<Self>> {
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-08-01 15:36:40 +00:00
|
|
|
int hashCode();
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-08-01 15:36:40 +00:00
|
|
|
boolean equals(Object o);
|
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
/**
|
|
|
|
* keys have parent pointers, useful for when nesting cloning must occur
|
|
|
|
* (e.g., unrolling of nested loops)
|
|
|
|
*/
|
2007-08-01 15:36:40 +00:00
|
|
|
Self parent();
|
|
|
|
|
2017-07-12 23:54:57 +00:00
|
|
|
}
|
2007-08-01 15:36:40 +00:00
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
/**
|
|
|
|
* interface to be implemented by contexts used while traversing the AST
|
|
|
|
*/
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
public interface RewriteContext<K extends CopyKey<K>> {
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
/**
|
|
|
|
* get the cloning key for this context
|
|
|
|
*/
|
2007-08-01 15:36:40 +00:00
|
|
|
K key();
|
|
|
|
|
2017-07-12 23:54:57 +00:00
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2011-04-22 22:59:44 +00:00
|
|
|
/**
|
|
|
|
* represents a rewritten CAst
|
|
|
|
*/
|
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
|
|
|
|
2018-10-17 23:44:44 +00:00
|
|
|
CAstNode[] newDefaults();
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
protected final CAst Ast;
|
|
|
|
|
2011-04-22 22:59:44 +00:00
|
|
|
/**
|
|
|
|
* for CAstEntity nodes r s.t. r.getAst() == null, should the scoped entities
|
|
|
|
* of r be rewritten?
|
|
|
|
*/
|
2007-08-01 15:36:40 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-04-22 22:59:44 +00:00
|
|
|
/**
|
2011-04-26 18:44:49 +00:00
|
|
|
* rewrite the CAst rooted at root under some context, returning the node at
|
|
|
|
* the root of the rewritten tree. mutate nodeMap in the process, indicating
|
|
|
|
* how (original node, copy key) pairs are mapped to nodes in the rewritten
|
|
|
|
* tree.
|
2011-04-22 22:59:44 +00:00
|
|
|
*/
|
2012-01-27 20:15:33 +00:00
|
|
|
protected abstract CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, C context, Map<Pair<CAstNode, K>, CAstNode> nodeMap);
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
/**
|
|
|
|
* in {@link #copyFlow(Map, CAstControlFlowMap, CAstSourcePositionMap)}, if
|
|
|
|
* the source of some original CFG edge is replicated, but we find no replica
|
|
|
|
* for the target, what node should be the target of the CFG edge in the
|
|
|
|
* rewritten AST? By default, just uses the original target.
|
|
|
|
*
|
|
|
|
*/
|
2017-07-28 20:33:41 +00:00
|
|
|
@SuppressWarnings("unused")
|
2011-04-22 22:59:13 +00:00
|
|
|
protected CAstNode flowOutTo(Map<Pair<CAstNode, K>, CAstNode> nodeMap, CAstNode oldSource, Object label, CAstNode oldTarget,
|
2007-07-05 03:04:50 +00:00
|
|
|
CAstControlFlowMap orig, CAstSourcePositionMap src) {
|
2007-06-25 20:08:56 +00:00
|
|
|
return oldTarget;
|
|
|
|
}
|
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
/**
|
|
|
|
* create a control-flow map for the rewritten tree, given the mapping from
|
|
|
|
* (original node, copy key) pairs ot new nodes and the original control-flow
|
|
|
|
* map.
|
|
|
|
*/
|
2012-01-06 21:17:15 +00:00
|
|
|
protected CAstControlFlowMap copyFlow(Map<Pair<CAstNode, K>, CAstNode> nodeMap, CAstControlFlowMap orig,
|
2011-04-22 22:59:13 +00:00
|
|
|
CAstSourcePositionMap newSrc) {
|
2011-04-26 18:44:49 +00:00
|
|
|
|
|
|
|
// the new control-flow map
|
|
|
|
final CAstControlFlowRecorder newMap = new CAstControlFlowRecorder(newSrc);
|
|
|
|
// tracks which CAstNodes not present in nodeMap's key set (under any copy
|
|
|
|
// key) are added as targets of CFG edges
|
|
|
|
// via a call to flowOutTo() (see below); used to ensure these nodes are
|
|
|
|
// only mapped to themselves once in newMap
|
|
|
|
final Set<CAstNode> mappedOutsideNodes = HashSetFactory.make(1);
|
|
|
|
// all edge targets in new control-flow map; must all be mapped to
|
|
|
|
// themselves
|
2010-09-14 20:29:29 +00:00
|
|
|
Set<CAstNode> allNewTargetNodes = HashSetFactory.make(1);
|
2011-04-22 22:59:44 +00:00
|
|
|
Collection<CAstNode> oldSources = orig.getMappedNodes();
|
2007-08-01 15:36:40 +00:00
|
|
|
|
2017-11-28 20:26:09 +00:00
|
|
|
for (Entry<Pair<CAstNode, K>, CAstNode> entry : nodeMap.entrySet()) {
|
2011-04-22 22:59:13 +00:00
|
|
|
Pair<CAstNode, K> N = entry.getKey();
|
|
|
|
CAstNode oldSource = N.fst;
|
2011-07-06 19:50:56 +00:00
|
|
|
K key = N.snd;
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2013-10-16 21:37:53 +00:00
|
|
|
CAstNode newSource = entry.getValue();
|
2009-04-30 13:16:52 +00:00
|
|
|
assert newSource != null;
|
2007-08-01 15:36:40 +00:00
|
|
|
|
|
|
|
newMap.map(newSource, newSource);
|
|
|
|
|
|
|
|
if (DEBUG) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("\n\nlooking at " + key + ":" + CAstPrinter.print(oldSource)));
|
2007-08-01 15:36:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (oldSources.contains(oldSource)) {
|
2007-12-04 20:44:04 +00:00
|
|
|
Iterator<Object> LS = orig.getTargetLabels(oldSource).iterator();
|
2012-01-27 20:15:33 +00:00
|
|
|
//if (orig.getTarget(oldSource, null) != null) {
|
|
|
|
// LS = IteratorPlusOne.make(LS, null);
|
|
|
|
//}
|
2007-08-06 18:31:22 +00:00
|
|
|
|
|
|
|
while (LS.hasNext()) {
|
2010-10-02 20:27:17 +00:00
|
|
|
Object origLabel = LS.next();
|
|
|
|
CAstNode oldTarget = orig.getTarget(oldSource, origLabel);
|
2010-09-14 20:29:29 +00:00
|
|
|
assert oldTarget != null;
|
2007-08-06 18:31:22 +00:00
|
|
|
|
|
|
|
if (DEBUG) {
|
2010-10-02 20:27:17 +00:00
|
|
|
System.err.println(("old: " + origLabel + " --> " + CAstPrinter.print(oldTarget)));
|
2007-08-06 18:31:22 +00:00
|
|
|
}
|
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
// try to find a k in key's parent chain such that (oldTarget, k) is
|
|
|
|
// in nodeMap's key set
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
Pair<CAstNode,CopyKey<K>> targetKey;
|
|
|
|
CopyKey<K> k = key;
|
2007-08-06 18:31:22 +00:00
|
|
|
do {
|
2007-08-31 23:19:52 +00:00
|
|
|
targetKey = Pair.make(oldTarget, k);
|
2007-08-06 18:31:22 +00:00
|
|
|
if (k != null) {
|
|
|
|
k = k.parent();
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!nodeMap.containsKey(targetKey));
|
|
|
|
|
2010-10-02 20:27:17 +00:00
|
|
|
Object newLabel;
|
2011-04-22 22:59:13 +00:00
|
|
|
if (nodeMap.containsKey(Pair.make(origLabel, targetKey.snd))) { // label
|
|
|
|
// is
|
|
|
|
// mapped
|
|
|
|
// too
|
|
|
|
newLabel = nodeMap.get(Pair.make(origLabel, targetKey.snd));
|
2010-10-02 20:27:17 +00:00
|
|
|
} else {
|
2011-04-22 22:59:13 +00:00
|
|
|
newLabel = origLabel;
|
2010-10-02 20:27:17 +00:00
|
|
|
}
|
2011-04-22 22:59:13 +00:00
|
|
|
|
2007-08-06 18:31:22 +00:00
|
|
|
CAstNode newTarget;
|
|
|
|
if (nodeMap.containsKey(targetKey)) {
|
2013-10-16 21:37:53 +00:00
|
|
|
newTarget = nodeMap.get(targetKey);
|
2010-10-02 20:27:17 +00:00
|
|
|
newMap.add(newSource, newTarget, newLabel);
|
2010-09-14 20:29:29 +00:00
|
|
|
allNewTargetNodes.add(newTarget);
|
2007-08-06 18:31:22 +00:00
|
|
|
|
|
|
|
} else {
|
2011-04-26 18:44:49 +00:00
|
|
|
// could not discover target of CFG edge in nodeMap under any key related to the current source key.
|
|
|
|
// the edge might have been deleted, or it may end at a node above the root where we were
|
|
|
|
// rewriting
|
|
|
|
// ask flowOutTo() to just choose a target
|
2010-10-02 20:27:17 +00:00
|
|
|
newTarget = flowOutTo(nodeMap, oldSource, origLabel, oldTarget, orig, newSrc);
|
2010-09-14 20:29:29 +00:00
|
|
|
allNewTargetNodes.add(newTarget);
|
2010-10-02 20:27:17 +00:00
|
|
|
newMap.add(newSource, newTarget, newLabel);
|
2007-08-06 18:31:22 +00:00
|
|
|
if (newTarget != CAstControlFlowMap.EXCEPTION_TO_EXIT && !mappedOutsideNodes.contains(newTarget)) {
|
|
|
|
mappedOutsideNodes.add(newTarget);
|
2007-08-01 15:36:40 +00:00
|
|
|
newMap.map(newTarget, newTarget);
|
2007-07-05 03:04:50 +00:00
|
|
|
}
|
2007-08-06 18:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG) {
|
2011-04-22 22:59:13 +00:00
|
|
|
System.err.println(("mapping:old: " + CAstPrinter.print(oldSource) + "-- " + origLabel + " --> " + CAstPrinter
|
|
|
|
.print(oldTarget)));
|
|
|
|
System.err.println(("mapping:new: " + CAstPrinter.print(newSource) + "-- " + newLabel + " --> " + CAstPrinter
|
|
|
|
.print(newTarget)));
|
2007-08-06 18:31:22 +00:00
|
|
|
}
|
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-14 20:29:29 +00:00
|
|
|
allNewTargetNodes.removeAll(newMap.getMappedNodes());
|
2011-04-22 22:59:13 +00:00
|
|
|
for (CAstNode newTarget : allNewTargetNodes) {
|
2012-01-27 20:15:33 +00:00
|
|
|
if (newTarget != CAstControlFlowMap.EXCEPTION_TO_EXIT) {
|
|
|
|
newMap.map(newTarget, newTarget);
|
|
|
|
}
|
2010-09-14 20:29:29 +00:00
|
|
|
}
|
2012-01-06 21:18:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
assert !oldNodesInNewMap(nodeMap, newMap);
|
2011-04-22 22:59:13 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
return newMap;
|
|
|
|
}
|
|
|
|
|
2012-01-06 21:18:20 +00:00
|
|
|
// check whether newMap contains any CFG edges involving nodes in the domain of nodeMap
|
|
|
|
private boolean oldNodesInNewMap(Map<Pair<CAstNode, K>, CAstNode> nodeMap, final CAstControlFlowRecorder newMap) {
|
|
|
|
HashSet<CAstNode> oldNodes = HashSetFactory.make();
|
|
|
|
for(Entry<Pair<CAstNode, K>, CAstNode> e : nodeMap.entrySet())
|
|
|
|
oldNodes.add(e.getKey().fst);
|
|
|
|
for(CAstNode mappedNode : newMap.getMappedNodes()) {
|
|
|
|
if(oldNodes.contains(mappedNode))
|
|
|
|
return true;
|
|
|
|
for(Object lbl : newMap.getTargetLabels(mappedNode))
|
|
|
|
if(oldNodes.contains(newMap.getTarget(mappedNode, lbl)))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-01-06 21:17:15 +00:00
|
|
|
protected CAstSourcePositionMap copySource(Map<Pair<CAstNode, K>, CAstNode> nodeMap, CAstSourcePositionMap orig) {
|
2007-08-01 15:36:40 +00:00
|
|
|
CAstSourcePositionRecorder newMap = new CAstSourcePositionRecorder();
|
2017-11-28 20:26:09 +00:00
|
|
|
for (Entry<Pair<CAstNode, K>, CAstNode> entry : nodeMap.entrySet()) {
|
2011-04-22 22:59:13 +00:00
|
|
|
Pair<CAstNode, K> N = entry.getKey();
|
|
|
|
CAstNode oldNode = N.fst;
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2011-04-22 22:59:13 +00:00
|
|
|
CAstNode newNode = entry.getValue();
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
if (orig.getPosition(oldNode) != null) {
|
2007-08-06 18:31:22 +00:00
|
|
|
newMap.setPosition(newNode, orig.getPosition(oldNode));
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2007-08-01 15:36:40 +00:00
|
|
|
return newMap;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
2012-01-06 21:17:15 +00:00
|
|
|
protected CAstNodeTypeMap copyTypes(Map<Pair<CAstNode, K>, CAstNode> nodeMap, CAstNodeTypeMap orig) {
|
2007-04-19 13:48:01 +00:00
|
|
|
if (orig != null) {
|
|
|
|
CAstNodeTypeMapRecorder newMap = new CAstNodeTypeMapRecorder();
|
2017-11-28 20:26:09 +00:00
|
|
|
for (Entry<Pair<CAstNode, K>, CAstNode> entry : nodeMap.entrySet()) {
|
2011-04-22 22:59:13 +00:00
|
|
|
Pair<CAstNode, K> N = entry.getKey();
|
|
|
|
CAstNode oldNode = N.fst;
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2011-04-22 22:59:13 +00:00
|
|
|
CAstNode newNode = entry.getValue();
|
2007-08-06 18:31:22 +00:00
|
|
|
|
|
|
|
if (orig.getNodeType(oldNode) != null) {
|
|
|
|
newMap.add(newNode, orig.getNodeType(oldNode));
|
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
return newMap;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-28 20:33:41 +00:00
|
|
|
protected Map<CAstNode, Collection<CAstEntity>> copyChildren(@SuppressWarnings("unused") CAstNode root, Map<Pair<CAstNode, K>, CAstNode> nodeMap,
|
2011-04-22 22:59:13 +00:00
|
|
|
Map<CAstNode, Collection<CAstEntity>> children) {
|
2017-03-12 03:20:51 +00:00
|
|
|
final Map<CAstNode, Collection<CAstEntity>> newChildren = new LinkedHashMap<>();
|
2007-04-19 13:48:01 +00:00
|
|
|
|
2017-11-28 20:26:09 +00:00
|
|
|
for (Entry<Pair<CAstNode, K>, CAstNode> entry : nodeMap.entrySet()) {
|
2011-04-22 22:59:13 +00:00
|
|
|
Pair<CAstNode, K> N = entry.getKey();
|
|
|
|
CAstNode oldNode = N.fst;
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2011-04-22 22:59:13 +00:00
|
|
|
CAstNode newNode = entry.getValue();
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
if (children.containsKey(oldNode)) {
|
2017-03-12 03:20:51 +00:00
|
|
|
Set<CAstEntity> newEntities = new LinkedHashSet<>();
|
2007-08-06 18:31:22 +00:00
|
|
|
newChildren.put(newNode, newEntities);
|
2017-11-28 20:26:09 +00:00
|
|
|
for (CAstEntity cAstEntity : children.get(oldNode)) {
|
|
|
|
newEntities.add(rewrite(cAstEntity));
|
2007-08-06 18:31:22 +00:00
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-06 18:31:22 +00:00
|
|
|
|
2017-11-28 20:26:09 +00:00
|
|
|
for (Entry<CAstNode, Collection<CAstEntity>> entry : children.entrySet()) {
|
2007-12-04 21:40:34 +00:00
|
|
|
CAstNode key = entry.getKey();
|
2011-04-26 18:44:49 +00:00
|
|
|
if (key == null) {
|
2017-03-12 03:20:51 +00:00
|
|
|
Set<CAstEntity> newEntities = new LinkedHashSet<>();
|
2007-08-06 18:31:22 +00:00
|
|
|
newChildren.put(key, newEntities);
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
for (CAstEntity oldEntity : entry.getValue()) {
|
|
|
|
newEntities.add(rewrite(oldEntity));
|
2007-08-06 18:31:22 +00:00
|
|
|
}
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return newChildren;
|
|
|
|
}
|
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
/**
|
|
|
|
* rewrite the CAst sub-tree rooted at root
|
|
|
|
*/
|
2012-01-06 21:18:20 +00:00
|
|
|
public Rewrite rewrite(final CAstNode root, final CAstControlFlowMap cfg, final CAstSourcePositionMap pos, final CAstNodeTypeMap types,
|
2018-10-17 23:44:44 +00:00
|
|
|
final Map<CAstNode, Collection<CAstEntity>> children, final CAstNode[] defaults) {
|
2011-04-22 22:59:13 +00:00
|
|
|
final Map<Pair<CAstNode, K>, CAstNode> nodes = HashMapFactory.make();
|
2012-01-27 20:15:33 +00:00
|
|
|
final CAstNode newRoot = copyNodes(root, cfg, rootContext, nodes);
|
2018-10-17 23:44:44 +00:00
|
|
|
final CAstNode newDefaults[] = new CAstNode[ defaults==null? 0: defaults.length ];
|
|
|
|
for(int i = 0; i < newDefaults.length; i++) {
|
|
|
|
newDefaults[i] = copyNodes(defaults[i], cfg, rootContext, nodes);
|
|
|
|
}
|
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
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
|
|
|
|
2018-10-17 23:44:44 +00:00
|
|
|
@Override
|
|
|
|
public CAstNode[] newDefaults() {
|
|
|
|
return newDefaults;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstNode newRoot() {
|
|
|
|
return newRoot;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstControlFlowMap newCfg() {
|
2018-04-28 10:05:49 +00:00
|
|
|
if (theCfg == null && cfg != null)
|
2007-07-05 03:04:50 +00:00
|
|
|
theCfg = copyFlow(nodes, cfg, newPos());
|
2007-04-24 14:10:57 +00:00
|
|
|
return theCfg;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstSourcePositionMap newPos() {
|
2017-01-20 00:12:22 +00:00
|
|
|
if (theSource == null && pos != null)
|
2007-04-24 14:10:57 +00:00
|
|
|
theSource = copySource(nodes, pos);
|
|
|
|
return theSource;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-19 13:48:01 +00:00
|
|
|
public CAstNodeTypeMap newTypes() {
|
2018-04-28 10:05:49 +00:00
|
|
|
if (theTypes == null && types != null)
|
2007-04-24 14:10:57 +00:00
|
|
|
theTypes = copyTypes(nodes, types);
|
|
|
|
return theTypes;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
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)
|
2012-01-06 21:18:20 +00:00
|
|
|
theChildren = copyChildren(root, nodes, children);
|
2007-04-24 14:10:57 +00:00
|
|
|
return theChildren;
|
2007-04-19 13:48:01 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
/**
|
|
|
|
* perform the rewrite on a {@link CAstEntity}, returning the new
|
|
|
|
* {@link CAstEntity} as the result
|
|
|
|
*/
|
2007-04-19 13:48:01 +00:00
|
|
|
public CAstEntity rewrite(final CAstEntity root) {
|
2011-04-22 22:59:13 +00:00
|
|
|
|
2007-04-19 13:48:01 +00:00
|
|
|
if (root.getAST() != null) {
|
2011-04-22 22:59:13 +00:00
|
|
|
final Rewrite rewrite = rewrite(root.getAST(), root.getControlFlow(), root.getSourceMap(), root.getNodeTypeMap(),
|
2018-10-17 23:44:44 +00:00
|
|
|
root.getAllScopedEntities(), root.getArgumentDefaults());
|
2007-04-19 13:48:01 +00:00
|
|
|
|
|
|
|
return new DelegatingEntity(root) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public String toString() {
|
|
|
|
return root.toString() + " (clone)";
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-04-13 16:18:58 +00:00
|
|
|
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
|
|
|
|
Map<CAstNode, Collection<CAstEntity>> newChildren = getAllScopedEntities();
|
2007-04-24 14:10:57 +00:00
|
|
|
if (newChildren.containsKey(construct)) {
|
2011-04-13 16:18:58 +00:00
|
|
|
return newChildren.get(construct).iterator();
|
2007-04-24 14:10:57 +00:00
|
|
|
} else {
|
|
|
|
return EmptyIterator.instance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
|
|
|
|
return rewrite.newChildren();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstNode getAST() {
|
|
|
|
return rewrite.newRoot();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstNodeTypeMap getNodeTypeMap() {
|
|
|
|
return rewrite.newTypes();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstSourcePositionMap getSourceMap() {
|
|
|
|
return rewrite.newPos();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public CAstControlFlowMap getControlFlow() {
|
|
|
|
return rewrite.newCfg();
|
|
|
|
}
|
2018-10-17 23:44:44 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public CAstNode[] getArgumentDefaults() {
|
|
|
|
return rewrite.newDefaults();
|
|
|
|
}
|
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();
|
2017-03-12 03:20:51 +00:00
|
|
|
final Map<CAstNode, Collection<CAstEntity>> newChildren = new LinkedHashMap<>();
|
2017-11-28 20:26:09 +00:00
|
|
|
for (Entry<CAstNode, Collection<CAstEntity>> entry : children.entrySet()) {
|
2007-04-24 14:10:57 +00:00
|
|
|
CAstNode key = entry.getKey();
|
2017-03-12 03:20:51 +00:00
|
|
|
Set<CAstEntity> newValues = new LinkedHashSet<>();
|
2007-04-24 14:10:57 +00:00
|
|
|
newChildren.put(key, newValues);
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
for (CAstEntity entity : entry.getValue()) {
|
|
|
|
newValues.add(rewrite(entity));
|
2007-04-24 14:10:57 +00:00
|
|
|
}
|
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) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-24 14:10:57 +00:00
|
|
|
public String toString() {
|
|
|
|
return root.toString() + " (clone)";
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-04-13 16:18:58 +00:00
|
|
|
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
|
2007-04-24 14:10:57 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
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
|
|
|
}
|