]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/types/AbstractRuntimeJavaReferenceValidator.java
(refs #7586) Allow always conversion to Object in SCL-Java interface
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / types / AbstractRuntimeJavaReferenceValidator.java
1 package org.simantics.scl.compiler.internal.codegen.types;
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
9 import org.cojen.classfile.TypeDesc;
10 import org.simantics.scl.compiler.constants.generic.ClassRef;
11 import org.simantics.scl.runtime.function.Function;
12
13 public abstract class AbstractRuntimeJavaReferenceValidator 
14 implements JavaReferenceValidator<Class<?>, Method, Field, Constructor<?>> {
15
16     @Override
17     public abstract Class<?> findClass(TypeDesc name);
18     
19     @Override
20     public boolean isInterface(Class<?> clazz) {
21         return clazz.isInterface();
22     }
23     
24     @Override
25     public boolean isPublic(Class<?> clazz) {
26         return Modifier.isPublic(clazz.getModifiers());
27     }
28
29     @Override
30     public Method[] findCompatibleMethods(Class<?> clazz, boolean isStatic, String name, TypeDesc[] parameterTypes, TypeDesc returnType) {
31         Class<?>[] parameterClasses = new Class[parameterTypes.length];
32         for(int i=0;i<parameterTypes.length;++i)
33             parameterClasses[i] = findClass(parameterTypes[i]);
34         Class<?> returnClass = findClass(returnType);
35         
36         ArrayList<Method> methods = new ArrayList<Method>(2);
37         
38         methodLoop: 
39         for(Method method : clazz.getMethods()) {
40             if(!method.getName().equals(name))
41                 continue;
42             if(Modifier.isStatic(method.getModifiers()) != isStatic)
43                 continue;
44             
45             Class<?>[] parameters = method.getParameterTypes();
46             if(parameters.length != parameterClasses.length)
47                 continue;
48             for(int i=0;i<parameters.length;++i)
49                 if(!parameters[i].isAssignableFrom(parameterClasses[i]))
50                     continue methodLoop;
51
52             if(!returnClass.isAssignableFrom(method.getReturnType()))
53                 continue;            
54             
55             methods.add(method);
56         }       
57         
58         return methods.toArray(new Method[methods.size()]);
59     }
60
61     @Override
62     public TypeDesc getReturnType(Method method) {
63         return TypeDesc.forClass(method.getReturnType());
64     }
65
66     @Override
67     public TypeDesc[] getParameterTypes(Method method) {
68         Class<?>[] parameters = method.getParameterTypes();
69         TypeDesc[] result = new TypeDesc[parameters.length];
70         for(int i=0;i<parameters.length;++i)
71             result[i] = TypeDesc.forClass(parameters[i]);
72         return result;
73     }
74
75     @Override
76     public Constructor<?>[] findCompatibleConstructors(Class<?> clazz,
77             TypeDesc[] types) {
78         Class<?>[] classes = new Class[types.length];
79         for(int i=0;i<types.length;++i)
80             classes[i] = findClass(types[i]);
81         int maxArity = types.length-1;
82         
83         ArrayList<Constructor<?>> constructors = new ArrayList<Constructor<?>>(2);
84         
85         methodLoop: 
86         for(Constructor<?> constructor : clazz.getConstructors()) {           
87             Class<?>[] parameters = constructor.getParameterTypes();
88             int arity = parameters.length;
89             if(arity > maxArity)
90                 continue;
91             for(int i=0;i<parameters.length;++i)
92                 if(!parameters[i].isAssignableFrom(classes[i]))
93                     continue methodLoop;
94             
95             if(arity == maxArity) {
96                 if(!classes[maxArity].isAssignableFrom(clazz))
97                     continue;
98             }
99             else {
100                 if(!Function.class.isAssignableFrom(clazz))
101                     continue;
102             }
103             
104             constructors.add(constructor);
105         }       
106         
107         return constructors.toArray(new Constructor[constructors.size()]);
108     }
109
110     @Override
111     public TypeDesc[] getConstructorParameterTypes(Constructor<?> constructor) {
112         Class<?>[] parameters = constructor.getParameterTypes();
113         TypeDesc[] result = new TypeDesc[parameters.length];
114         for(int i=0;i<parameters.length;++i)
115             result[i] = TypeDesc.forClass(parameters[i]);
116         return result;
117     }
118
119     @Override
120     public Field findField(Class<?> clazz, String name) {
121         try {
122             return clazz.getField(name);
123         } catch(NoSuchFieldException e) {
124             return null;
125         }
126     }
127
128     @Override
129     public boolean isStaticField(Field field) {
130         return Modifier.isStatic(field.getModifiers());
131     }
132
133     @Override
134     public TypeDesc getFieldType(Field field) {
135         return TypeDesc.forClass(field.getType());
136     }
137
138     @Override
139     public boolean isAssignableFrom(TypeDesc to, TypeDesc from) {
140         if(to.equals(from) || to.equals(TypeDesc.OBJECT))
141             return true;
142         Class<?> toClass = findClass(to);
143         Class<?> fromClass = findClass(from);
144         if(toClass == null || fromClass == null)
145             // Note: I added this branch when I noticed that type can be
146             //       one from the module under compilation.
147             // Note2: A problem with this seems to be that also 
148             //        some other type descs go to null, such as double[][]
149             return false; 
150         else
151             return toClass.isAssignableFrom(fromClass);
152     }
153
154     @Override
155     public Method[] chooseBest(Method[] methods) {
156         ArrayList<Method> newResult = new ArrayList<Method>();
157         for(Method method : methods)
158             if(!method.isSynthetic())
159                 newResult.add(method);
160         return newResult.toArray(new Method[newResult.size()]);
161     }
162     
163     @Override
164     public ClassRef getClassRef(String className) {
165         Class<?> clazz = findClass(TypeDesc.forClass(className));
166         if(clazz == null)
167             return null;
168         return new ClassRef(clazz);
169     }
170
171 }