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

checker.src.org.checkerframework.checker.interning.InterningAnnotatedTypeFactory 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.checker.interning;

import org.checkerframework.checker.interning.qual.Interned;
import org.checkerframework.checker.interning.qual.PolyInterned;
import org.checkerframework.checker.interning.qual.UnknownInterned;
import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.framework.qual.DefaultQualifier;
import org.checkerframework.framework.qual.ImplicitFor;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType;
import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator;
import org.checkerframework.framework.type.treeannotator.TreeAnnotator;
import org.checkerframework.framework.type.typeannotator.ListTypeAnnotator;
import org.checkerframework.framework.type.typeannotator.TypeAnnotator;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.InternalUtils;
import org.checkerframework.javacutil.TreeUtils;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;

import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.CompoundAssignmentTree;
import com.sun.source.tree.Tree;

/**
 * An {@link AnnotatedTypeFactory} that accounts for the properties of the
 * Interned type system. This type factory will add the {@link Interned}
 * annotation to a type if the input:
 *
 * 
    *
  1. is a String literal *
  2. is a class literal *
  3. has an enum type *
  4. has a primitive type *
  5. has the type java.lang.Class *
  6. is a use of a class declared to be @Interned
  7. *
* * This factory extends {@link BaseAnnotatedTypeFactory} and inherits its * functionality, including: flow-sensitive qualifier inference, qualifier * polymorphism (of {@link PolyInterned}), implicit annotations via * {@link ImplicitFor} on {@link Interned} (to handle cases 1, 2, 4), and * user-specified defaults via {@link DefaultQualifier}. * Case 5 is handled by the stub library. */ public class InterningAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { /** The {@link Interned} annotation. */ final AnnotationMirror INTERNED, TOP; /** * Creates a new {@link InterningAnnotatedTypeFactory} that operates on a * particular AST. * * @param checker the checker to use */ public InterningAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker); this.INTERNED = AnnotationUtils.fromClass(elements, Interned.class); this.TOP = AnnotationUtils.fromClass(elements, UnknownInterned.class); // If you update the following, also update ../../../manual/interning-checker.tex . addAliasedAnnotation(com.sun.istack.internal.Interned.class, INTERNED); this.postInit(); } @Override protected TreeAnnotator createTreeAnnotator() { return new ListTreeAnnotator( super.createTreeAnnotator(), new InterningTreeAnnotator(this) ); } @Override protected TypeAnnotator createTypeAnnotator() { return new ListTypeAnnotator( new InterningTypeAnnotator(this), super.createTypeAnnotator() ); } @Override public void addComputedTypeAnnotations(Tree tree, AnnotatedTypeMirror type, boolean useFlow) { Element element = InternalUtils.symbol(tree); if (!type.isAnnotatedInHierarchy(INTERNED) && ElementUtils.isCompileTimeConstant(element)) { type.addAnnotation(INTERNED); } super.addComputedTypeAnnotations(tree, type, useFlow); } @Override public void addComputedTypeAnnotations(Element element, AnnotatedTypeMirror type) { if (!type.isAnnotatedInHierarchy(INTERNED) && ElementUtils.isCompileTimeConstant(element)) { type.addAnnotation(INTERNED); } super.addComputedTypeAnnotations(element, type); } /** * A class for adding annotations based on tree */ private class InterningTreeAnnotator extends TreeAnnotator { InterningTreeAnnotator(InterningAnnotatedTypeFactory atypeFactory) { super(atypeFactory); } @Override public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { if (TreeUtils.isCompileTimeString(node)) { type.replaceAnnotation(INTERNED); } else if (TreeUtils.isStringConcatenation(node)) { type.replaceAnnotation(TOP); } else if ((type.getKind().isPrimitive()) || node.getKind() == Tree.Kind.EQUAL_TO || node.getKind() == Tree.Kind.NOT_EQUAL_TO) { type.replaceAnnotation(INTERNED); } else { type.replaceAnnotation(TOP); } return super.visitBinary(node, type); } /* Compound assignments never result in an interned result. */ @Override public Void visitCompoundAssignment(CompoundAssignmentTree node, AnnotatedTypeMirror type) { type.replaceAnnotation(TOP); return super.visitCompoundAssignment(node, type); } } /** * Adds @Interned to enum types and any use of a class that is declared to be @Interned */ private class InterningTypeAnnotator extends TypeAnnotator { InterningTypeAnnotator(InterningAnnotatedTypeFactory atypeFactory) { super(atypeFactory); } @Override public Void visitDeclared(AnnotatedDeclaredType t, Void p) { // case 3: Enum types, and the Enum class itself, are interned Element elt = t.getUnderlyingType().asElement(); assert elt != null; if (elt.getKind() == ElementKind.ENUM) { t.replaceAnnotation(INTERNED); //TODO: CODE REVIEW: //TODO: I am not sure this makes sense. An element for a declared type doesn't always have //TODO: to be a class declaration. AND I would assume if the class declaration has //TODO: @Interned then the type would already receive an @Interned from the framework without //TODO: this case (I think from InheritFromClass) //TODO: IF this is true, perhaps remove item 6 I added to the class comment } else if (typeFactory.fromElement(elt).hasAnnotation(INTERNED)) { // If the class/interface has an @Interned annotation, use it. t.replaceAnnotation(INTERNED); } return super.visitDeclared(t, p); } } /** * Unbox type and replace any interning type annotatiosn with @Interned since all * all primitives can safely use ==. See case 4 in the class comments. */ @Override public AnnotatedPrimitiveType getUnboxedType(AnnotatedDeclaredType type) { AnnotatedPrimitiveType primitive = super.getUnboxedType(type); primitive.replaceAnnotation(INTERNED); return primitive; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy