package examples.javari; import checkers.javari.quals.*; import java.awt.Point; class JavariExample { Point a = new Point(0, 1); @ReadOnly Point b = new Point(2, 3), c = new Point(4, 5); int i = 0; JavariCell mc = new JavariCell(); @ReadOnly JavariCell roc = new JavariCell(); String mString; @ReadOnly String roString; public String isMutable() { return "isMutable"; } @ReadOnly public String isReadOnly() { return "isReadOnly"; } @PolyRead public String isPolyRead(String doesntMatter, @PolyRead JavariCell matters) { matters.cell = null; // cannot modify PolyRead argument return "isPolyRead"; } public void canDo() { i = b.x; c = b; b = a; b = (/*@ReadOnly*/ Point) a; a = (Point) b; // should emit a warning here a.x = 0; i = a.x; a.x = b.y; // can assign inherited readonly PRIMITIVE field to mutable mc.cell = mc; roc = roc.cell; roc = null; roString = isPolyRead(mString, roc); // polyread resolved as readonly mString = isPolyRead(mString, mc); // polyread resolved as mutable; mc.mutateInternal("foo"); mString = isMutable(); roString = isReadOnly(); roString = isMutable(); mString = mc.isMutable(); // method with mutable receiver w/ mutable reference mString = mc.isThisMutable(); // method with thismutable receiver w/ mutable reference mString = roc.isMutable(); // method with mutable receiver w/ readonly reference roString = mc.isMutable(); roString = mc.isThisMutable(); roString = mc.isReadOnly(); roString = roc.isMutable(); roString = roc.isThisMutable(); roString = roc.isReadOnly(); } public void cannotDo() { @ReadOnly int j = 0; // primitive cannot be annotated as readonly a = b; // cannot assign readonly to mutable b.y = i; // readonly field behave as final b.y = 3; // readonly field behave as final b.x = a.y; // readonly field behave as final roc.cell = mc; // readonly field behave as final roc.mutateInternal("foo"); // readonly instance is readonly mc.cell = roc; // cannot assign readonly to mutable mc.cell = roc.cell; // cannot assign inherited readonly non-primitive field to mutable mString = isReadOnly(); // cannot put readonly return in mutable variable mString = roc.isReadOnly(); // method with readonly receiver w/ readonly reference mString = roc.isThisMutable(); // method with thismutable receiver w/ readonly reference mString = mc.isReadOnly(); // method with readonly receiver w/ mutable reference mString = isPolyRead(mString, roc); // polyread resolved as readonly } class JavariCell { JavariCell cell; String s; @ReadOnly String isReadOnly() { return "isReadOnly"; } String isThisMutable() { return "isThisMutable"; } @Mutable String isMutable() { return "isMutable"; } String argumentReadOnly(@ReadOnly String s) { s = s + " "; // can reassign? yes, because it is not final return s; // ... but cannot return readonly as mutable. } void argumentReadOnly(@ReadOnly JavariCell c){ c.cell = this; // readonly parameter is readonly cell = c; // cannot pass readonly reference to mutable } // this is ok void mutateInternal(String other) /*@Mutable*/ { s = other; this.s = other; } // this is not ok void illegalMutateInternal(String other) /*@ReadOnly*/ { s = other; // method with readonly receiver, cannot do this this.s = other; // method with readonly readonly, cannot do this either } @ReadOnly int readonlyIntReturnType() { // illegal return type return 0; } } public class illegalExtensions extends JavariExample { @ReadOnly public String isMutable() { // cannot override return "isNotReally"; } } }