blob: 9bc2dbac30e8236ab76196ed4d73611e248558b9 [file] [log] [blame]
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.KeyFor;
import org.checkerframework.checker.nullness.qual.KeyForBottom;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.qual.Pure;
import org.checkerframework.framework.qual.Covariant;
import org.checkerframework.framework.qual.DefaultQualifier;
import org.checkerframework.framework.qual.TypeUseLocation;
@DefaultQualifier(value = NonNull.class, locations = TypeUseLocation.IMPLICIT_UPPER_BOUND)
public class KeyForChecked {
interface KFMap<@KeyForBottom K extends @NonNull Object, V extends @NonNull Object> {
@Covariant(0)
public static interface Entry<
@KeyForBottom K1 extends @Nullable Object, V1 extends @Nullable Object> {
K1 getKey();
V1 getValue();
}
@Pure
boolean containsKey(@Nullable Object a1);
@Pure
@Nullable V get(@Nullable Object a1);
@Nullable V put(K a1, V a2);
Set<@KeyFor("this") K> keySet();
Set<KFMap.Entry<@KeyFor("this") K, V>> entrySet();
KFIterator<K> iterator();
}
class KFHashMap<@KeyForBottom K2 extends @NonNull Object, V2 extends @NonNull Object>
implements KFMap<K2, V2> {
@Pure
public boolean containsKey(@Nullable Object a1) {
return false;
}
@Pure
public @Nullable V2 get(@Nullable Object a1) {
return null;
}
public @Nullable V2 put(K2 a1, V2 a2) {
return null;
}
public Set<@KeyFor("this") K2> keySet() {
return new HashSet<@KeyFor("this") K2>();
}
public Set<KFMap.Entry<@KeyFor("this") K2, V2>> entrySet() {
return new HashSet<KFMap.Entry<@KeyFor("this") K2, V2>>();
}
public KFIterator<K2> iterator() {
return new KFIterator<K2>();
}
}
@Covariant(0)
class KFIterator<@KeyForBottom E extends @Nullable Object> {}
void incorrect1(Object map) {
String nonkey = "";
// :: error: (assignment)
@KeyFor("map") String key = nonkey;
}
void correct1(Object map) {
String nonkey = "";
@SuppressWarnings("assignment")
@KeyFor("map") String key = nonkey;
}
void incorrect2() {
KFMap<String, Object> m = new KFHashMap<>();
m.put("a", new Object());
m.put("b", new Object());
m.put("c", new Object());
Collection<@KeyFor("m") String> coll = m.keySet();
@SuppressWarnings("assignment")
@KeyFor("m") String newkey = "new";
coll.add(newkey);
// TODO: at this point, the @KeyFor annotation is violated
m.put("new", new Object());
}
void correct2() {
KFMap<String, Object> m = new KFHashMap<>();
m.put("a", new Object());
m.put("b", new Object());
m.put("c", new Object());
Collection<@KeyFor("m") String> coll = m.keySet();
@SuppressWarnings("assignment")
@KeyFor("m") String newkey = "new";
m.put(newkey, new Object());
coll.add(newkey);
}
void iter() {
KFMap<String, Object> emap = new KFHashMap<>();
Set<@KeyFor("emap") String> s = emap.keySet();
Iterator<@KeyFor("emap") String> it = emap.keySet().iterator();
Iterator<@KeyFor("emap") String> it2 = s.iterator();
Collection<@KeyFor("emap") String> x = Collections.unmodifiableSet(emap.keySet());
for (@KeyFor("emap") String st : s) {}
for (String st : s) {}
Object bubu = new Object();
// :: error: (enhancedfor)
for (@KeyFor("bubu") String st : s) {}
}
<T> void dominators(KFMap<T, List<T>> preds) {
for (T node : preds.keySet()) {}
for (@KeyFor("preds") T node : preds.keySet()) {}
}
void entrySet() {
KFMap<String, Object> emap = new KFHashMap<>();
Set<KFMap.Entry<@KeyFor("emap") String, Object>> es = emap.entrySet();
// KeyFor has to be explicit on the component to Entry sets because
// a) it's not clear which map the Entry set may have come from
// b) and there is no guarantee the map is still accessible
// :: error: (assignment)
Set<KFMap.Entry<String, Object>> es2 = emap.entrySet();
}
public static <K, V> void mapToString(KFMap<K, V> m) {
Set<KFMap.Entry<@KeyFor("m") K, V>> eset = m.entrySet();
for (KFMap.Entry<@KeyFor("m") K, V> entry : m.entrySet()) {}
}
void testWF(KFMap<String, Object> m) {
KFIterator<String> it = m.iterator();
}
}