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

framework.src.org.checkerframework.common.wholeprograminference.AnnotationConverter Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.common.wholeprograminference;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;

import org.checkerframework.framework.util.AnnotationBuilder;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.ErrorReporter;

import annotations.Annotation;
import annotations.el.AnnotationDef;
import annotations.field.AnnotationFieldType;
import annotations.field.ArrayAFT;
import annotations.field.BasicAFT;
import annotations.field.ScalarAFT;

import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Attribute.Array;
import com.sun.tools.javac.code.Type.ArrayType;

/**
 * This class has auxiliary methods that performs conversion between
 * {@link annotations.Annotation} and
 * {@link javax.lang.model.element.AnnotationMirror}.
 * @author pbsf
 */
public class AnnotationConverter {

    /**
     * Converts an {@link javax.lang.model.element.AnnotationMirror}
     * into an {@link annotations.Annotation}.
     */
    protected static Annotation annotationMirrorToAnnotation(AnnotationMirror am) {
        AnnotationDef def = new AnnotationDef(AnnotationUtils.annotationName(am));
        Map fieldTypes = new HashMap<>();
        // Handling cases where there are fields in annotations.
        for (ExecutableElement ee : am.getElementValues().keySet()) {
            AnnotationFieldType aft = getAnnotationFieldType(ee, am.
                    getElementValues().get(ee).getValue());
            if (aft == null) return null;
            // Here we just add the type of the field into fieldTypes.
            fieldTypes.put(ee.getSimpleName().toString(), aft);
        }
        def.setFieldTypes(fieldTypes);

        // Now, we handle the values of those types below
        Map values =
                am.getElementValues();
        Map newValues = new HashMap<>();
        for (ExecutableElement ee : values.keySet()) {
            Object value = values.get(ee).getValue();
            if (value instanceof List) {
                @SuppressWarnings("unchecked")
                List valueList = (List)value;
                List newList = new ArrayList<>();
                // If we have a List here, then it is a List of AnnotatedValue.
                // Converting each AnnotatedValue to its respective Java type:
                for (Object o : valueList) {
                    newList.add(((AnnotationValue)o).getValue());
                }
                value = newList;
            }
            newValues.put(ee.getSimpleName().toString(), value);
        }
        Annotation out = new Annotation(def, newValues);
        return out;
    }

    /**
     * Converts an {@link annotations.Annotation} into an
     * {@link javax.lang.model.element.AnnotationMirror}.
     */
    protected static AnnotationMirror annotationToAnnotationMirror(
            Annotation anno, ProcessingEnvironment processingEnv) {
        final AnnotationBuilder builder = new AnnotationBuilder(processingEnv,
                anno.def().name);
        for (String fieldKey : anno.fieldValues.keySet()) {
            addFieldToAnnotationBuilder(fieldKey,
                    anno.fieldValues.get(fieldKey), builder);
        }
        return builder.build();
    }

    /**
     * Returns an AnnotationFieldType given an ExecutableElement or value.
     */
    protected static AnnotationFieldType getAnnotationFieldType(ExecutableElement ee, Object value) {
        if (value instanceof List) {
            AnnotationValue defaultValue = ee.getDefaultValue();
            if (defaultValue == null || ((ArrayType)((Array)defaultValue).type) == null) {
                List listV = (List)value;
                if (!listV.isEmpty()) {
                    ScalarAFT scalarAFT = (ScalarAFT) getAnnotationFieldType(ee,
                            ((AnnotationValue)listV.get(0)).getValue());
                    if (scalarAFT != null) {
                        return new ArrayAFT(scalarAFT);
                    }
                }
                return null;
            }
            Type elemType = ((ArrayType)((Array)defaultValue).type).elemtype;
            try {
                return new ArrayAFT((ScalarAFT) BasicAFT.
                        forType(Class.forName(elemType.toString())));
            } catch (ClassNotFoundException e) {
                ErrorReporter.errorAbort(e.getMessage());
            }
        } else if (value instanceof Boolean) {
            return BasicAFT.forType(boolean.class);
        } else if (value instanceof Character) {
            return BasicAFT.forType(char.class);
        } else if (value instanceof Double) {
            return BasicAFT.forType(double.class);
        } else if (value instanceof Float) {
            return BasicAFT.forType(float.class);
        } else if (value instanceof Integer) {
            return BasicAFT.forType(int.class);
        } else if (value instanceof Long) {
            return BasicAFT.forType(long.class);
        } else if (value instanceof Short) {
            return BasicAFT.forType(short.class);
        } else if (value instanceof String) {
            return BasicAFT.forType(String.class);
        }
        return null;
    }


    /**
     * Adds a field to an AnnotationBuilder.
     * @param fieldKey is the name of the field
     * @param obj is the value of the field
     * @param builder is the AnnotationBuilder
     */
    @SuppressWarnings("unchecked") // This is actually checked in the first instanceOf call below.
    protected static void addFieldToAnnotationBuilder(String fieldKey, Object obj,
            AnnotationBuilder builder) {
        if (obj instanceof List) {
            builder.setValue(fieldKey, (List) obj);
        } else if (obj instanceof String) {
            builder.setValue(fieldKey, (String)obj);
        } else if (obj instanceof Integer) {
            builder.setValue(fieldKey, (Integer)obj);
        } else if (obj instanceof Float) {
            builder.setValue(fieldKey, (Float)obj);
        } else if (obj instanceof Long) {
            builder.setValue(fieldKey, (Long)obj);
        } else if (obj instanceof Boolean) {
            builder.setValue(fieldKey, (Boolean)obj);
        } else if (obj instanceof Character) {
            builder.setValue(fieldKey, (Character)obj);
        } else if (obj instanceof Class) {
            builder.setValue(fieldKey, (Class)obj);
        } else if (obj instanceof Double) {
            builder.setValue(fieldKey, (Double)obj);
        } else if (obj instanceof Float) {
            builder.setValue(fieldKey, (Float)obj);
        } else if (obj instanceof Enum) {
            builder.setValue(fieldKey, (Enum)obj);
        } else if (obj instanceof Enum[]) {
            builder.setValue(fieldKey, (Enum[])obj);
        } else if (obj instanceof AnnotationMirror) {
            builder.setValue(fieldKey, (AnnotationMirror)obj);
        } else if (obj instanceof Object[]) {
            builder.setValue(fieldKey, (Object[])obj);
        } else if (obj instanceof TypeMirror) {
            builder.setValue(fieldKey, (TypeMirror)obj);
        } else if (obj instanceof Short) {
            builder.setValue(fieldKey, (Short)obj);
        } else if (obj instanceof VariableElement) {
            builder.setValue(fieldKey, (VariableElement)obj);
        } else if (obj instanceof VariableElement[]) {
            builder.setValue(fieldKey, (VariableElement[])obj);
        } else {
            ErrorReporter.errorAbort("Unrecognized type: " + obj.getClass());
        }
    }
}