/******************************************************************************* * Copyright (c) 2013 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.analysis.reflection; import com.ibm.wala.analysis.typeInference.PointType; import com.ibm.wala.analysis.typeInference.TypeAbstraction; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.ipa.callgraph.Context; import com.ibm.wala.ipa.callgraph.ContextItem; import com.ibm.wala.ipa.callgraph.ContextKey; import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; /** * A context which may be used if * <ul> * <li>the method to be interpreted is either * {@link java.lang.Class#getMethod(String, Class...)} or * {@link java.lang.Class#getDeclaredMethod(String, Class...)},</li> * <li>the type of the "this" argument is known and</li> * <li>the value of the first argument (the method name) is a constant.</li> * </ul> * * In the special case described above, * {@link GetMethodContextInterpreter} * and * {@link GetMethodContextSelector} * should be preferred over * {@link JavaLangClassContextInterpreter} * and * {@link JavaLangClassContextSelector}, * as * {@link GetMethodContextInterpreter} * and * {@link GetMethodContextSelector} * drastically reduce the number of methods returned increasing the precision of the analysis. * Thus, * {@link GetMethodContextInterpreter} * and * {@link GetMethodContextSelector} * should be placed in be placed in front of * {@link JavaLangClassContextInterpreter} * and * {@link JavaLangClassContextSelector} * . * @author Michael Heilmann * @see com.ibm.wala.analysis.reflection.GetMethodContextInterpreter * @see com.ibm.wala.analysis.reflection.GetMethodContextSelector * TODO Do the same for {@link Class#getField(String)} and {@link Class#getDeclaredField(String)}. */ public class GetMethodContext implements Context { /** * The type abstraction. */ private final TypeAbstraction type; /** * The method name. */ private final ConstantKey name; /** * Construct this GetMethodContext. * @param type the type * @param name the name of the method */ public GetMethodContext(TypeAbstraction type,ConstantKey name) { if (type == null) { throw new IllegalArgumentException("null == type"); } this.type = type; if (name == null) { throw new IllegalArgumentException("null == name"); } this.name = name; } @Override public ContextItem get(ContextKey name) { if (name == ContextKey.RECEIVER) { return type; } else if (name == ContextKey.PARAMETERS[0]) { if (type instanceof PointType) { IClass cls = ((PointType) type).getIClass(); return new FilteredPointerKey.SingleClassFilter(cls); } else { return null; } } else if (name == ContextKey.PARAMETERS[1]) { return new FilteredPointerKey.SingleClassFilter(this.name.getConcreteType()); } else { return null; } } @Override public String toString() { return "GetMethodContext<" + type + ", " + name + ">"; } @Override public int hashCode() { return 6367 * type.hashCode() * name.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass().equals(obj.getClass())) { GetMethodContext other = (GetMethodContext) obj; return type.equals(other.type) && name.equals(other.name); } else { return false; } } /** * Get the type. * @return the type */ public TypeAbstraction getType() { return type; } /** * Get the name. * @return the name */ public String getName() { return (String)name.getValue(); } }