IDEA-285172 - [decompiler] - StrongConnectivityHelper refactoring
[idea/community.git] / plugins / java-decompiler / engine / src / org / jetbrains / java / decompiler / modules / decompiler / ClasspathHelper.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.java.decompiler.modules.decompiler;
3
4 import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
5 import org.jetbrains.java.decompiler.struct.gen.VarType;
6
7 import java.lang.reflect.Method;
8 import java.util.Collections;
9 import java.util.HashMap;
10 import java.util.Map;
11
12 public final class ClasspathHelper {
13
14   private static final Map<String, Method> METHOD_CACHE = Collections.synchronizedMap(new HashMap<>());
15
16   public static Method findMethod(String classname, String methodName, MethodDescriptor descriptor) {
17     String targetClass = classname.replace('/', '.');
18     String methodSignature = buildMethodSignature(targetClass + '.' + methodName, descriptor);
19
20     Method method;
21     if (METHOD_CACHE.containsKey(methodSignature)) {
22       method = METHOD_CACHE.get(methodSignature);
23     }
24     else {
25       method = findMethodOnClasspath(targetClass, methodSignature);
26       METHOD_CACHE.put(methodSignature, method);
27     }
28
29     return method;
30   }
31
32   private static Method findMethodOnClasspath(String targetClass, String methodSignature) {
33     try {
34       // use bootstrap classloader to only provide access to JRE classes
35       Class cls = new ClassLoader(null) {}.loadClass(targetClass);
36       for (Method mtd : cls.getMethods()) {
37         // use contains() to ignore access modifiers and thrown exceptions
38         if (mtd.toString().contains(methodSignature)) {
39           return mtd;
40         }
41       }
42     }
43     catch (Exception e) {
44       // ignore
45     }
46     return null;
47   }
48
49   private static String buildMethodSignature(String name, MethodDescriptor md) {
50     StringBuilder sb = new StringBuilder();
51
52     appendType(sb, md.ret);
53     sb.append(' ').append(name).append('(');
54     for (VarType param : md.params) {
55       appendType(sb, param);
56       sb.append(',');
57     }
58     if (sb.charAt(sb.length() - 1) == ',') {
59       sb.setLength(sb.length() - 1);
60     }
61     sb.append(')');
62
63     return sb.toString();
64   }
65
66   private static void appendType(StringBuilder sb, VarType type) {
67     sb.append(type.value.replace('/', '.'));
68     for (int i = 0; i < type.arrayDim; i++) {
69       sb.append("[]");
70     }
71   }
72 }