blob: c0761ec98131fccbe6b906d522a4f20d8f836e1b [file] [log] [blame]
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.*;
public class KeyFors {
public void withoutKeyFor() {
Map<String, String> map = new HashMap<>();
String key = "key";
// :: error: (assignment)
@NonNull String value = map.get(key);
}
public void withKeyFor() {
Map<String, String> map = new HashMap<>();
@SuppressWarnings("assignment")
@KeyFor("map") String key = "key";
@NonNull String value = map.get(key);
}
public void withCollection() {
Map<String, String> map = new HashMap<>();
List<@KeyFor("map") String> keys = new ArrayList<>();
@KeyFor("map") String key = keys.get(0);
@NonNull String value = map.get(key);
value = map.get(keys.get(0));
}
public void withIndirectReference() {
class Container {
Map<String, String> map = new HashMap<>();
}
Container container = new Container();
@SuppressWarnings("assignment")
@KeyFor("container.map") String key = "m";
@NonNull String value = container.map.get(key);
}
/** Returns a sorted version of m.keySet(). */
public static <K extends Comparable<? super K>, V> Collection<@KeyFor("#1") K> sortedKeySet(
Map<K, V> m) {
throw new RuntimeException();
}
static HashMap<Integer, Object> call_hashmap = new HashMap<>();
public void testForLoop(HashMap<String, String> lastMap) {
Collection<@KeyFor("lastMap") String> sorted = sortedKeySet(lastMap);
for (@KeyFor("lastMap") String key : sorted) {
@NonNull String al = lastMap.get(key);
}
for (@KeyFor("call_hashmap") Integer i : sortedKeySet(call_hashmap)) {}
}
static class Otherclass {
static Map<String, String> map = new HashMap<>();
}
public void testStaticKeyFor(@KeyFor("Otherclass.map") String s1, String s2) {
Otherclass.map.get(s1).toString();
// :: error: (dereference.of.nullable)
Otherclass.map.get(s2).toString();
Otherclass o = new Otherclass();
o.map.get(s1).toString();
// TODO:: error: (dereference.of.nullable)
o.map.get(s2).toString();
}
public class Graph<T> {
HashMap<T, List<@KeyFor("childMap") T>> childMap;
public Graph(HashMap<T, List<@KeyFor("childMap") T>> childMap) {
this.childMap = childMap;
}
public void addNode(T n) {
// body omitted, not relevant to test case
}
public void addEdge2(T parent, T child) {
addNode(parent);
@SuppressWarnings("cast.unsafe")
@KeyFor("childMap") T parent2 = (@KeyFor("childMap") T) parent;
@NonNull List<@KeyFor("childMap") T> l = childMap.get(parent2);
}
// TODO: This is a feature request to have KeyFor inferred
// public void addEdge3( T parent, T child ) {
// addNode(parent);
// parent = (@KeyFor("childMap") T) parent;
// @NonNull List<T> l = childMap.get(parent);
// }
}
/* TODO: add logic that after a call to "put" the first argument is
annotated with @KeyFor. A "@KeyForAfter" annotation to
support this in a general way might be overkill.
Similarly, for calls to "remove" we need to invalidate all (?)
KeyFor annotations.*/
void keyForFlow() {
Map<String, String> leaders = new LinkedHashMap<>();
Set<@KeyFor("leaders") String> varsUsedPreviously =
new LinkedHashSet<@KeyFor("leaders") String>();
String varName = "hello";
leaders.put(varName, "goodbye");
@KeyFor("leaders") String kf = varName;
}
public static void mapPut(String start) {
Map<String, Integer> n2e = new HashMap<>();
n2e.put(start, Integer.valueOf(0));
@KeyFor("n2e") String start2 = start;
}
}