blob: 29cc943792e12f22c4bd1598d39f612dfb98c209 [file] [log] [blame]
import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.interning.qual.*;
public class StringIntern {
// It would be very handy (and would eliminate quite a few annotations)
// if any final variable that is initialized to something interned
// (essentially, to a literal) were treated as implicitly @Interned.
final String finalStringInitializedToInterned = "foo"; // implicitly @Interned
final String finalString2 = new String("foo");
static final String finalStringStatic1 = "foo"; // implicitly @Interned
static final String finalStringStatic2 = new String("foo");
static class HasFields {
static final String finalStringStatic3 = "foo"; // implicitly @Interned
static final String finalStringStatic4 = new String("foo");
}
static class Foo {
private static Map<Foo, @Interned Foo> pool = new HashMap<>();
@SuppressWarnings("interning")
public @Interned Foo intern() {
if (!pool.containsKey(this)) {
pool.put(this, (@Interned Foo) this);
}
return pool.get(this);
}
}
// Another example of the "final initialized to interned" rule
final Foo finalFooInitializedToInterned = new Foo().intern();
public void test(@Interned String arg) {
String notInternedStr = new String("foo");
@Interned String internedStr = notInternedStr.intern();
internedStr = finalStringInitializedToInterned; // OK
// :: error: (assignment)
internedStr = finalString2; // error
@Interned Foo internedFoo = finalFooInitializedToInterned; // OK
if (arg == finalStringStatic1) {} // OK
// :: error: (not.interned)
if (arg == finalStringStatic2) {} // error
if (arg == HasFields.finalStringStatic3) {} // OK
// :: error: (not.interned)
if (arg == HasFields.finalStringStatic4) {} // error
}
private @Interned String base;
static final String BASE_HASHCODE = "hashcode";
public void foo() {
if (base == BASE_HASHCODE) {}
}
public @Interned String emptyString(boolean b) {
if (b) {
return "";
} else {
return ("");
}
}
}