Skip to content

Commit 33dfd50

Browse files
committed
Starting move PICO to EISOP
1 parent 3081b3a commit 33dfd50

27 files changed

Lines changed: 3065 additions & 0 deletions
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import org.checkerframework.checker.initialization.qual.HoldsForDefaultValue;
4+
5+
import java.lang.annotation.Documented;
6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
10+
11+
/**
12+
* This annotation is used to exclude the field from the abstract state and means the field can be
13+
* reassigned after initialization. It should only annotate on field, not class or method.
14+
*/
15+
@Documented
16+
@Retention(RetentionPolicy.RUNTIME)
17+
@Target({ElementType.FIELD})
18+
@HoldsForDefaultValue
19+
public @interface Assignable {}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import org.checkerframework.framework.qual.DefaultFor;
4+
import org.checkerframework.framework.qual.SubtypeOf;
5+
import org.checkerframework.framework.qual.TargetLocations;
6+
import org.checkerframework.framework.qual.TypeKind;
7+
import org.checkerframework.framework.qual.TypeUseLocation;
8+
9+
import java.lang.annotation.Documented;
10+
import java.lang.annotation.ElementType;
11+
import java.lang.annotation.Retention;
12+
import java.lang.annotation.RetentionPolicy;
13+
import java.lang.annotation.Target;
14+
15+
/**
16+
* {@code @Bottom} can only be annotated before a type parameter (For example, {@code class
17+
* C<@Bottom T extends MutableBox>{}}). This means {@code @Bottom} is the lower bound for this type
18+
* parameter.
19+
*
20+
* <p>User can explicitly write {@code @Bottom} but it's not necessary because it's automatically
21+
* inferred, and we have -AwarnRedundantAnnotations flag to warn about redundant annotations.
22+
*/
23+
@SubtypeOf({Mutable.class, Immutable.class, ReceiverDependentMutable.class, Lost.class})
24+
@DefaultFor(typeKinds = {TypeKind.NULL})
25+
@Documented
26+
@Retention(RetentionPolicy.RUNTIME)
27+
@Target({ElementType.TYPE_PARAMETER})
28+
@TargetLocations({TypeUseLocation.LOWER_BOUND})
29+
public @interface Bottom {}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import org.checkerframework.checker.initialization.qual.HoldsForDefaultValue;
4+
import org.checkerframework.framework.qual.DefaultFor;
5+
import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
6+
import org.checkerframework.framework.qual.LiteralKind;
7+
import org.checkerframework.framework.qual.QualifierForLiterals;
8+
import org.checkerframework.framework.qual.SubtypeOf;
9+
import org.checkerframework.framework.qual.TypeKind;
10+
import org.checkerframework.framework.qual.TypeUseLocation;
11+
import org.checkerframework.framework.qual.UpperBoundFor;
12+
13+
import java.lang.annotation.Documented;
14+
import java.lang.annotation.ElementType;
15+
import java.lang.annotation.Retention;
16+
import java.lang.annotation.RetentionPolicy;
17+
import java.lang.annotation.Target;
18+
import java.math.BigDecimal;
19+
import java.math.BigInteger;
20+
21+
/**
22+
* {@code @Immutable} is a type qualifier that indicates that the fields of annotated reference
23+
* cannot be mutated.
24+
*
25+
* <p>For usage in PICO, there are three ways to use this annotation: Object creation: the object
26+
* created will always be immutable; Annotation on a reference: the object that reference points to
27+
* is immutable; Annotation on a class: all instances of that class are immutable.
28+
*/
29+
@SubtypeOf({Readonly.class})
30+
@Documented
31+
@DefaultQualifierInHierarchy
32+
@Retention(RetentionPolicy.RUNTIME)
33+
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
34+
@DefaultFor(
35+
value = {TypeUseLocation.EXCEPTION_PARAMETER},
36+
types = {
37+
Enum.class,
38+
String.class,
39+
Double.class,
40+
Boolean.class,
41+
Byte.class,
42+
Character.class,
43+
Float.class,
44+
Integer.class,
45+
Long.class,
46+
Short.class,
47+
Number.class,
48+
BigDecimal.class,
49+
BigInteger.class
50+
},
51+
typeKinds = {
52+
TypeKind.INT,
53+
TypeKind.BYTE,
54+
TypeKind.SHORT,
55+
TypeKind.BOOLEAN,
56+
TypeKind.LONG,
57+
TypeKind.CHAR,
58+
TypeKind.FLOAT,
59+
TypeKind.DOUBLE
60+
})
61+
@QualifierForLiterals({LiteralKind.PRIMITIVE, LiteralKind.STRING})
62+
@UpperBoundFor(
63+
typeKinds = {
64+
TypeKind.INT, TypeKind.BYTE, TypeKind.SHORT, TypeKind.BOOLEAN,
65+
TypeKind.LONG, TypeKind.CHAR, TypeKind.FLOAT, TypeKind.DOUBLE
66+
},
67+
types = {
68+
Enum.class,
69+
String.class,
70+
Double.class,
71+
Boolean.class,
72+
Byte.class,
73+
Character.class,
74+
Float.class,
75+
Integer.class,
76+
Long.class,
77+
Short.class,
78+
Number.class,
79+
BigDecimal.class,
80+
BigInteger.class
81+
})
82+
@HoldsForDefaultValue
83+
public @interface Immutable {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import org.checkerframework.framework.qual.SubtypeOf;
4+
5+
import java.lang.annotation.*;
6+
7+
/** Lost means the mutability type of this reference is unknown. This is a subtype of Readonly. */
8+
@SubtypeOf({Readonly.class})
9+
@Documented
10+
@Retention(RetentionPolicy.RUNTIME)
11+
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
12+
public @interface Lost {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import org.checkerframework.checker.initialization.qual.HoldsForDefaultValue;
4+
import org.checkerframework.framework.qual.SubtypeOf;
5+
6+
import java.lang.annotation.Documented;
7+
import java.lang.annotation.ElementType;
8+
import java.lang.annotation.Retention;
9+
import java.lang.annotation.RetentionPolicy;
10+
import java.lang.annotation.Target;
11+
12+
/**
13+
* {@code @Mutable} is a type qualifier that indicates that the fields of annotated reference can be
14+
* mutated through this reference. This is default behavior for all references in Java.
15+
*
16+
* <p>For usage in PICO, there are three ways to use this annotation: Object creation: the object
17+
* created will always be mutable; Annotation on a reference: the object that reference points to is
18+
* mutable; Annotation on a class: all instances of that class are mutable.
19+
*/
20+
@SubtypeOf({Readonly.class})
21+
@Documented
22+
@Retention(RetentionPolicy.RUNTIME)
23+
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
24+
// @DefaultFor({ TypeUseLocation.EXCEPTION_PARAMETER })
25+
@HoldsForDefaultValue
26+
public @interface Mutable {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
9+
@Documented
10+
@Retention(RetentionPolicy.RUNTIME)
11+
@Target({ElementType.METHOD})
12+
public @interface ObjectIdentityMethod {}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import org.checkerframework.framework.qual.PolymorphicQualifier;
4+
import org.checkerframework.framework.qual.TargetLocations;
5+
import org.checkerframework.framework.qual.TypeUseLocation;
6+
7+
import java.lang.annotation.Documented;
8+
import java.lang.annotation.ElementType;
9+
import java.lang.annotation.Retention;
10+
import java.lang.annotation.RetentionPolicy;
11+
import java.lang.annotation.Target;
12+
13+
/**
14+
* The polymorphic qualifier {@code @PolyMutable} indicates that the mutability type of this
15+
* reference can be substituted to {@code @Mutable} or {@code @Immutable} or {@code @RDM}. This is a
16+
* polymorphic qualifier that can be used in the type hierarchy.
17+
*
18+
* <p>{@code @PolyMutable} applies to method parameters, method return type and receiver.
19+
*/
20+
@Documented
21+
@Retention(RetentionPolicy.RUNTIME)
22+
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
23+
@PolymorphicQualifier(Readonly.class)
24+
@TargetLocations({
25+
TypeUseLocation.PARAMETER,
26+
TypeUseLocation.RECEIVER,
27+
TypeUseLocation.RETURN,
28+
TypeUseLocation.LOCAL_VARIABLE
29+
})
30+
public @interface PolyMutable {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import org.checkerframework.framework.qual.DefaultFor;
4+
import org.checkerframework.framework.qual.SubtypeOf;
5+
import org.checkerframework.framework.qual.TypeUseLocation;
6+
7+
import java.lang.annotation.Documented;
8+
import java.lang.annotation.ElementType;
9+
import java.lang.annotation.Retention;
10+
import java.lang.annotation.RetentionPolicy;
11+
import java.lang.annotation.Target;
12+
13+
/**
14+
* The top qualifier in the mutability type hierarchy that indicates that the fields of annotated
15+
* reference cannot be mutated through this reference but can be mutated through other Aliasing.
16+
* This is the default qualifier for local variables and subject to flow-sensitive type refinement.
17+
*/
18+
@SubtypeOf({})
19+
@Documented
20+
@Retention(RetentionPolicy.RUNTIME)
21+
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
22+
@DefaultFor({TypeUseLocation.LOCAL_VARIABLE, TypeUseLocation.IMPLICIT_UPPER_BOUND})
23+
public @interface Readonly {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.checkerframework.checker.pico.qual;
2+
3+
import org.checkerframework.checker.initialization.qual.HoldsForDefaultValue;
4+
import org.checkerframework.framework.qual.SubtypeOf;
5+
6+
import java.lang.annotation.Documented;
7+
import java.lang.annotation.ElementType;
8+
import java.lang.annotation.Retention;
9+
import java.lang.annotation.RetentionPolicy;
10+
import java.lang.annotation.Target;
11+
12+
/**
13+
* {@code @ReceiverDependentMutable} is a type qualifier that indicates that mutability type depends
14+
* on the receiver type.
15+
*
16+
* <p>For usage in PICO, there are three ways to use this annotation: Object creation: the object
17+
* created depends on the lhs type; Annotation on a reference: the object that reference depends on
18+
* the receiver type; Annotation on a class: the instances can be mutable or immutable.
19+
*/
20+
@SubtypeOf(Readonly.class)
21+
@Documented
22+
@Retention(RetentionPolicy.RUNTIME)
23+
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
24+
// @DefaultFor({ TypeUseLocation.FIELD })
25+
@HoldsForDefaultValue
26+
public @interface ReceiverDependentMutable {}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package org.checkerframework.checker.pico;
2+
3+
import static org.checkerframework.checker.pico.PICOAnnotationMirrorHolder.MUTABLE;
4+
import static org.checkerframework.checker.pico.PICOAnnotationMirrorHolder.READONLY;
5+
6+
import com.sun.source.tree.IdentifierTree;
7+
import com.sun.source.tree.MemberSelectTree;
8+
import com.sun.source.tree.MethodInvocationTree;
9+
import com.sun.source.tree.Tree;
10+
import com.sun.source.util.TreePath;
11+
import com.sun.source.util.TreePathScanner;
12+
13+
import org.checkerframework.common.basetype.BaseTypeChecker;
14+
import org.checkerframework.framework.util.AnnotatedTypes;
15+
import org.checkerframework.javacutil.ElementUtils;
16+
import org.checkerframework.javacutil.TreeUtils;
17+
18+
import javax.lang.model.element.Element;
19+
import javax.lang.model.element.ElementKind;
20+
import javax.lang.model.element.ExecutableElement;
21+
22+
public class ObjectIdentityMethodEnforcer extends TreePathScanner<Void, Void> {
23+
24+
private PICONoInitAnnotatedTypeFactory typeFactory;
25+
private BaseTypeChecker checker;
26+
27+
private ObjectIdentityMethodEnforcer(
28+
PICONoInitAnnotatedTypeFactory typeFactory, BaseTypeChecker checker) {
29+
this.typeFactory = typeFactory;
30+
this.checker = checker;
31+
}
32+
33+
// Main entry
34+
public static void check(
35+
TreePath statement,
36+
PICONoInitAnnotatedTypeFactory typeFactory,
37+
BaseTypeChecker checker) {
38+
if (statement == null) return;
39+
ObjectIdentityMethodEnforcer asfchecker =
40+
new ObjectIdentityMethodEnforcer(typeFactory, checker);
41+
asfchecker.scan(statement, null);
42+
}
43+
44+
@Override
45+
public Void visitMethodInvocation(MethodInvocationTree node, Void aVoid) {
46+
Element elt = TreeUtils.elementFromUse(node);
47+
checkMethod(node, elt);
48+
return super.visitMethodInvocation(node, aVoid);
49+
}
50+
51+
private void checkMethod(MethodInvocationTree node, Element elt) {
52+
assert elt instanceof ExecutableElement;
53+
if (ElementUtils.isStatic(elt)) {
54+
return; // Doesn't check static method invocation because it doesn't access instance
55+
// field
56+
}
57+
if (!PICOTypeUtil.isObjectIdentityMethod((ExecutableElement) elt, typeFactory)) {
58+
// Report warning since invoked method is not only dependent on abstract state fields,
59+
// but we
60+
// don't know whether this method invocation's result flows into the hashcode or not.
61+
checker.reportWarning(node, "object.identity.method.invocation.invalid", elt);
62+
}
63+
}
64+
65+
@Override
66+
public Void visitIdentifier(IdentifierTree node, Void aVoid) {
67+
Element elt = TreeUtils.elementFromUse(node);
68+
checkField(node, elt);
69+
return super.visitIdentifier(node, aVoid);
70+
}
71+
72+
@Override
73+
public Void visitMemberSelect(MemberSelectTree node, Void aVoid) {
74+
Element elt = TreeUtils.elementFromUse(node);
75+
checkField(node, elt);
76+
return super.visitMemberSelect(node, aVoid);
77+
}
78+
79+
private void checkField(Tree node, Element elt) {
80+
if (elt == null) return;
81+
if (elt.getSimpleName().contentEquals("this")
82+
|| elt.getSimpleName().contentEquals("super")) {
83+
return;
84+
}
85+
if (elt.getKind() == ElementKind.FIELD) {
86+
if (ElementUtils.isStatic(elt)) {
87+
checker.reportWarning(node, "object.identity.static.field.access.forbidden", elt);
88+
} else {
89+
if (!isInAbstractState(elt, typeFactory)) {
90+
// Report warning since accessed field is not within abstract state
91+
checker.reportWarning(node, "object.identity.field.access.invalid", elt);
92+
}
93+
}
94+
}
95+
}
96+
97+
// Deeply test if a field is in abstract state or not. For composite types: array component,
98+
// type arguments, upper bound of type parameter uses are also checked.
99+
private boolean isInAbstractState(Element elt, PICONoInitAnnotatedTypeFactory typeFactory) {
100+
boolean in = true;
101+
if (PICOTypeUtil.isAssignableField(elt, typeFactory)) {
102+
in = false;
103+
} else if (AnnotatedTypes.containsModifier(typeFactory.getAnnotatedType(elt), MUTABLE)) {
104+
in = false;
105+
} else if (AnnotatedTypes.containsModifier(typeFactory.getAnnotatedType(elt), READONLY)) {
106+
in = false;
107+
}
108+
return in;
109+
}
110+
}

0 commit comments

Comments
 (0)