/****************************************************************************** * Copyright (c) 2002 - 2014 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.impl; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.Context; import com.ibm.wala.ipa.callgraph.DelegatingContext; import com.ibm.wala.ipa.callgraph.ContextSelector; import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; import com.ibm.wala.util.intset.IntSet; /** * Checks ContextSelectors A and B, then returns the union of their findings. * * The returned Context contains the ContextKeys from A and B. If for a given key a value is * generated by A as well as B the value generated by A has the precedence. * * As the UnionContextSelector optionally returns a DelegatingContext it cannot be used to * anihilate ContextValues of B to null. * * @see com.ibm.wala.ipa.callgraph.impl.DelegatingContextSelector * * @author Tobias Blaschke <code@tobiasblaschke.de> */ public class UnionContextSelector implements ContextSelector { private final ContextSelector A; private final ContextSelector B; public UnionContextSelector(final ContextSelector A, final ContextSelector B) { if (A == null) { throw new IllegalArgumentException("The ContextSelector given as A may not be null"); } if (B == null) { throw new IllegalArgumentException("The ContextSelector given as B may not be null"); } this.A = A; this.B = B; } /** * If only one Context exists return it, else return a DelegatingContext. */ @Override public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { final Context ctxA = A.getCalleeTarget(caller, site, callee, receiver); final Context ctxB = B.getCalleeTarget(caller, site, callee, receiver); if (ctxA == null) { return ctxB; } else if (ctxB == null) { return ctxA; } else { final Context ctxU = new DelegatingContext(ctxA, ctxB); return ctxU; } } @Override public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { return A.getRelevantParameters(caller, site).union(B.getRelevantParameters(caller, site)); } @Override public String toString() { return "<UnionContextSelector A=" + A + " B=" + B + " />"; } }