Search in sources :

Example 1 with Metamodel

use of org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel in project ceylon by eclipse.

the class ClassOrInterfaceImpl method lookupMember.

@SuppressWarnings("unchecked")
private <T extends NestableDeclarationImpl, Container> MemberLookup<T, Container> lookupMember(@Ignore TypeDescriptor $reifiedT, @Ignore TypeDescriptor $reifiedContainer, org.eclipse.ceylon.model.typechecker.model.Type reifiedContainer, T value) {
    ClassOrInterfaceImpl<Container> containerMetamodel;
    org.eclipse.ceylon.model.typechecker.model.Type qualifyingType;
    if ($reifiedContainer == TypeDescriptor.NothingType) {
        // wildcard: everything goes
        qualifyingType = this.producedType.getSupertype((TypeDeclaration) value.declaration.getContainer());
    } else {
        // get the declaration as seen from the container
        Declaration memberInContainer = reifiedContainer.getDeclaration().getMember(value.getName(), null, false);
        // cheaper this way than through reflection type checks
        if ($reifiedT == ValueDeclarationImpl.$TypeDescriptor$) {
            if (memberInContainer instanceof org.eclipse.ceylon.model.typechecker.model.Value == false)
                return null;
        } else if ($reifiedT == FunctionDeclarationImpl.$TypeDescriptor$) {
            if (memberInContainer instanceof org.eclipse.ceylon.model.typechecker.model.Function == false)
                return null;
        } else if ($reifiedT == InterfaceDeclarationImpl.$TypeDescriptor$) {
            if (memberInContainer instanceof org.eclipse.ceylon.model.typechecker.model.Interface == false)
                return null;
        } else if ($reifiedT == ClassDeclarationImpl.$TypeDescriptor$) {
            if (memberInContainer instanceof org.eclipse.ceylon.model.typechecker.model.Class == false)
                return null;
        } else if ($reifiedT == ClassOrInterfaceDeclarationImpl.$TypeDescriptor$) {
            if (memberInContainer instanceof org.eclipse.ceylon.model.typechecker.model.ClassOrInterface == false)
                return null;
        } else {
            throw new AssertionError("Member type not supported: " + $reifiedT);
        }
        // get the right container type
        qualifyingType = reifiedContainer.getSupertype((TypeDeclaration) memberInContainer.getContainer());
    }
    if (qualifyingType == null)
        throw new AssertionError("Could not find qualifying type for reifiedContainer: " + $reifiedContainer);
    // now get the right metamodel for the qualifying type
    containerMetamodel = (ClassOrInterfaceImpl<Container>) Metamodel.getAppliedMetamodel(qualifyingType);
    if (containerMetamodel == null)
        throw new AssertionError("Could not find metamodel for qualifying type: " + qualifyingType);
    // we already have the right member for the wildcard
    if ($reifiedContainer != TypeDescriptor.NothingType) {
        // now get the right member
        value = ((ClassOrInterfaceDeclarationImpl) containerMetamodel.getDeclaration()).findDeclaredDeclaration($reifiedT, value.getName());
    }
    return new MemberLookup<T, Container>($reifiedT, $reifiedContainer, value, qualifyingType, containerMetamodel);
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) AssertionError(ceylon.language.AssertionError) Metamodel(org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel) ClassDeclaration(ceylon.language.meta.declaration.ClassDeclaration) NestableDeclaration(ceylon.language.meta.declaration.NestableDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) InterfaceDeclaration(ceylon.language.meta.declaration.InterfaceDeclaration) ValueDeclaration(ceylon.language.meta.declaration.ValueDeclaration) FunctionDeclaration(ceylon.language.meta.declaration.FunctionDeclaration) ClassOrInterfaceDeclaration(ceylon.language.meta.declaration.ClassOrInterfaceDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Example 2 with Metamodel

use of org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel in project ceylon by eclipse.

the class ClassDeclarationImpl method init.

@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected void init() {
    super.init();
    // anonymous classes don't have parameter lists
    if (!declaration.isAnonymous()) {
        org.eclipse.ceylon.model.typechecker.model.Class classDeclaration = (org.eclipse.ceylon.model.typechecker.model.Class) declaration;
        if (classDeclaration.isAbstraction()) {
            List<Declaration> overloads = classDeclaration.getOverloads();
            if (overloads.size() == 1) {
                classDeclaration = (org.eclipse.ceylon.model.typechecker.model.Class) overloads.get(0);
            }
        // else{
        // throw Metamodel.newModelError("Class has more than one overloaded constructor: "+classDeclaration.getNameAsString());
        // }
        }
        ParameterList parameterList = classDeclaration.getParameterList();
        if (parameterList != null) {
            this.parameters = FunctionalUtil.getParameters(classDeclaration);
        } else {
            this.parameters = null;
        }
    } else {
        this.parameters = null;
    }
    if (((Class) declaration).hasConstructors() || ((Class) declaration).hasEnumerated()) {
        this.constructors = new LinkedList<ceylon.language.meta.declaration.Declaration>();
        for (Declaration d : declaration.getMembers()) {
            if (d instanceof Constructor) {
                this.constructors.add(Metamodel.<ceylon.language.meta.declaration.Declaration>getOrCreateMetamodel(d));
            }
        }
    } else {
        this.constructors = Collections.emptyList();
    }
}
Also used : Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) Class(org.eclipse.ceylon.model.typechecker.model.Class) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) Metamodel(org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel) Class(org.eclipse.ceylon.model.typechecker.model.Class) CallableConstructorDeclaration(ceylon.language.meta.declaration.CallableConstructorDeclaration) FunctionOrValueDeclaration(ceylon.language.meta.declaration.FunctionOrValueDeclaration) ValueDeclaration(ceylon.language.meta.declaration.ValueDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) ConstructorDeclaration(ceylon.language.meta.declaration.ConstructorDeclaration) ValueConstructorDeclaration(ceylon.language.meta.declaration.ValueConstructorDeclaration)

Example 3 with Metamodel

use of org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel in project ceylon by eclipse.

the class ValueConstructorImpl method getJavaMethod.

// /////////////////////////////////////////
/**
 * Gets the getter {@code java.lang.reflect.Method} for the
 * given value constructor.
 */
@Ignore
public static Method getJavaMethod(ValueConstructorDeclarationImpl declaration) {
    org.eclipse.ceylon.model.typechecker.model.Value decl = (org.eclipse.ceylon.model.typechecker.model.Value) declaration.declaration;
    String getterName = "";
    try {
        if (decl instanceof JavaBeanValue) {
            java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
            getterName = ((JavaBeanValue) decl).getGetterName();
            java.lang.Class<?>[] params = NO_PARAMS;
            boolean isJavaArray = MethodHandleUtil.isJavaArray(javaClass);
            if (isJavaArray)
                params = MethodHandleUtil.getJavaArrayGetArrayParameterTypes(javaClass, getterName);
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            Method m = decl.isShared() ? javaClass.getMethod(getterName, params) : javaClass.getDeclaredMethod(getterName, params);
            return m;
        } else if (decl instanceof LazyValue) {
            LazyValue lazyDecl = (LazyValue) decl;
            java.lang.Class<?> javaClass = ((ReflectionClass) lazyDecl.classMirror).klass;
            // FIXME: we should really save the getter name in the LazyDecl
            getterName = NamingBase.getGetterName(lazyDecl);
            // toplevels don't have inheritance
            Method m = javaClass.getDeclaredMethod(getterName);
            return m;
        } else if (ModelUtil.isEnumeratedConstructor(decl)) {
            java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
            Class constructedClass = ModelUtil.getConstructedClass(decl);
            if (constructedClass.isMember()) {
                // the getter for member classes is on the enclosing class.
                javaClass = javaClass.getEnclosingClass();
            } else if (ModelUtil.isLocalNotInitializer(constructedClass))
                // local class has no way to get the value
                return null;
            getterName = NamingBase.getGetterName(decl);
            java.lang.Class<?>[] params = NO_PARAMS;
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            Method m = javaClass.getDeclaredMethod(getterName, params);
            return m;
        } else {
            throw new StorageException("Attribute " + decl.getName() + " is neither captured nor shared so it has no physical storage allocated and cannot be read by the metamodel");
        }
    } catch (NoSuchMethodException | SecurityException e) {
        throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
    }
}
Also used : LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) Method(java.lang.reflect.Method) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Metamodel(org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel) Class(org.eclipse.ceylon.model.typechecker.model.Class) ReflectionClass(org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) StorageException(ceylon.language.meta.model.StorageException) Ignore(org.eclipse.ceylon.compiler.java.metadata.Ignore)

Example 4 with Metamodel

use of org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel in project ceylon by eclipse.

the class ValueImpl method initField.

private void initField(Object instance, Type valueType) {
    org.eclipse.ceylon.model.typechecker.model.Value decl = (org.eclipse.ceylon.model.typechecker.model.Value) declaration.declaration;
    String name = decl.getName();
    if (decl instanceof JavaBeanValue) {
        java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
        if (javaClass == ceylon.language.Object.class || javaClass == ceylon.language.Basic.class || javaClass == ceylon.language.Identifiable.class) {
            if ("string".equals(name) || "hash".equals(name)) {
                // look it up on j.l.Object, getterName should work
                javaClass = java.lang.Object.class;
            } else {
                throw Metamodel.newModelError("Object/Basic/Identifiable member not supported: " + name);
            }
        } else if (javaClass == ceylon.language.Throwable.class) {
            if ("cause".equals(name) || "message".equals(name) || "suppressed".equals(name)) {
                javaClass = instance.getClass();
                isSuppressed = "suppressed".equals(name);
            }
        }
        String getterName = ((JavaBeanValue) decl).getGetterName();
        try {
            Class<?>[] params;
            if (!declaration.getStatic()) {
                params = NO_PARAMS;
            } else {
                int numCapturedTypeParams = ((ClassOrInterface) declaration.declaration.getContainer()).getTypeParameters().size();
                params = new Class[numCapturedTypeParams];
                Arrays.fill(params, TypeDescriptor.class);
            }
            boolean isJavaArray = MethodHandleUtil.isJavaArray(javaClass);
            if (isJavaArray)
                params = MethodHandleUtil.getJavaArrayGetArrayParameterTypes(javaClass, getterName);
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            Method m = decl.isShared() ? javaClass.getMethod(getterName, params) : javaClass.getDeclaredMethod(getterName, params);
            m.setAccessible(true);
            getter = MethodHandles.lookup().unreflect(m);
            java.lang.Class<?> getterType = m.getReturnType();
            getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
            if (instance != null && // XXXArray.getArray is static but requires an instance as first param
            (isJavaArray || !Modifier.isStatic(m.getModifiers()))) {
                getter = getter.bindTo(instance);
            }
            if (declaration.getStatic()) {
                getter = getter.asType(MethodType.methodType(Object.class, params));
                TypeDescriptor[] typeArguments = ((TypeDescriptor.Class) ((ClassOrInterfaceImpl<?>) container).$reifiedType).getTypeArguments();
                getter = getter.asSpreader(TypeDescriptor[].class, typeArguments.length);
                getter = getter.bindTo(typeArguments);
            } else {
                // we need to cast to Object because this is what comes out when calling it in $call
                getter = getter.asType(MethodType.methodType(Object.class));
            }
            initSetter(decl, javaClass, getterType, instance, valueType);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
        }
    } else if (decl instanceof LazyValue) {
        LazyValue lazyDecl = (LazyValue) decl;
        java.lang.Class<?> javaClass = ((ReflectionClass) lazyDecl.classMirror).klass;
        // FIXME: we should really save the getter name in the LazyDecl
        String getterName = NamingBase.getGetterName(lazyDecl);
        try {
            // toplevels don't have inheritance
            Method m = javaClass.getDeclaredMethod(getterName);
            m.setAccessible(true);
            getter = MethodHandles.lookup().unreflect(m);
            java.lang.Class<?> getterType = m.getReturnType();
            getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
            // we need to cast to Object because this is what comes out when calling it in $call
            getter = getter.asType(MethodType.methodType(Object.class));
            initSetter(decl, javaClass, getterType, null, valueType);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
        }
    } else if (decl instanceof FieldValue) {
        FieldValue fieldDecl = (FieldValue) decl;
        java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
        String fieldName = fieldDecl.getRealName();
        if (MethodHandleUtil.isJavaArray(javaClass)) {
            try {
                Method method = Array.class.getDeclaredMethod("getLength", Object.class);
                getter = MethodHandles.lookup().unreflect(method);
                java.lang.Class<?> getterType = method.getReturnType();
                getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
                // this one is static but requires an instance a first param
                if (instance != null)
                    getter = getter.bindTo(instance);
                // we need to cast to Object because this is what comes out when calling it in $call
                getter = getter.asType(MethodType.methodType(Object.class));
            } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
                throw Metamodel.newModelError("Failed to find Array.getLength method for: " + decl, e);
            }
        } else {
            try {
                // fields are not inherited
                Field f = javaClass.getDeclaredField(fieldName);
                f.setAccessible(true);
                getter = MethodHandles.lookup().unreflectGetter(f);
                java.lang.Class<?> getterType = f.getType();
                getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
                if (instance != null && !Modifier.isStatic(f.getModifiers()))
                    getter = getter.bindTo(instance);
                // we need to cast to Object because this is what comes out when calling it in $call
                getter = getter.asType(MethodType.methodType(Object.class));
                initSetter(decl, javaClass, getterType, instance, valueType);
            } catch (NoSuchFieldException | SecurityException | IllegalAccessException e) {
                throw Metamodel.newModelError("Failed to find field " + fieldName + " for: " + decl, e);
            }
        }
    } else if (ModelUtil.isEnumeratedConstructor(decl)) {
        java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
        String getterName = NamingBase.getGetterName(decl);
        try {
            Class<?>[] params = NO_PARAMS;
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            Method m = decl.isShared() ? javaClass.getMethod(getterName, params) : javaClass.getDeclaredMethod(getterName, params);
            m.setAccessible(true);
            getter = MethodHandles.lookup().unreflect(m);
            java.lang.Class<?> getterType = m.getReturnType();
            getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
            if (instance != null && // XXXArray.getArray is static but requires an instance as first param
            (!Modifier.isStatic(m.getModifiers()))) {
                getter = getter.bindTo(instance);
            }
            // we need to cast to Object because this is what comes out when calling it in $call
            getter = getter.asType(MethodType.methodType(Object.class));
            initSetter(decl, javaClass, getterType, instance, valueType);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
        }
    } else
        throw new StorageException("Attribute " + name + " is neither captured nor shared so it has no physical storage allocated and cannot be read by the metamodel");
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) Field(java.lang.reflect.Field) Metamodel(org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) Method(java.lang.reflect.Method) TypeDescriptor(org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) ReflectionClass(org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) StorageException(ceylon.language.meta.model.StorageException)

Example 5 with Metamodel

use of org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel in project ceylon by eclipse.

the class ValueConstructorImpl method initField.

private void initField(Object instance, Type valueType) {
    org.eclipse.ceylon.model.typechecker.model.Value decl = (org.eclipse.ceylon.model.typechecker.model.Value) declaration.declaration;
    Method m = getJavaMethod(declaration);
    // local classes have no getters
    if (m == null)
        return;
    String getterName = m.getName();
    try {
        if (decl instanceof JavaBeanValue) {
            java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
            boolean isJavaArray = MethodHandleUtil.isJavaArray(javaClass);
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            m.setAccessible(true);
            getter = MethodHandles.lookup().unreflect(m);
            java.lang.Class<?> getterType = m.getReturnType();
            getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
            if (instance != null && // XXXArray.getArray is static but requires an instance as first param
            (isJavaArray || !Modifier.isStatic(m.getModifiers()))) {
                getter = getter.bindTo(instance);
            }
            // we need to cast to Object because this is what comes out when calling it in $call
            getter = getter.asType(MethodType.methodType(Object.class));
        } else if (ModelUtil.isEnumeratedConstructor(decl)) {
            java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
            if (ModelUtil.getConstructedClass(decl).isMember()) {
                // the getter for member classes is on the enclosing class.
                javaClass = javaClass.getEnclosingClass();
            }
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            m.setAccessible(true);
            getter = MethodHandles.lookup().unreflect(m);
            java.lang.Class<?> getterType = m.getReturnType();
            getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
            if (instance != null && // XXXArray.getArray is static but requires an instance as first param
            (!Modifier.isStatic(m.getModifiers()))) {
                getter = getter.bindTo(instance);
            }
            // if(!ModelUtil.getConstructedClass(decl).isMember()) {
            // we need to cast to Object because this is what comes out when calling it in $call
            getter = getter.asType(MethodType.methodType(Object.class));
        // }
        } else
            throw new StorageException("Attribute " + decl.getName() + " is neither captured nor shared so it has no physical storage allocated and cannot be read by the metamodel");
    } catch (SecurityException | IllegalAccessException e) {
        throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
    }
}
Also used : Method(java.lang.reflect.Method) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Metamodel(org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel) Class(org.eclipse.ceylon.model.typechecker.model.Class) ReflectionClass(org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) StorageException(ceylon.language.meta.model.StorageException)

Aggregations

Metamodel (org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel)5 StorageException (ceylon.language.meta.model.StorageException)3 Method (java.lang.reflect.Method)3 ReflectionClass (org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass)3 JavaBeanValue (org.eclipse.ceylon.model.loader.model.JavaBeanValue)3 LazyValue (org.eclipse.ceylon.model.loader.model.LazyValue)3 Class (org.eclipse.ceylon.model.typechecker.model.Class)3 ValueDeclaration (ceylon.language.meta.declaration.ValueDeclaration)2 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)2 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)2 AssertionError (ceylon.language.AssertionError)1 CallableConstructorDeclaration (ceylon.language.meta.declaration.CallableConstructorDeclaration)1 ClassDeclaration (ceylon.language.meta.declaration.ClassDeclaration)1 ClassOrInterfaceDeclaration (ceylon.language.meta.declaration.ClassOrInterfaceDeclaration)1 ConstructorDeclaration (ceylon.language.meta.declaration.ConstructorDeclaration)1 FunctionDeclaration (ceylon.language.meta.declaration.FunctionDeclaration)1 FunctionOrValueDeclaration (ceylon.language.meta.declaration.FunctionOrValueDeclaration)1 InterfaceDeclaration (ceylon.language.meta.declaration.InterfaceDeclaration)1 NestableDeclaration (ceylon.language.meta.declaration.NestableDeclaration)1 ValueConstructorDeclaration (ceylon.language.meta.declaration.ValueConstructorDeclaration)1