All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robovm.compiler.Annotations Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 RoboVM AB
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.robovm.compiler;

import static soot.tagkit.AnnotationConstants.*;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import soot.SootClass;
import soot.SootMethod;
import soot.SootResolver;
import soot.tagkit.AnnotationAnnotationElem;
import soot.tagkit.AnnotationArrayElem;
import soot.tagkit.AnnotationElem;
import soot.tagkit.AnnotationIntElem;
import soot.tagkit.AnnotationStringElem;
import soot.tagkit.AnnotationTag;
import soot.tagkit.Host;
import soot.tagkit.Tag;
import soot.tagkit.VisibilityAnnotationTag;
import soot.tagkit.VisibilityParameterAnnotationTag;

/**
 * @author niklas
 *
 */
public class Annotations {
    
    public enum Visibility { RuntimeVisible, RuntimeInvisible, SourceVisible, Any }
    
    public static final String BRIDGE = "Lorg/robovm/rt/bro/annotation/Bridge;";
    public static final String CALLBACK = "Lorg/robovm/rt/bro/annotation/Callback;";
    public static final String STRUCT_MEMBER = "Lorg/robovm/rt/bro/annotation/StructMember;";
    public static final String VECTORISED = "Lorg/robovm/rt/bro/annotation/Vectorised;";
    public static final String STRUCT_PACKED = "Lorg/robovm/rt/bro/annotation/Packed;";
    public static final String GLOBAL_VALUE = "Lorg/robovm/rt/bro/annotation/GlobalValue;";
    public static final String ARRAY = "Lorg/robovm/rt/bro/annotation/Array;";
    public static final String BASE_TYPE = "Lorg/robovm/rt/bro/annotation/BaseType;";
    public static final String STRUCT_RET = "Lorg/robovm/rt/bro/annotation/StructRet;";
    public static final String POINTER = "Lorg/robovm/rt/bro/annotation/Pointer;";
    public static final String MACHINE_SIZED_FLOAT = "Lorg/robovm/rt/bro/annotation/MachineSizedFloat;";
    public static final String MACHINE_SIZED_S_INT = "Lorg/robovm/rt/bro/annotation/MachineSizedSInt;";
    public static final String MACHINE_SIZED_U_INT = "Lorg/robovm/rt/bro/annotation/MachineSizedUInt;";
    public static final String MARSHALER = "Lorg/robovm/rt/bro/annotation/Marshaler;";
    public static final String MARSHALERS = "Lorg/robovm/rt/bro/annotation/Marshalers;";
    public static final String MARSHALS_POINTER = "Lorg/robovm/rt/bro/annotation/MarshalsPointer;";
    public static final String MARSHALS_VALUE = "Lorg/robovm/rt/bro/annotation/MarshalsValue;";
    public static final String MARSHALS_ARRAY = "Lorg/robovm/rt/bro/annotation/MarshalsArray;";
    public static final String AFTER_BRIDGE_CALL = "Lorg/robovm/rt/bro/annotation/AfterBridgeCall;";
    public static final String AFTER_CALLBACK_CALL = "Lorg/robovm/rt/bro/annotation/AfterCallbackCall;";
    public static final String BY_VAL = "Lorg/robovm/rt/bro/annotation/ByVal;";
    public static final String BY_REF = "Lorg/robovm/rt/bro/annotation/ByRef;";
    public static final String VARIADIC = "Lorg/robovm/rt/bro/annotation/Variadic;";
    public static final String WEAKLY_LINKED = "Lorg/robovm/rt/annotation/WeaklyLinked;";
    public static final String STRONGLY_LINKED = "Lorg/robovm/rt/annotation/StronglyLinked;";

    public static boolean hasAnnotation(Host host, String annotationType) {
        return getAnnotation(host, annotationType) != null;
    }
    
    public static boolean hasParameterAnnotation(SootMethod method, int paramIndex, String annotationType) {
        return getParameterAnnotation(method, paramIndex, annotationType) != null;
    }

    public static List getAnnotations(Host host, Visibility visibility) {
        if (host instanceof SootClass) {
            SootResolver.v().bringToHierarchy((SootClass) host);
        }
        List result = new ArrayList<>();
        for (Tag tag : host.getTags()) {
            if (tag instanceof VisibilityAnnotationTag) {
                if (visibility == Visibility.Any
                        || ((VisibilityAnnotationTag) tag).getVisibility() == visibility.ordinal()) {
                    result.addAll(((VisibilityAnnotationTag) tag).getAnnotations());
                }
            }
        }
        return result;
    }
    
    public static AnnotationTag getAnnotation(Host host, String annotationType) {
        for (AnnotationTag tag : getAnnotations(host, Visibility.Any)) {
            if (annotationType.equals(tag.getType())) {
                return tag;
            }                    
        }
        return null;
    }
    
    public static List getParameterAnnotations(SootMethod method, int paramIndex, Visibility visibility) {
        List result = new ArrayList<>();
        for (Tag tag : method.getTags()) {
            if (tag instanceof VisibilityParameterAnnotationTag) { 
                if (visibility == Visibility.Any 
                        || ((VisibilityParameterAnnotationTag) tag).getKind() == visibility.ordinal()) {
                    
                    ArrayList l = 
                            ((VisibilityParameterAnnotationTag) tag).getVisibilityAnnotations();
                    if (l != null && paramIndex < l.size()) {
                        ArrayList annotations = l.get(paramIndex).getAnnotations();
                        if (annotations != null) {
                            result.addAll(annotations);
                        }
                    }
                }
            }
        }
        return result;
    }

    public static List[] getParameterAnnotations(SootMethod method, Visibility visibility) {
        @SuppressWarnings("unchecked")
        ArrayList[] result = new ArrayList[method.getParameterCount()];
        for (int i = 0; i < result.length; i++) {
            result[i] = new ArrayList<>();
        }
        for (Tag tag : method.getTags()) {
            if (tag instanceof VisibilityParameterAnnotationTag) {
                if (visibility == Visibility.Any 
                        || ((VisibilityParameterAnnotationTag) tag).getKind() == visibility.ordinal()) {
                    
                    ArrayList l = 
                            ((VisibilityParameterAnnotationTag) tag).getVisibilityAnnotations();
                    if (l != null) {
                        int i = 0;
                        for (VisibilityAnnotationTag t : l) {
                            ArrayList annotations = t.getAnnotations();
                            if (annotations != null) {
                                result[i].addAll(annotations);
                            }
                            i++;
                        }
                    }
                }
            }
        }
        return result;
    }
    
    public static AnnotationTag getParameterAnnotation(SootMethod method, int paramIndex, String annotationType) {
        for (AnnotationTag tag : getParameterAnnotations(method, paramIndex, Visibility.Any)) {
            if (annotationType.equals(tag.getType())) {
                return tag;
            }                    
        }
        return null;
    }
    
    public static boolean hasBridgeAnnotation(SootMethod method) {
        return hasAnnotation(method, BRIDGE);
    }
    
    public static boolean hasCallbackAnnotation(SootMethod method) {
        return hasAnnotation(method, CALLBACK);
    }
    
    public static boolean hasStructMemberAnnotation(SootMethod method) {
        return hasAnnotation(method, STRUCT_MEMBER);
    }
    
    public static boolean hasGlobalValueAnnotation(SootMethod method) {
        return hasAnnotation(method, GLOBAL_VALUE);
    }
    
    public static boolean hasArrayAnnotation(SootMethod method) {
        return hasAnnotation(method, ARRAY);
    }

    public static boolean hasArrayAnnotation(SootMethod method, int paramIndex) {
        return hasParameterAnnotation(method, paramIndex, ARRAY);
    }
    
    public static boolean hasPointerAnnotation(SootMethod method) {
        return hasAnnotation(method, POINTER);
    }

    public static boolean hasMachineSizedFloatAnnotation(SootMethod method) {
        return hasAnnotation(method, MACHINE_SIZED_FLOAT);
    }

    public static boolean hasMachineSizedSIntAnnotation(SootMethod method) {
        return hasAnnotation(method, MACHINE_SIZED_S_INT);
    }

    public static boolean hasMachineSizedUIntAnnotation(SootMethod method) {
        return hasAnnotation(method, MACHINE_SIZED_U_INT);
    }

    public static boolean hasByValAnnotation(SootMethod method) {
        return hasAnnotation(method, BY_VAL);
    }
    
    public static boolean hasByRefAnnotation(SootMethod method) {
        return hasAnnotation(method, BY_REF);
    }
    
    public static boolean hasStructRetAnnotation(SootMethod method, int paramIndex) {
        return hasParameterAnnotation(method, paramIndex, STRUCT_RET);
    }
    
    public static boolean hasPointerAnnotation(SootMethod method, int paramIndex) {
        return hasParameterAnnotation(method, paramIndex, POINTER);
    }

    public static boolean hasMachineSizedFloatAnnotation(SootMethod method, int paramIndex) {
        return hasParameterAnnotation(method, paramIndex, MACHINE_SIZED_FLOAT);
    }

    public static boolean hasMachineSizedSIntAnnotation(SootMethod method, int paramIndex) {
        return hasParameterAnnotation(method, paramIndex, MACHINE_SIZED_S_INT);
    }

    public static boolean hasMachineSizedUIntAnnotation(SootMethod method, int paramIndex) {
        return hasParameterAnnotation(method, paramIndex, MACHINE_SIZED_U_INT);
    }

    public static boolean hasByValAnnotation(SootMethod method, int paramIndex) {
        return hasParameterAnnotation(method, paramIndex, BY_VAL);
    }
    
    public static boolean hasByRefAnnotation(SootMethod method, int paramIndex) {
        return hasParameterAnnotation(method, paramIndex, BY_REF);
    }
    
    public static boolean hasVariadicAnnotation(SootMethod method) {
        return hasAnnotation(method, VARIADIC);
    }

    public static boolean hasWeaklyLinkedAnnotation(Host host) {
        return hasAnnotation(host, WEAKLY_LINKED);
    }

    public static boolean hasStronglyLinkedAnnotation(Host host) {
        return hasAnnotation(host, STRONGLY_LINKED);
    }

    public static int getVariadicParameterIndex(SootMethod method) {
        AnnotationTag annotation = getAnnotation(method, VARIADIC);
        return readIntElem(annotation, "value", 0);
    }

    public static boolean hasAfterBridgeCallAnnotation(SootMethod method) {
        return hasAnnotation(method, AFTER_BRIDGE_CALL);
    }
    
    public static boolean hasAfterCallbackCallAnnotation(SootMethod method) {
        return hasAnnotation(method, AFTER_CALLBACK_CALL);
    }

    public static AnnotationTag getMarshalerAnnotation(SootMethod method, int paramIndex) {
        return getParameterAnnotation(method, paramIndex, MARSHALER);
    }
    
    public static AnnotationTag getMarshalerAnnotation(SootMethod method) {
        return getAnnotation(method, MARSHALER);
    }
    
    public static List getMarshalerAnnotations(SootClass clazz) {
        List tags = new ArrayList();
        AnnotationTag marshaler = getAnnotation(clazz, MARSHALER);
        if (marshaler != null) {
            tags.add(marshaler);
        } else {
            AnnotationTag marshalers = getAnnotation(clazz, MARSHALERS);
            if (marshalers != null) {
                for (AnnotationElem e : ((AnnotationArrayElem) marshalers.getElemAt(0)).getValues()) {
                    AnnotationAnnotationElem elem = (AnnotationAnnotationElem) e;
                    tags.add(elem.getValue());
                }
            }
        }
        
        return tags;
    }
    
    public static AnnotationTag getMarshalsPointerAnnotation(SootMethod method) {
        return getAnnotation(method, MARSHALS_POINTER);
    }

    public static AnnotationTag getMarshalsValueAnnotation(SootMethod method) {
        return getAnnotation(method, MARSHALS_VALUE);
    }
    
    public static AnnotationTag getMarshalsArrayAnnotation(SootMethod method) {
        return getAnnotation(method, MARSHALS_ARRAY);
    }

    public static AnnotationTag getStructMemberAnnotation(SootMethod method) {
        return getAnnotation(method, STRUCT_MEMBER);
    }

    public static AnnotationTag getStructVectorisedAnnotation(SootClass clazz) {
        return getAnnotation(clazz, VECTORISED);
    }

    public static AnnotationTag getStructPackedAnnotation(SootClass clazz) {
        return getAnnotation(clazz, STRUCT_PACKED);
    }
    
    public static AnnotationTag getArrayAnnotation(SootMethod method) {
        return getAnnotation(method, ARRAY);
    }

    public static AnnotationTag getArrayAnnotation(SootMethod method, int paramIndex) {
        return getParameterAnnotation(method, paramIndex, ARRAY);
    }
    
    public static AnnotationTag getBaseTypeAnnotation(SootMethod method) {
        return getAnnotation(method, BASE_TYPE);
    }

    public static boolean hasByValAnnotation(SootClass clazz) {
        while (!clazz.isPhantom() && clazz.hasSuperclass()) {
            if (hasAnnotation(clazz, BY_VAL)) {
                return true;
            }
            if (hasAnnotation(clazz, BY_REF)) {
                return false;
            }
            clazz = clazz.getSuperclass();
        }
        return false;
    }
    
    public static boolean hasByRefAnnotation(SootClass clazz) {
        while (!clazz.isPhantom() && clazz.hasSuperclass()) {
            if (hasAnnotation(clazz, BY_REF)) {
                return true;
            }
            if (hasAnnotation(clazz, BY_VAL)) {
                return false;
            }
            clazz = clazz.getSuperclass();
        }
        return false;
    }
    
    public static AnnotationElem getElemByName(AnnotationTag annotation, String name) {
        for (int i = 0; i < annotation.getNumElems(); i++) {
            AnnotationElem elem = annotation.getElemAt(i);
            if (name.equals(elem.getName())) {
                return elem;
            }
        }
        return null;
    }
    
    public static String readStringElem(AnnotationTag annotation, String name, String def) {
        AnnotationStringElem elem = (AnnotationStringElem) getElemByName(annotation, name);
        return elem != null ? elem.getValue() : def;
    }

    public static boolean readBooleanElem(AnnotationTag annotation, String name, boolean def) {
        AnnotationIntElem elem = (AnnotationIntElem) getElemByName(annotation, name);
        return elem != null ? elem.getValue() == 1 : def;
    }

    public static int readIntElem(AnnotationTag annotation, String name, int def) {
        AnnotationIntElem elem = (AnnotationIntElem) getElemByName(annotation, name);
        return elem != null ? elem.getValue() : def;
    }

    public static VisibilityAnnotationTag getOrCreateRuntimeVisibilityAnnotationTag(Host host) {
        for (Tag tag : host.getTags()) {
            if (tag instanceof VisibilityAnnotationTag) {
                if (((VisibilityAnnotationTag) tag).getVisibility() == RUNTIME_VISIBLE) {
                    return (VisibilityAnnotationTag) tag;
                }
            }
        }
        VisibilityAnnotationTag tag = new VisibilityAnnotationTag(RUNTIME_VISIBLE);
        host.addTag(tag);
        return tag;
    }
    
    public static void addRuntimeVisibleAnnotation(Host host, String annotationType) {
        if (!hasAnnotation(host, annotationType)) {
            VisibilityAnnotationTag tag = getOrCreateRuntimeVisibilityAnnotationTag(host);
            tag.addAnnotation(new AnnotationTag(annotationType, 0));
        }
    }

    public static void addRuntimeVisibleAnnotation(Host host, AnnotationTag annoTag) {
        removeAnnotation(host, annoTag.getType());
        VisibilityAnnotationTag tag = getOrCreateRuntimeVisibilityAnnotationTag(host);
        tag.addAnnotation(annoTag);
    }

    public static void removeAnnotation(Host host, String annotationType) {
        for (Tag tag : host.getTags()) {
            if (tag instanceof VisibilityAnnotationTag) {
                ArrayList l = ((VisibilityAnnotationTag) tag).getAnnotations();
                for (Iterator it = l.iterator(); it.hasNext();) {
                    AnnotationTag annoTag = it.next();
                    if (annoTag.getType().equals(annotationType)) {
                        it.remove();
                    }
                }
            }
        }
    }

    public static void removeParameterAnnotation(SootMethod method, int paramIndex, String annotationType) {
        for (Tag tag : method.getTags()) {
            if (tag instanceof VisibilityParameterAnnotationTag) {
                ArrayList l = 
                        ((VisibilityParameterAnnotationTag) tag).getVisibilityAnnotations();
                if (l != null && paramIndex < l.size()) {
                    ArrayList annotations = l.get(paramIndex).getAnnotations();
                    if (annotations != null) {
                        for (Iterator it = annotations.iterator(); it.hasNext();) {
                            AnnotationTag annoTag = it.next();
                            if (annoTag.getType().equals(annotationType)) {
                                it.remove();
                            }
                        }
                    }
                }
            }
        }
    }

    private static void copyAnnotations(SootMethod fromMethod, SootMethod toMethod, int visibility) {
        for (Tag tag : fromMethod.getTags()) {
            if (tag instanceof VisibilityAnnotationTag) {
                if (((VisibilityAnnotationTag) tag).getVisibility() == visibility) {
                    VisibilityAnnotationTag copy = new VisibilityAnnotationTag(visibility);
                    for (AnnotationTag annoTag : ((VisibilityAnnotationTag) tag).getAnnotations()) {
                        copy.addAnnotation(annoTag);
                    }
                    toMethod.addTag(copy);
                }
            }
        }
    }
    
    public static void copyAnnotations(SootMethod fromMethod, SootMethod toMethod, Visibility visibility) {
        if (visibility == Visibility.Any) {
            copyAnnotations(fromMethod, toMethod, RUNTIME_VISIBLE);
            copyAnnotations(fromMethod, toMethod, RUNTIME_INVISIBLE);
            copyAnnotations(fromMethod, toMethod, SOURCE_VISIBLE);
        } else {
            copyAnnotations(fromMethod, toMethod, visibility.ordinal());
        }
    }
    
    private static void copyParameterAnnotations(SootMethod fromMethod, SootMethod toMethod, int start, int end, int shift, int visibility) {
        List[] fromAnnos = getParameterAnnotations(fromMethod, Visibility.values()[visibility]);
        List[] toAnnos = getParameterAnnotations(toMethod, Visibility.values()[visibility]);

        for (int i = start; i < end; i++) {
            toAnnos[i + shift].addAll(fromAnnos[i]);
        }
        
        for (Iterator it = toMethod.getTags().iterator(); it.hasNext();) {
            Tag tag = it.next();
            if (tag instanceof VisibilityParameterAnnotationTag) {
                if (((VisibilityParameterAnnotationTag) tag).getKind() == visibility) {
                    it.remove();
                }
            }
        }
        
        VisibilityParameterAnnotationTag vpaTag = new VisibilityParameterAnnotationTag(toAnnos.length, visibility);
        for (List annos : toAnnos) {
            VisibilityAnnotationTag vaTag = new VisibilityAnnotationTag(visibility);
            for (AnnotationTag anno : annos) {
                vaTag.addAnnotation(anno);
            }
            vpaTag.addVisibilityAnnotation(vaTag);
        }
        toMethod.addTag(vpaTag);
    }
    
    public static void copyParameterAnnotations(SootMethod fromMethod, SootMethod toMethod, int start, int end, int shift, Visibility visibility) {
        if (visibility == Visibility.Any) {
            copyParameterAnnotations(fromMethod, toMethod, start, end, shift, RUNTIME_VISIBLE);
            copyParameterAnnotations(fromMethod, toMethod, start, end, shift, RUNTIME_INVISIBLE);
            copyParameterAnnotations(fromMethod, toMethod, start, end, shift, SOURCE_VISIBLE);
        } else {
            copyParameterAnnotations(fromMethod, toMethod, start, end, shift, visibility.ordinal());
        }
    }
    
    public static VisibilityAnnotationTag getOrCreateRuntimeVisibilityAnnotationTag(SootMethod method, int paramIndex) {
        for (Tag tag : method.getTags()) {
            if (tag instanceof VisibilityParameterAnnotationTag) {
                ArrayList l = 
                        ((VisibilityParameterAnnotationTag) tag).getVisibilityAnnotations();
                if (l != null && paramIndex < l.size()) {
                    if ((l.get(paramIndex)).getVisibility() == RUNTIME_VISIBLE) {
                        return l.get(paramIndex);
                    }
                }
            }
        }
        VisibilityParameterAnnotationTag ptag = 
                new VisibilityParameterAnnotationTag(method.getParameterCount(), RUNTIME_VISIBLE);
        for (int i = 0; i < method.getParameterCount(); i++) {
            ptag.addVisibilityAnnotation(new VisibilityAnnotationTag(RUNTIME_VISIBLE));

        }
        method.addTag(ptag);
        return ptag.getVisibilityAnnotations().get(paramIndex);
    }
    
    public static void addRuntimeVisibleParameterAnnotation(SootMethod method, int paramIndex, String annotationType) {
        if (!hasParameterAnnotation(method, paramIndex, annotationType)) {
            VisibilityAnnotationTag tag = getOrCreateRuntimeVisibilityAnnotationTag(method, paramIndex);
            tag.addAnnotation(new AnnotationTag(annotationType, 0));
        }
    }

    public static void addRuntimeVisibleParameterAnnotation(SootMethod method, int paramIndex, AnnotationTag annoTag) {
        removeParameterAnnotation(method, paramIndex, annoTag.getType());
        VisibilityAnnotationTag tag = getOrCreateRuntimeVisibilityAnnotationTag(method, paramIndex);
        tag.addAnnotation(annoTag);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy