| import java.util.HashMap; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.Vector; |
| import org.checkerframework.checker.interning.qual.InternMethod; |
| import org.checkerframework.checker.interning.qual.Interned; |
| import org.checkerframework.checker.interning.qual.UnknownInterned; |
| |
| // The @Interned annotation indicates that much like an enum, all variables |
| // declared of this type are interned (except the constructor return value). |
| public @Interned class InternedClass { |
| |
| int value; |
| |
| InternedClass factory(int i) { |
| return new InternedClass(i).intern(); |
| } |
| |
| // Private constructor |
| private InternedClass(int i) { |
| value = i; |
| // "this" in the constructor is not interned. |
| // :: error: (assignment) |
| @Interned InternedClass that = this; |
| } |
| |
| // Overriding method |
| @org.checkerframework.dataflow.qual.Pure |
| public String toString() { |
| @Interned InternedClass c = this; |
| return Integer.valueOf(value).toString(); |
| } |
| |
| // Factory method |
| private InternedClass(InternedClass ic) { |
| value = ic.value; |
| } |
| |
| // Equals method (used only by interning; clients should use ==) |
| @org.checkerframework.dataflow.qual.Pure |
| public boolean equals(Object other) { |
| if (!(other instanceof InternedClass)) { |
| return false; |
| } |
| return value == ((InternedClass) other).value; |
| } |
| |
| // Interning method |
| @SuppressWarnings("annotations.on.use") |
| private static Map<@UnknownInterned InternedClass, @Interned InternedClass> pool = |
| new HashMap<>(); |
| |
| @InternMethod |
| public @Interned InternedClass intern() { |
| if (!pool.containsKey(this)) { |
| pool.put(this, (@Interned InternedClass) this); |
| } |
| return pool.get(this); |
| } |
| |
| public void myMethod(InternedClass ic, InternedClass[] ica) { |
| boolean b1 = (this == ic); // valid |
| boolean b2 = (this == returnInternedObject()); // valid |
| boolean b3 = (this == ica[0]); // valid |
| InternedClass ic2 = returnArray()[0]; // valid |
| // :: error: (interned.object.creation) |
| ica[0] = new InternedClass(22); |
| InternedClass[] arr1 = returnArray(); // valid |
| InternedClass[] arr2 = new InternedClass[22]; // valid |
| InternedClass[] arr3 = new InternedClass[] {}; // valid |
| |
| Map<InternedClass, Integer> map = new LinkedHashMap<>(); |
| for (Map.Entry<InternedClass, Integer> e : map.entrySet()) { |
| InternedClass ic3 = e.getKey(); // valid |
| } |
| } |
| |
| public InternedClass returnInternedObject() { |
| return this; |
| } |
| |
| public InternedClass[] returnArray() { |
| return new InternedClass[] {}; |
| } |
| |
| public void internedVarargs(String name, InternedClass... args) { |
| InternedClass arg = args[0]; // valid |
| } |
| |
| public void internedVarargs2(String name, @Interned String... args) { |
| @Interned String arg = args[0]; // valid |
| } |
| |
| public static InternedClass[] arrayclone_simple(InternedClass[] a_old) { |
| int len = a_old.length; |
| InternedClass[] a_new = new InternedClass[len]; |
| for (int i = 0; i < len; i++) { |
| // :: error: (interned.object.creation) |
| a_new[i] = new InternedClass(a_old[i]); |
| } |
| return a_new; |
| } |
| |
| public @Interned class Subclass extends InternedClass { |
| // Private constructor |
| private Subclass(int i) { |
| super(i); |
| } |
| } |
| |
| public static void castFromInternedClass(InternedClass ic) { |
| Subclass s = (Subclass) ic; |
| } |
| |
| public static void castToInternedClass(Object o) { |
| InternedClass ic = (InternedClass) o; |
| } |
| |
| // Default implementation |
| @org.checkerframework.dataflow.qual.Pure |
| public InternedClass clone() throws CloneNotSupportedException { |
| return (InternedClass) super.clone(); |
| } |
| |
| // java.lang.Class should be considered interned |
| public static void classTest() { |
| Integer i = 5; |
| assert i.getClass() == Integer.class; |
| } |
| |
| // java.lang.Class is interned |
| public static void arrayOfClass() throws Exception { |
| Class<?> c = String.class; |
| Class[] parameterTypes = new Class[1]; |
| parameterTypes[0] = String.class; |
| java.lang.reflect.Constructor<?> ctor = c.getConstructor(parameterTypes); |
| } |
| |
| Class[] getSuperClasses(Class<?> c) { |
| Vector<Class<?>> v = new Vector<>(); |
| while (true) { |
| // :: warning: (unnecessary.equals) |
| if (c.getSuperclass().equals((new Object()).getClass())) { |
| break; |
| } |
| c = c.getSuperclass(); |
| v.addElement(c); |
| } |
| return (Class[]) v.toArray(new Class[0]); |
| } |
| |
| void testCast(Object o) { |
| Object i = (InternedClass) o; |
| if (i == this) {} |
| } |
| } |