import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.*;

public class MisuseProperties {

  void propertiesToHashtable(Properties p) {
    // :: error: (argument)
    p.setProperty("line.separator", null);
    // :: error: (argument)
    p.put("line.separator", null);
    Hashtable h = p;
    // Error, because HashTable value has NonNull bound.
    // put(K,V) as a member of the raw type java.util.Hashtable
    // :: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type
    // java.util.Hashtable
    // :: error: (argument)
    h.put("line.separator", null);
    // :: error: (argument)
    System.setProperty("line.separator", null);

    Dictionary d1 = p;
    // No error, because Dictionary value has Nullable bound.
    // :: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type
    // java.util.Dictionary
    d1.put("line.separator", null);

    // :: error: (assignment)
    Dictionary<Object, @Nullable Object> d2 = p;
    d2.put("line.separator", null);

    // :: error: (clear.system.property)
    System.setProperties(p); // OK; p has no null values

    System.clearProperty("foo.bar"); // OK

    // Each of the following should cause an error, because it leaves line.separator null.

    // These first few need to be special-cased, I think:

    // :: error: (clear.system.property)
    System.clearProperty("line.separator");

    p.remove("line.separator");
    p.clear();

    // These are OK because they seem to only add, not remove, properties:
    // p.load(InputStream), p.load(Reader), p.loadFromXML(InputStream)

    // The following problems are a result of treating a Properties as one
    // of its supertypes.  Here are some solutions:
    //  * Forbid treating a Properties object as any of its supertypes.
    //  * Create an annotation on a Properties object, such as
    //    @HasSystemProperties, and forbid some operations (or any
    //    treatment as a supertype) for such properties.

    Set<@KeyFor("p") Object> keys = p.keySet();
    // now remove "line.separator" from the set
    keys.remove("line.separator");
    keys.removeAll(keys);
    keys.clear();
    keys.retainAll(Collections.EMPTY_SET);

    Set<Map.Entry<@KeyFor("p") Object, Object>> entries = p.entrySet();
    // now remove the pair containing "line.separator" from the set, as above

    Collection<Object> values = p.values();
    // now remove the line separator value from values, as above

    Hashtable h9 = p;
    h9.remove("line.separator");
    h9.clear();
    // also access via entrySet, keySet, values

    Dictionary d9 = p;
    d9.remove("line.separator");
  }
}
