130 lines
4.8 KiB
Java
130 lines
4.8 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.ipa.callgraph.propagation;
|
|
|
|
import java.util.Collection;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.Set;
|
|
|
|
import com.ibm.wala.classLoader.IClass;
|
|
import com.ibm.wala.classLoader.SyntheticMethod;
|
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
|
import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter;
|
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
|
import com.ibm.wala.ipa.slicer.NormalReturnCallee;
|
|
import com.ibm.wala.ipa.slicer.NormalStatement;
|
|
import com.ibm.wala.ipa.slicer.Slicer;
|
|
import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions;
|
|
import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions;
|
|
import com.ibm.wala.ipa.slicer.Statement;
|
|
import com.ibm.wala.ipa.slicer.Statement.Kind;
|
|
import com.ibm.wala.ssa.SSACheckCastInstruction;
|
|
import com.ibm.wala.types.TypeReference;
|
|
import com.ibm.wala.util.CancelException;
|
|
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
|
import com.ibm.wala.util.Predicate;
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
|
|
|
/**
|
|
* A helper class which can modify a {@link PropagationCallGraphBuilder} to deal with reflective factory methods.
|
|
*/
|
|
public class ReflectionHandler {
|
|
private final static boolean VERBOSE = false;
|
|
|
|
private final PropagationCallGraphBuilder builder;
|
|
|
|
public ReflectionHandler(PropagationCallGraphBuilder builder) {
|
|
this.builder = builder;
|
|
}
|
|
|
|
/**
|
|
* update the pointer analysis solver based on flow of reflective factory results to checkcasts
|
|
* @param monitor
|
|
*
|
|
* @return true if anything has changed
|
|
* @throws CancelException
|
|
* @throws IllegalArgumentException
|
|
*/
|
|
protected boolean updateForReflection(IProgressMonitor monitor) throws IllegalArgumentException, CancelException {
|
|
|
|
Collection<Statement> returnStatements = computeFactoryReturnStatements();
|
|
Set<CGNode> changedNodes = HashSetFactory.make();
|
|
for (Statement st : returnStatements) {
|
|
if (VERBOSE) {
|
|
System.err.println("Slice " + st);
|
|
}
|
|
Collection<Statement> slice = Slicer.computeForwardSlice(st, builder.callGraph, null, DataDependenceOptions.REFLECTION, ControlDependenceOptions.NONE);
|
|
if (VERBOSE) {
|
|
for (Statement x : slice) {
|
|
System.err.println(" " + x);
|
|
}
|
|
}
|
|
Predicate<Statement> f = new Predicate<Statement>() {
|
|
@Override
|
|
public boolean test(Statement s) {
|
|
if (s.getKind() == Kind.NORMAL) {
|
|
return ((NormalStatement) s).getInstruction() instanceof SSACheckCastInstruction;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
};
|
|
Collection<Statement> casts = Predicate.filter(slice.iterator(), f);
|
|
changedNodes.addAll(modifyFactoryInterpreter(st, casts, builder.getContextInterpreter(), builder.getClassHierarchy()));
|
|
}
|
|
for (Iterator<CGNode> it = changedNodes.iterator(); it.hasNext();) {
|
|
builder.addConstraintsFromChangedNode(it.next(), monitor);
|
|
}
|
|
return changedNodes.size() > 0;
|
|
|
|
}
|
|
|
|
private Collection<Statement> computeFactoryReturnStatements() {
|
|
// todo: clean up logic with inheritance, delegation.
|
|
HashSet<Statement> result = HashSetFactory.make();
|
|
for (Iterator it = builder.getCallGraph().iterator(); it.hasNext();) {
|
|
CGNode n = (CGNode) it.next();
|
|
if (n.getMethod() instanceof SyntheticMethod) {
|
|
SyntheticMethod m = (SyntheticMethod) n.getMethod();
|
|
if (m.isFactoryMethod()) {
|
|
result.add(new NormalReturnCallee(n));
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* modify the contextInterpreter to account for new interpretations of factory methods.
|
|
*
|
|
* @return set of nodes whose interpretation has changed.
|
|
*/
|
|
private static Set<CGNode> modifyFactoryInterpreter(Statement returnStatement, Collection<Statement> casts,
|
|
RTAContextInterpreter contextInterpreter, IClassHierarchy cha) {
|
|
HashSet<CGNode> result = HashSetFactory.make();
|
|
|
|
for (Statement st : casts) {
|
|
SSACheckCastInstruction c = (SSACheckCastInstruction) ((NormalStatement) st).getInstruction();
|
|
|
|
for (TypeReference type : c.getDeclaredResultTypes()) {
|
|
IClass klass = cha.lookupClass(type);
|
|
if (klass != null) {
|
|
if (contextInterpreter.recordFactoryType(returnStatement.getNode(), klass)) {
|
|
result.add(returnStatement.getNode());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|