code: package us.msu.cse.repair.core.parser;
  
  import java.io.IOException;
  import java.lang.reflect.Method;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.eclipse.jdt.core.dom.IMethodBinding;
  import org.eclipse.jdt.core.dom.ITypeBinding;
  import org.eclipse.jdt.core.dom.Modifier;
  
  import us.msu.cse.repair.core.util.Helper;
  
  public class MethodDetector {
  	List<ModificationPoint> modificationPoints;
  
  	Map<String, ITypeBinding> declaredClasses;
  
  	Set<String> dependences;
  	URLClassLoader classLoader;
  
  	Map<String, Map<String, MethodInfo>> declaredMethodMap;
  	Map<String, Map<String, MethodInfo>> inheritedMethodMap;
  	Map<String, Map<String, MethodInfo>> outerMethodMap;
  
  	public MethodDetector(List<ModificationPoint> modificationPoints, Map<String, ITypeBinding> declaredClasses,
  			Set<String> dependences) throws MalformedURLException {
  		this.modificationPoints = modificationPoints;
  		this.declaredClasses = declaredClasses;
  		this.dependences = dependences;
  
  		declaredMethodMap = new HashMap<String, Map<String, MethodInfo>>();
  		inheritedMethodMap = new HashMap<String, Map<String, MethodInfo>>();
  		outerMethodMap = new HashMap<String, Map<String, MethodInfo>>();
  
  		if (dependences != null) {
  			URL[] urls = Helper.getURLs(dependences);
  			classLoader = new URLClassLoader(urls);
  		} else
  			classLoader = new URLClassLoader(new URL[0]);
  
  	}
  
  	public void detect() throws ClassNotFoundException, IOException {
  		for (ModificationPoint mp : modificationPoints)
  			detectVisibleMethods(mp);
  		classLoader.close();
  	}
  
  	private void detectVisibleMethods(ModificationPoint mp) throws ClassNotFoundException {
  		// TODO Auto-generated method stub
  		String className = mp.getLCNode().getClassName();
  
  		detectVisibleMethods(className);
  
  		Map<String, MethodInfo> declaredMethods = declaredMethodMap.get(className);
  		Map<String, MethodInfo> inheritedMethods = inheritedMethodMap.get(className);
  		Map<String, MethodInfo> outerMethods = outerMethodMap.get(className);
  
  		if (mp.isInStaticMethod()) {
  			declaredMethods = getStaticMethods(declaredMethods);
  			inheritedMethods = getStaticMethods(inheritedMethods);
  		}
  
  		mp.setDeclaredMethods(declaredMethods);
  		mp.setInheritedMethods(inheritedMethods);
  		mp.setOuterMethods(outerMethods);
  	}
  
  	void detectVisibleMethods(String className) throws ClassNotFoundException {
  		if (declaredMethodMap.containsKey(className))
  			return;
  
  		Map<String, MethodInfo> methods;
  		String superClassName = null, outerClassName = null;
  		boolean isStaticClass;
  
  		if (declaredClasses.containsKey(className)) {
  			ITypeBinding tb = declaredClasses.get(className);
  			IMethodBinding[] mbs = tb.getDeclaredMethods();
  
  			methods = Helper.getMethodInfos(mbs);
  
  			ITypeBinding superClass = tb.getSuperclass();
  			if (superClass != null && !superClass.isInterface())
  				superClassName = superClass.getBinaryName();
  
  			ITypeBinding outerClass = tb.getDeclaringClass();
  			if (outerClass != null && !outerClass.isInterface())
  				outerClassName = outerClass.getBinaryName();
  
  			isStaticClass = Modifier.isStatic(tb.getModifiers());
  		} else {
  			Class<?> target = classLoader.loadClass(className);
  			Method[] mds = target.getDeclaredMethods();
  			methods = Helper.getMethodInfos(mds);
  
  			Class<?> superClass = target.getSuperclass();
  			if (superClass != null && !superClass.isInterface())
  				superClassName = superClass.getName();
  
  			Class<?> outerClass = target.getDeclaringClass();
  			if (outerClass != null && !outerClass.isInterface())
  				outerClassName = outerClass.getName();
  
  			isStaticClass = Modifier.isStatic(target.getModifiers());
  		}
  		declaredMethodMap.put(className, methods);
  
  		Map<String, MethodInfo> inheritedMethods = new HashMap<String, MethodInfo>();
  		if (superClassName != null) {
  			detectVisibleMethods(superClassName);
  
  			Map<String, MethodInfo> declaredMethodsOfSuper = declaredMethodMap.get(superClassName);
  			Map<String, MethodInfo> inheritedMethodsOfSuper = inheritedMethodMap.get(superClassName);
  
  			collectInheritedMethods(inheritedMethodsOfSuper, inheritedMethods, className, superClassName);
  			collectInheritedMethods(declaredMethodsOfSuper, inheritedMethods, className, superClassName);
  		}
  
  		HashMap<String, MethodInfo> outerMethods = new HashMap<String, MethodInfo>();
  		if (outerClassName != null) {
  			detectVisibleMethods(outerClassName);
  
  			Map<String, MethodInfo> declaredMethodsOfOuter = declaredMethodMap.get(outerClassName);
  			Map<String, MethodInfo> inheritedMethodsOfOuter = inheritedMethodMap.get(outerClassName);
  			Map<String, MethodInfo> outerMethodsOfOuter = outerMethodMap.get(outerClassName);
  
  			collectOuterMethods(outerMethodsOfOuter, outerMethods, isStaticClass);
  			collectOuterMethods(inheritedMethodsOfOuter, outerMethods, isStaticClass);
  			collectOuterMethods(declaredMethodsOfOuter, outerMethods, isStaticClass);
  
  			filterOuterMethods(outerMethods, methods, inheritedMethods);
  
  		}
  
  		inheritedMethodMap.put(className, inheritedMethods);
  		outerMethodMap.put(className, outerMethods);
  	}
  
  	void filterOuterMethods(Map<String, MethodInfo> outerMethods, Map<String, MethodInfo> methods,
  			Map<String, MethodInfo> inheritedMethods) {
  		Iterator<String> iterator = outerMethods.keySet().iterator();
  		while (iterator.hasNext()) {
  			String key = (String) iterator.next();
  			if (containsMethodName(key, methods) || containsMethodName(key, inheritedMethods))
  				iterator.remove();
  		}
  	}
  
  	boolean containsMethodName(String key, Map<String, MethodInfo> methods) {
  		String methodName = Helper.getMethodName(key);
  
  		for (String str : methods.keySet()) {
  			String name = Helper.getMethodName(str);
  			if (name.equals(methodName))
  				return true;
  		}
  		return false;
  	}
  
  	void collectInheritedMethods(Map<String, MethodInfo> map, Map<String, MethodInfo> inheritedMethods,
  			String className, String superClassName) {
  		for (Map.Entry<String, MethodInfo> entry : map.entrySet()) {
  			boolean flag1 = Helper.isPublicMethod(entry.getValue());
  			boolean flag2 = Helper.isProtectedMethod(entry.getValue());
  			boolean flag3 = Helper.isPackagePrivateMethod(entry.getValue())
  					&& Helper.isInSamePackage(className, superClassName);
  
  			if (flag1 || flag2 || flag3)
  				inheritedMethods.put(entry.getKey(), entry.getValue());
  		}
  	}
  
  	void collectOuterMethods(Map<String, MethodInfo> map, Map<String, MethodInfo> outerMethods, boolean isStaticClass) {
  
  		if (!isStaticClass) {
  			for (Map.Entry<String, MethodInfo> entry : map.entrySet())
  				outerMethods.put(entry.getKey(), entry.getValue());
  		} else {
  			for (Map.Entry<String, MethodInfo> entry : map.entrySet()) {
  				if (Helper.isStaticMethod(entry.getValue()))
  					outerMethods.put(entry.getKey(), entry.getValue());
  			}
  		}
  	}
  
  	Map<String, MethodInfo> getStaticMethods(Map<String, MethodInfo> methods) {
  		Map<String, MethodInfo> staticMethods = new HashMap<String, MethodInfo>();
  
  		for (Map.Entry<String, MethodInfo> entry : methods.entrySet()) {
  			if (Helper.isStaticMethod(entry.getValue()))
  				staticMethods.put(entry.getKey(), entry.getValue());
  		}
  
  		return staticMethods;
  	}
  
  }
  