]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/generic/ClassRef.java
migrated to svn revision 33108
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / constants / generic / ClassRef.java
1 package org.simantics.scl.compiler.constants.generic;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Field;
5 import java.lang.reflect.Method;
6 import java.lang.reflect.Modifier;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.List;
10
11 import org.cojen.classfile.TypeDesc;
12 import org.simantics.scl.compiler.constants.generic.MethodRef.ConstructorRef;
13 import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
14 import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef;
15 import org.simantics.scl.compiler.constants.generic.MethodRef.SetFieldRef;
16 import org.simantics.scl.compiler.constants.generic.MethodRef.SetStaticFieldRef;
17 import org.simantics.scl.compiler.constants.generic.MethodRef.StaticFieldRef;
18 import org.simantics.scl.compiler.constants.generic.MethodRef.StaticMethodRef;
19 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
20
21 import gnu.trove.map.hash.THashMap;
22
23 /**
24  * This class is a reference to a Java class that contains a map of MethodRef for each
25  * method declared by the referenced class.
26  * 
27  * Use {@link #getMethodRefs(String)} to get a list of overloaded methods for a given name.
28  */
29 public class ClassRef {
30         /**
31          * A zero length array used as the value of argument lists of zero-arity methods.
32          */
33     public static final TypeDesc[] NO_PARAMS = new TypeDesc[0];
34     
35     /**
36      * A map from method names to lists of identically named methods.
37      */
38     private THashMap<String, ArrayList<MethodRef>> methods = 
39             new THashMap<String, ArrayList<MethodRef>>();
40     
41     /**
42      * Get a list of methods with a given name.
43      * @param methodName A method name
44      * @return  A list of {@link MethodRef} instances that share the name {@code methodName}.
45      */
46     public List<MethodRef> getMethodRefs(String methodName) {
47         List<MethodRef> refs = methods.get(methodName);
48         if(refs == null)
49             return Collections.emptyList();
50         return refs;
51     }
52
53     /**
54      * Construct a {@link ClassRef} with class loaders and a class name.
55      * @throws ClassNotFoundException  if the class is not found.
56      */
57     public ClassRef(ClassLoader classLoader, String className) throws ClassNotFoundException {
58         analyzeClass(classLoader.loadClass(className), className);
59     }
60
61     /**
62      * Construct a {@link ClassRef} for a Java class object.
63      */
64     public ClassRef(Class<?> clazz) {
65         analyzeClass(clazz, MethodBuilderBase.getClassName(clazz));
66     }
67
68     /**
69      * Analyse the Java class and store {@link MethodRef} entries for all methods implemented by the class.
70      */
71     private void analyzeClass(Class<?> clazz, String className) {
72         boolean isInterface = clazz.isInterface();
73         for(Constructor<?> constructor : clazz.getConstructors()) {
74             addMethodRef("<init>", new ConstructorRef(
75                     className,
76                     toTypeDescs(constructor.getParameterTypes())
77                     ));
78         }
79         for(Method method : clazz.getMethods()) {     
80             if(method.isSynthetic())
81                 continue;
82             String methodName = method.getName();
83             TypeDesc returnType = TypeDesc.forClass(method.getReturnType());
84             TypeDesc[] parameters = toTypeDescs(method.getParameterTypes());
85             
86             int modifiers = method.getModifiers();
87             if(Modifier.isStatic(modifiers))
88                 addMethodRef(methodName, new StaticMethodRef(
89                         className, methodName,
90                         returnType,
91                         parameters
92                         ));
93             else
94                 addMethodRef(methodName, new ObjectMethodRef(
95                         isInterface,
96                         className, methodName,
97                         returnType,
98                         parameters
99                         ));
100         }
101         for(Field field : clazz.getFields()) {
102             String fieldName = field.getName();
103             TypeDesc type = TypeDesc.forClass(field.getType());
104             
105             int modifiers = field.getModifiers();
106             if(Modifier.isStatic(modifiers)) {
107                 addMethodRef(fieldName, new StaticFieldRef(
108                         className,
109                         fieldName,
110                         type
111                         ));
112                 addMethodRef("<set>" + fieldName, new SetStaticFieldRef(
113                         className,
114                         fieldName,
115                         type
116                         ));
117             }
118             else {
119                 addMethodRef(fieldName, new FieldRef(
120                         className,
121                         fieldName,
122                         type
123                         ));
124                 addMethodRef("<set>" + fieldName, new SetFieldRef(
125                         className,
126                         fieldName,
127                         type
128                         ));
129             }
130         }
131     }
132     
133     /**
134      * Create an array of {@link TypeDesc} instances for an array of Class instances.
135      * For an empty array of classes the result will always be the empty array constant {@link #NO_PARAMS}.
136      */
137     private static TypeDesc[] toTypeDescs(Class<?>[] classes) {
138         if(classes.length == 0)
139             return NO_PARAMS;
140         TypeDesc[] result = new TypeDesc[classes.length];
141         for(int i=0;i<result.length;++i)
142             result[i] = TypeDesc.forClass(classes[i]);
143         return result;
144     }
145     
146     /**
147      * Add a {@code MethodRef} to the {@link #methods} map. 
148      */
149     private void addMethodRef(String name, MethodRef ref) {
150         ArrayList<MethodRef> l = methods.get(name);
151         if(l == null) {
152             l = new ArrayList<MethodRef>(2);
153             methods.put(name, l);
154         }
155         l.add(ref);
156     }   
157 }