Make FilterIterator and Predicate statically type-correct
Previously FilterIterator was very permissive regarding the type relationships between the original iterator, the filtered iterator, and the predicate used to prune the former down to the latter. Now we enforce those relationships more strictly, including proper use of covariant ("<? extends T>") and contravariant ("<? super T>") polymorphic type parameters where appropriate. This lets us get rid of seven suppressed warnings about generic types and/or unchecked conversions. It also moves us toward being able to use modern Java features like lambdas and streams more easily.
This commit is contained in:
parent
5ac8bf881d
commit
28f0e09435
|
@ -82,7 +82,7 @@ public abstract class CAstAbstractLoader implements IClassLoader {
|
|||
}
|
||||
|
||||
private Iterator<ModuleEntry> getMessages(final byte severity) {
|
||||
return new MapIterator<>(new FilterIterator<Map.Entry<ModuleEntry,Set<Warning>>>(errors.entrySet().iterator(), new Predicate<Map.Entry<ModuleEntry,Set<Warning>>>() {
|
||||
return new MapIterator<>(new FilterIterator<>(errors.entrySet().iterator(), new Predicate<Map.Entry<ModuleEntry,Set<Warning>>>() {
|
||||
@Override public boolean test(Entry<ModuleEntry, Set<Warning>> o) {
|
||||
for(Warning w : o.getValue()) {
|
||||
if (w.getLevel() == severity) {
|
||||
|
|
|
@ -80,7 +80,7 @@ public class CAstFunctions {
|
|||
};
|
||||
}
|
||||
|
||||
public static Iterator<CAstNode> findAll(CAstNode tree, Predicate<?> f) {
|
||||
public static Iterator<CAstNode> findAll(CAstNode tree, Predicate<? super CAstNode> f) {
|
||||
return new FilterIterator<>(iterateNodes(tree), f);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public abstract class HeapGraphImpl<T extends InstanceKey> implements HeapGraph<
|
|||
|
||||
@Override
|
||||
public Collection<Object> getReachableInstances(Set<Object> roots) {
|
||||
Predicate f = new Predicate() {
|
||||
Predicate<Object> f = new Predicate<Object>() {
|
||||
@Override public boolean test(Object o) {
|
||||
return (o instanceof InstanceKey);
|
||||
}
|
||||
|
|
|
@ -76,14 +76,13 @@ public class BackwardsSupergraph<T, P> implements ISupergraph<T, P> {
|
|||
/**
|
||||
* a filter that accepts only exit nodes from the original graph.
|
||||
*/
|
||||
private class ExitFilter implements Predicate {
|
||||
private class ExitFilter implements Predicate<T> {
|
||||
/*
|
||||
* @see com.ibm.wala.util.Filter#accepts(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean test(Object o) {
|
||||
return delegate.isExit((T) o);
|
||||
public boolean test(T o) {
|
||||
return delegate.isExit(o);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,7 +97,7 @@ public class BackwardsSupergraph<T, P> implements ISupergraph<T, P> {
|
|||
if (DEBUG_LEVEL > 1) {
|
||||
System.err.println(getClass() + " getCalledNodes " + ret);
|
||||
System.err.println("called nodes: "
|
||||
+ Iterator2Collection.toSet(new FilterIterator<Object>(getSuccNodes(ret), exitFilter)));
|
||||
+ Iterator2Collection.toSet(new FilterIterator<>(getSuccNodes(ret), exitFilter)));
|
||||
}
|
||||
return new FilterIterator<T>(getSuccNodes(ret), exitFilter);
|
||||
}
|
||||
|
@ -110,15 +109,15 @@ public class BackwardsSupergraph<T, P> implements ISupergraph<T, P> {
|
|||
*/
|
||||
@Override
|
||||
public Iterator<T> getNormalSuccessors(final T ret) {
|
||||
Iterator<? extends Object> allPreds = delegate.getPredNodes(ret);
|
||||
Predicate sameProc = new Predicate<T>() {
|
||||
Iterator<T> allPreds = delegate.getPredNodes(ret);
|
||||
Predicate<T> sameProc = new Predicate<T>() {
|
||||
@Override public boolean test(T o) {
|
||||
// throw out the exit node, which can be a predecessor due to tail recursion.
|
||||
return getProcOf(ret).equals(getProcOf(o)) && !delegate.isExit(o);
|
||||
}
|
||||
};
|
||||
Iterator<Object> sameProcPreds = new FilterIterator<Object>(allPreds, sameProc);
|
||||
Predicate notCall = new Predicate<T>() {
|
||||
Iterator<T> sameProcPreds = new FilterIterator<>(allPreds, sameProc);
|
||||
Predicate<T> notCall = new Predicate<T>() {
|
||||
@Override public boolean test(T o) {
|
||||
return !delegate.isCall(o);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class LocalLiveRangeAnalysis {
|
|||
final Collection<BasicBlock> uses = findBlocks(ir, du.getUses(v));
|
||||
|
||||
// a filter which accepts everything but the block which defs v
|
||||
Predicate notDef = new Predicate() {
|
||||
Predicate<Object> notDef = new Predicate<Object>() {
|
||||
@Override public boolean test(Object o) {
|
||||
return (defBlock == null || !defBlock.equals(o));
|
||||
}
|
||||
|
|
|
@ -187,9 +187,9 @@ public class ExplicitCallGraph extends BasicCallGraph<SSAContextInterpreter> imp
|
|||
*/
|
||||
protected Iterator<CallSiteReference> getPossibleSites(final CGNode to) {
|
||||
final int n = getCallGraph().getNumber(to);
|
||||
return new FilterIterator<CallSiteReference>(iterateCallSites(), new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
IntSet s = getPossibleTargetNumbers((CallSiteReference) o);
|
||||
return new FilterIterator<CallSiteReference>(iterateCallSites(), new Predicate<CallSiteReference>() {
|
||||
@Override public boolean test(CallSiteReference o) {
|
||||
IntSet s = getPossibleTargetNumbers(o);
|
||||
return s == null ? false : s.contains(n);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -122,9 +122,9 @@ public class PartialCallGraph extends DelegatingGraph<CGNode> implements CallGra
|
|||
|
||||
@Override
|
||||
public Iterator<CGNode> iterateNodes(IntSet nodes) {
|
||||
return new FilterIterator<CGNode>(cg.iterateNodes(nodes), new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
return containsNode((CGNode) o);
|
||||
return new FilterIterator<CGNode>(cg.iterateNodes(nodes), new Predicate<CGNode>() {
|
||||
@Override public boolean test(CGNode o) {
|
||||
return containsNode(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -201,9 +201,9 @@ public class PointsToMap {
|
|||
* @return {@link Iterator}<{@link PointerKey}>
|
||||
*/
|
||||
public Iterator<PointerKey> getTransitiveRoots() {
|
||||
return new FilterIterator<PointerKey>(iterateKeys(), new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
return isTransitiveRoot((PointerKey) o);
|
||||
return new FilterIterator<PointerKey>(iterateKeys(), new Predicate<PointerKey>() {
|
||||
@Override public boolean test(PointerKey o) {
|
||||
return isTransitiveRoot(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -26,11 +26,7 @@ import com.ibm.wala.fixpoint.IFixedPointSystem;
|
|||
import com.ibm.wala.fixpoint.IVariable;
|
||||
import com.ibm.wala.fixpoint.UnaryOperator;
|
||||
import com.ibm.wala.fixpoint.UnaryStatement;
|
||||
import com.ibm.wala.util.collections.CompoundIterator;
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.collections.FilterIterator;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.SmallMap;
|
||||
import com.ibm.wala.util.collections.*;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||
|
@ -274,14 +270,14 @@ public class PropagationGraph implements IFixedPointSystem<PointsToSetVariable>
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Iterator<AbstractStatement> getStatements() {
|
||||
Iterator<AbstractStatement> it = new FilterIterator(delegateGraph.iterator(), new Predicate() {
|
||||
@Override public boolean test(Object x) {
|
||||
Iterator<INodeWithNumber> it = new FilterIterator<>(delegateGraph.iterator(), new Predicate<INodeWithNumber>() {
|
||||
@Override public boolean test(INodeWithNumber x) {
|
||||
return x instanceof AbstractStatement;
|
||||
}
|
||||
});
|
||||
return new CompoundIterator<AbstractStatement>(it, new GlobalImplicitIterator());
|
||||
Iterator<AbstractStatement> converted = new MapIterator<>(it, AbstractStatement.class::cast);
|
||||
return new CompoundIterator<AbstractStatement>(converted, new GlobalImplicitIterator());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -765,14 +761,14 @@ public class PropagationGraph implements IFixedPointSystem<PointsToSetVariable>
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Iterator<PointsToSetVariable> getVariables() {
|
||||
Iterator<PointsToSetVariable> it = new FilterIterator(delegateGraph.iterator(), new Predicate() {
|
||||
@Override public boolean test(Object x) {
|
||||
Iterator<INodeWithNumber> it = new FilterIterator<>(delegateGraph.iterator(), new Predicate<INodeWithNumber>() {
|
||||
@Override public boolean test(INodeWithNumber x) {
|
||||
return x instanceof IVariable;
|
||||
}
|
||||
});
|
||||
return it;
|
||||
Iterator<PointsToSetVariable> converted = new MapIterator<INodeWithNumber, PointsToSetVariable>(it, PointsToSetVariable.class::cast);
|
||||
return converted;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -37,9 +37,7 @@ import com.ibm.wala.ipa.cha.IClassHierarchy;
|
|||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ssa.SymbolTable;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.util.collections.FilterIterator;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.*;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
|
||||
|
@ -178,12 +176,13 @@ public class TypeBasedHeapModel implements HeapModel {
|
|||
@Override
|
||||
public Iterator<PointerKey> iteratePointerKeys() {
|
||||
initAllPKeys();
|
||||
return new FilterIterator<>(pKeys.values().iterator(), new Predicate() {
|
||||
Iterator<Object> filtered = new FilterIterator<Object>(pKeys.values().iterator(), new Predicate<Object>() {
|
||||
@Override
|
||||
public boolean test(Object o) {
|
||||
return o instanceof PointerKey;
|
||||
}
|
||||
});
|
||||
return new MapIterator<Object, PointerKey>(filtered, PointerKey.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -842,9 +842,8 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
|
|||
|
||||
// a successor node is a return site if it is in the same
|
||||
// procedure, and is not the entry() node.
|
||||
Predicate isReturn = new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
BasicBlockInContext other = (BasicBlockInContext) o;
|
||||
Predicate<BasicBlockInContext> isReturn = new Predicate<BasicBlockInContext>() {
|
||||
@Override public boolean test(BasicBlockInContext other) {
|
||||
return !other.isEntryBlock() && node.equals(other.getNode());
|
||||
}
|
||||
};
|
||||
|
@ -863,7 +862,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
|
|||
Iterator<? extends T> it = cfg.getPredNodes(returnBlock.getDelegate());
|
||||
final CGNode node = returnBlock.getNode();
|
||||
|
||||
Predicate<? extends T> dispatchFilter = new Predicate<T>() {
|
||||
Predicate<T> dispatchFilter = new Predicate<T>() {
|
||||
@Override public boolean test(T callBlock) {
|
||||
BasicBlockInContext<T> bb = new BasicBlockInContext<T>(node, callBlock);
|
||||
if (!hasCall(bb, cfg)) {
|
||||
|
|
|
@ -225,9 +225,9 @@ public class PrunedCFG<I, T extends IBasicBlock<I>> extends AbstractNumberedGrap
|
|||
return max;
|
||||
}
|
||||
|
||||
private Iterator<T> filterNodes(Iterator nodeIterator) {
|
||||
return new FilterIterator<T>(nodeIterator, new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
private Iterator<T> filterNodes(Iterator<T> nodeIterator) {
|
||||
return new FilterIterator<T>(nodeIterator, new Predicate<T>() {
|
||||
@Override public boolean test(T o) {
|
||||
return subset.contains(o);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -644,8 +644,8 @@ public class HeapReachingDefs<T extends InstanceKey> {
|
|||
return null;
|
||||
} else {
|
||||
// only static fields are actually killed
|
||||
Predicate staticFilter = new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
Predicate<PointerKey> staticFilter = new Predicate<PointerKey>() {
|
||||
@Override public boolean test(PointerKey o) {
|
||||
return o instanceof StaticFieldKey;
|
||||
}
|
||||
};
|
||||
|
@ -654,10 +654,9 @@ public class HeapReachingDefs<T extends InstanceKey> {
|
|||
if (kill.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
Predicate f = new Predicate() {
|
||||
Predicate<Statement> f = new Predicate<Statement>() {
|
||||
// accept any statement which writes a killed location.
|
||||
@Override public boolean test(Object o) {
|
||||
Statement s = (Statement) o;
|
||||
@Override public boolean test(Statement s) {
|
||||
Collection m = getMod(s, node, heapModel, pa, exclusions);
|
||||
for (PointerKey k : kill) {
|
||||
if (m.contains(k)) {
|
||||
|
|
|
@ -53,12 +53,7 @@ import com.ibm.wala.ssa.SSAPhiInstruction;
|
|||
import com.ibm.wala.ssa.SSAPiInstruction;
|
||||
import com.ibm.wala.ssa.SSAReturnInstruction;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.util.collections.FilterIterator;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Iterator2Collection;
|
||||
import com.ibm.wala.util.collections.Iterator2Iterable;
|
||||
import com.ibm.wala.util.collections.MapUtil;
|
||||
import com.ibm.wala.util.collections.*;
|
||||
import com.ibm.wala.util.config.SetOfClasses;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
|
@ -679,8 +674,8 @@ public class PDG<T extends InstanceKey> implements NumberedGraph<Statement> {
|
|||
|
||||
// in reaching defs calculation, exclude heap statements that are
|
||||
// irrelevant.
|
||||
Predicate f = new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
Predicate<Statement> f = new Predicate<Statement>() {
|
||||
@Override public boolean test(Statement o) {
|
||||
if (o instanceof HeapStatement) {
|
||||
HeapStatement h = (HeapStatement) o;
|
||||
return h.getLocation().equals(pk);
|
||||
|
@ -771,8 +766,8 @@ public class PDG<T extends InstanceKey> implements NumberedGraph<Statement> {
|
|||
* @return Statements representing each return instruction in the ir
|
||||
*/
|
||||
private Collection<NormalStatement> computeReturnStatements(final IR ir) {
|
||||
Predicate filter = new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
Predicate<Statement> filter = new Predicate<Statement>() {
|
||||
@Override public boolean test(Statement o) {
|
||||
if (o instanceof NormalStatement) {
|
||||
NormalStatement s = (NormalStatement) o;
|
||||
SSAInstruction st = ir.getInstructions()[s.getInstructionIndex()];
|
||||
|
@ -782,7 +777,10 @@ public class PDG<T extends InstanceKey> implements NumberedGraph<Statement> {
|
|||
}
|
||||
}
|
||||
};
|
||||
return Iterator2Collection.toSet(new FilterIterator<NormalStatement>(iterator(), filter));
|
||||
return Iterator2Collection.toSet(
|
||||
new MapIterator<Statement, NormalStatement>(
|
||||
new FilterIterator<Statement>(iterator(), filter),
|
||||
NormalStatement.class::cast));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -97,9 +97,8 @@ class SDGSupergraph implements ISupergraph<Statement, PDG<? extends InstanceKey>
|
|||
public Iterator<? extends Statement> getCalledNodes(Statement call) {
|
||||
switch (call.getKind()) {
|
||||
case NORMAL:
|
||||
Predicate<?> f = new Predicate() {
|
||||
@Override public boolean test(Object o) {
|
||||
Statement s = (Statement) o;
|
||||
Predicate<Statement> f = new Predicate<Statement>() {
|
||||
@Override public boolean test(Statement s) {
|
||||
return isEntry(s);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -258,9 +258,9 @@ public class DefaultFixedPointSystem<T extends IVariable<T>> implements IFixedPo
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> getVariables() {
|
||||
return new FilterIterator<>(graph.iterator(), new Predicate<T>() {
|
||||
@Override public boolean test(T x) {
|
||||
public Iterator<INodeWithNumber> getVariables() {
|
||||
return new FilterIterator<>(graph.iterator(), new Predicate<Object>() {
|
||||
@Override public boolean test(Object x) {
|
||||
return x != null;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -18,10 +18,9 @@ import java.util.function.Predicate;
|
|||
* A <code>FilterIterator</code> filters an <code>Iterator</code> to generate a new one.
|
||||
*/
|
||||
public class FilterIterator<T> implements java.util.Iterator<T> {
|
||||
final Iterator<?> i;
|
||||
final Iterator<? extends T> i;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
final Predicate f;
|
||||
final Predicate<? super T> f;
|
||||
|
||||
private T next = null;
|
||||
|
||||
|
@ -31,8 +30,7 @@ public class FilterIterator<T> implements java.util.Iterator<T> {
|
|||
* @param i the original iterator
|
||||
* @param f a filter which defines which elements belong to the generated iterator
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public FilterIterator(Iterator<?> i, Predicate f) {
|
||||
public FilterIterator(Iterator<? extends T> i, Predicate<? super T> f) {
|
||||
if (i == null) {
|
||||
throw new IllegalArgumentException("null i");
|
||||
}
|
||||
|
@ -47,12 +45,11 @@ public class FilterIterator<T> implements java.util.Iterator<T> {
|
|||
/**
|
||||
* update the internal state to prepare for the next access to this iterator
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void advance() {
|
||||
while (i.hasNext()) {
|
||||
Object o = i.next();
|
||||
T o = i.next();
|
||||
if (f.test(o)) {
|
||||
next = (T) o;
|
||||
next = o;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class IteratorUtil {
|
|||
|
||||
public static <T, S extends T> Iterator<S> filter(Iterator<T> iterator, final Class<S> cls) {
|
||||
return new MapIterator<>(
|
||||
new FilterIterator<T>(iterator, new Predicate<T>() {
|
||||
new FilterIterator<>(iterator, new Predicate<T>() {
|
||||
@Override public boolean test(T o) {
|
||||
return cls.isInstance(o);
|
||||
}
|
||||
|
|
|
@ -58,12 +58,12 @@ public class GraphReachability<T, S> {
|
|||
* @param filter "interesting" node definition
|
||||
* @throws IllegalArgumentException if g is null
|
||||
*/
|
||||
public GraphReachability(Graph<T> g, Predicate<?> filter) {
|
||||
public GraphReachability(Graph<T> g, Predicate<? super T> filter) {
|
||||
if (g == null) {
|
||||
throw new IllegalArgumentException("g is null");
|
||||
}
|
||||
this.g = g;
|
||||
Iterator<S> i = new FilterIterator<>(g.iterator(), filter);
|
||||
Iterator<T> i = new FilterIterator<>(g.iterator(), filter);
|
||||
domain = new MutableMapping<>((Iterator2Collection.toSet(i)).toArray());
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ public class DFS {
|
|||
* @throws IllegalArgumentException if C is null
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static <T> Collection<T> getReachableNodes(final Graph<T> G, Collection<? extends T> C, @SuppressWarnings("rawtypes") final Predicate filter) {
|
||||
public static <T> Collection<T> getReachableNodes(final Graph<T> G, Collection<? extends T> C, final Predicate<? super T> filter) {
|
||||
if (C == null) {
|
||||
throw new IllegalArgumentException("C is null");
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class RtJar {
|
|||
public static void main(String[] args) {
|
||||
@SuppressWarnings("resource")
|
||||
JarFile rt = getRtJar(new MapIterator<>(
|
||||
new FilterIterator<String>(
|
||||
new FilterIterator<>(
|
||||
new ArrayIterator<>(System.getProperty("sun.boot.class.path").split(File.pathSeparator)),
|
||||
new Predicate<String>() {
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue