]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/generic/ClassRef.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / constants / generic / ClassRef.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/generic/ClassRef.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/generic/ClassRef.java
new file mode 100644 (file)
index 0000000..5686d63
--- /dev/null
@@ -0,0 +1,157 @@
+package org.simantics.scl.compiler.constants.generic;
+
+import gnu.trove.map.hash.THashMap;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.constants.generic.MethodRef.ConstructorRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.SetFieldRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.SetStaticFieldRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.StaticFieldRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.StaticMethodRef;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
+
+/**
+ * This class is a reference to a Java class that contains a map of MethodRef for each
+ * method declared by the referenced class.
+ * 
+ * Use {@link #getMethodRefs(String)} to get a list of overloaded methods for a given name.
+ */
+public class ClassRef {
+       /**
+        * A zero length array used as the value of argument lists of zero-arity methods.
+        */
+    public static final TypeDesc[] NO_PARAMS = new TypeDesc[0];
+    
+    /**
+     * A map from method names to lists of identically named methods.
+     */
+    private THashMap<String, ArrayList<MethodRef>> methods = 
+            new THashMap<String, ArrayList<MethodRef>>();
+    
+    /**
+     * Get a list of methods with a given name.
+     * @param methodName A method name
+     * @return  A list of {@link MethodRef} instances that share the name {@code methodName}.
+     */
+    public List<MethodRef> getMethodRefs(String methodName) {
+        List<MethodRef> refs = methods.get(methodName);
+        if(refs == null)
+            return Collections.emptyList();
+        return refs;
+    }
+
+    /**
+     * Construct a {@link ClassRef} with class loaders and a class name.
+     * @throws ClassNotFoundException  if the class is not found.
+     */
+    public ClassRef(ClassLoader classLoader, String className) throws ClassNotFoundException {
+        analyzeClass(classLoader.loadClass(className), className);
+    }
+
+    /**
+     * Construct a {@link ClassRef} for a Java class object.
+     */
+    public ClassRef(Class<?> clazz) {
+        analyzeClass(clazz, MethodBuilderBase.getClassName(clazz));
+    }
+
+    /**
+     * Analyse the Java class and store {@link MethodRef} entries for all methods implemented by the class.
+     */
+    private void analyzeClass(Class<?> clazz, String className) {
+        boolean isInterface = clazz.isInterface();
+        for(Constructor<?> constructor : clazz.getConstructors()) {
+            addMethodRef("<init>", new ConstructorRef(
+                    className,
+                    toTypeDescs(constructor.getParameterTypes())
+                    ));
+        }
+        for(Method method : clazz.getMethods()) {     
+            if(method.isSynthetic())
+                continue;
+            String methodName = method.getName();
+            TypeDesc returnType = TypeDesc.forClass(method.getReturnType());
+            TypeDesc[] parameters = toTypeDescs(method.getParameterTypes());
+            
+            int modifiers = method.getModifiers();
+            if(Modifier.isStatic(modifiers))
+                addMethodRef(methodName, new StaticMethodRef(
+                        className, methodName,
+                        returnType,
+                        parameters
+                        ));
+            else
+                addMethodRef(methodName, new ObjectMethodRef(
+                        isInterface,
+                        className, methodName,
+                        returnType,
+                        parameters
+                        ));
+        }
+        for(Field field : clazz.getFields()) {
+            String fieldName = field.getName();
+            TypeDesc type = TypeDesc.forClass(field.getType());
+            
+            int modifiers = field.getModifiers();
+            if(Modifier.isStatic(modifiers)) {
+                addMethodRef(fieldName, new StaticFieldRef(
+                        className,
+                        fieldName,
+                        type
+                        ));
+                addMethodRef("<set>" + fieldName, new SetStaticFieldRef(
+                        className,
+                        fieldName,
+                        type
+                        ));
+            }
+            else {
+                addMethodRef(fieldName, new FieldRef(
+                        className,
+                        fieldName,
+                        type
+                        ));
+                addMethodRef("<set>" + fieldName, new SetFieldRef(
+                        className,
+                        fieldName,
+                        type
+                        ));
+            }
+        }
+    }
+    
+    /**
+     * Create an array of {@link TypeDesc} instances for an array of Class instances.
+     * For an empty array of classes the result will always be the empty array constant {@link #NO_PARAMS}.
+     */
+    private static TypeDesc[] toTypeDescs(Class<?>[] classes) {
+        if(classes.length == 0)
+            return NO_PARAMS;
+        TypeDesc[] result = new TypeDesc[classes.length];
+        for(int i=0;i<result.length;++i)
+            result[i] = TypeDesc.forClass(classes[i]);
+        return result;
+    }
+    
+    /**
+     * Add a {@code MethodRef} to the {@link #methods} map. 
+     */
+    private void addMethodRef(String name, MethodRef ref) {
+        ArrayList<MethodRef> l = methods.get(name);
+        if(l == null) {
+            l = new ArrayList<MethodRef>(2);
+            methods.put(name, l);
+        }
+        l.add(ref);
+    }   
+}