| import java.util.HashMap; |
| import java.util.Map; |
| import org.checkerframework.checker.interning.qual.InternMethod; |
| import org.checkerframework.checker.interning.qual.Interned; |
| |
| public @Interned class InternedClass2 { |
| private final int i; |
| // @UnknownInterned is the default annotation on constructor results even for @Interned classes. |
| private InternedClass2(int i) { |
| // Type of "this" inside a constructor of an @Interned class is @UnknownInterned. |
| // :: error: (assignment) |
| @Interned InternedClass2 that = this; |
| this.i = i; |
| } |
| |
| InternedClass2 factory(int i) { |
| // :: error: (interned.object.creation) :: error: (method.invocation) |
| new InternedClass2(i).someMethod(); // error, call to constructor on for @Interned class. |
| (new InternedClass2(i)).intern(); // ok, call to constructor receiver to @InternMethod |
| ((((new InternedClass2(i))))).intern(); // ok, call to constructor receiver to @InternMethod |
| return new InternedClass2(i).intern(); // ok, call to constructor receiver to @InternMethod |
| } |
| |
| void someMethod() { |
| // Type of "this" inside a method (not marked @InternedMethod) is @Interned, |
| // assuming the method is declared in an @Interned class. |
| @Interned InternedClass2 that = this; // ok |
| } |
| |
| private static Map<Integer, InternedClass2> pool = new HashMap<>(); |
| |
| @InternMethod |
| public InternedClass2 intern() { |
| // Type of "this" inside an @InternMethod is @UnknownInterned |
| // :: error: (assignment) |
| @Interned InternedClass2 that = this; |
| if (!pool.containsKey(this.i)) { |
| // The above check proves "this" is interned. |
| @SuppressWarnings("interning:assignment") |
| @Interned InternedClass2 internedThis = this; |
| pool.put(this.i, internedThis); |
| } |
| return pool.get(this.i); |
| } |
| |
| @Override // ok, no override invalid receiver error is issued. |
| public String toString() { |
| @Interned InternedClass2 that = this; // ok |
| return super.toString(); |
| } |
| |
| @Override |
| public boolean equals(Object object) { |
| if (this == object) { |
| return true; |
| } |
| if (object == null || getClass() != object.getClass()) { |
| return false; |
| } |
| |
| InternedClass2 that = (InternedClass2) object; |
| |
| return i == that.i; |
| } |
| |
| @Override |
| public int hashCode() { |
| return i; |
| } |
| |
| public boolean hasNodeOfType(Class<?> type) { |
| if (type == this.getClass()) { |
| return true; |
| } |
| return false; |
| } |
| } |