/******************************************************************************* * Copyright (c) 2006, 2016 Mountainminds GmbH & Co. KG and Contributors * 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: * Marc R. Hoffmann - initial API and implementation * ******************************************************************************/ package com.mountainminds.eclemma.internal.core.analysis; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; /** * Internal utility to select methods by their binary signature. For performance * optimization matching is performed in two steps, where the first step should * quickly identify methods in most situations: Identification by name and * parameter count. Only if the first step does fails to identify a method * unambiguously the parameter types are resolved in a second step. */ public class MethodLocator { /** Index on methods by name and parameter count. */ private final Map<String, IMethod> indexParamCount = new HashMap<String, IMethod>(); /** * For the keys in this set there are multiple overloaded methods with the * same name and the more expensive signature resolver must be used. */ private final Set<String> ambiguous = new HashSet<String>(); /** Index on methods by name and parameter signature. */ private final Map<String, IMethod> indexParamSignature = new HashMap<String, IMethod>(); private final IType type; /** * Initializes a new locator for method search within the given type. * * @param type * type to search methods in * @throws JavaModelException */ public MethodLocator(final IType type) throws JavaModelException { this.type = type; for (final IMethod m : type.getMethods()) { addToIndex(m); } } /** * Searches for the method with the given binary name. * * @param name * binary method name * @param signature * binary method signature * @return method or <code>null</code> */ public IMethod findMethod(String name, String signature) { if ("<init>".equals(name)) { //$NON-NLS-1$ name = type.getElementName(); } final String paramCountKey = createParamCountKey(name, signature); if (ambiguous.contains(paramCountKey)) { return indexParamSignature.get(createParamSignatureKey(name, signature)); } else { return indexParamCount.get(paramCountKey); } } private void addToIndex(final IMethod method) throws JavaModelException { final String paramCountKey = createParamCountKey(method); if (ambiguous.contains(paramCountKey)) { indexParamSignature.put(createParamSignatureKey(method), method); } else { final IMethod existing = indexParamCount.get(paramCountKey); if (existing == null) { indexParamCount.put(paramCountKey, method); } else { ambiguous.add(paramCountKey); indexParamSignature.put(createParamSignatureKey(existing), existing); indexParamSignature.put(createParamSignatureKey(method), method); } } } private String createParamCountKey(final IMethod method) { return method.getElementName() + "@" + method.getParameterTypes().length; //$NON-NLS-1$ } private String createParamCountKey(final String name, final String fullSignature) { return name + "@" + Signature.getParameterCount(fullSignature); //$NON-NLS-1$ } private String createParamSignatureKey(final IMethod method) throws JavaModelException { return method.getElementName() + "#" //$NON-NLS-1$ + SignatureResolver.getParameters(method); } private String createParamSignatureKey(final String name, final String fullSignature) { return name + "#" + SignatureResolver.getParameters(fullSignature); //$NON-NLS-1$ } }