You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
4.0 KiB
161 lines
4.0 KiB
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
package codetoanalyze.java.nullsafe_default;
|
|
|
|
import android.app.Activity;
|
|
import android.os.Bundle;
|
|
import android.support.v4.app.Fragment;
|
|
import com.facebook.infer.annotation.Assertions;
|
|
import com.facebook.infer.annotation.Cleanup;
|
|
import com.facebook.infer.annotation.Initializer;
|
|
import javax.annotation.Nullable;
|
|
|
|
/**
|
|
* It is common in Android code to recycle the objects (e.g. views) by nullifying them in the
|
|
* onDestroy() or onDestroyView() methods. This allows the GC to recycle it not waiting the outer
|
|
* object to be freed. This is safe because the lifecycle of the object is over so those field are
|
|
* not going to be accessed. so it is not necessary to annotate those fields with @Nullable.
|
|
*/
|
|
class CanAssignNullInDestroyMethods extends Fragment {
|
|
|
|
String someObject = "";
|
|
|
|
@Override
|
|
public void onDestroyView() {
|
|
someObject = null;
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
someObject = null;
|
|
}
|
|
|
|
public void assignNullDissalowedInAnyOtherMethod() {
|
|
someObject = null; // BAD: field not nullable
|
|
}
|
|
}
|
|
|
|
public class FieldNotNullable {
|
|
@Nullable String nullable = "";
|
|
String notNullable = "";
|
|
|
|
String initializeNonNullableWithNullIsBAD = null;
|
|
@Nullable String initializeNullableWithNullIsOK = null;
|
|
|
|
@Nullable
|
|
String getNullable() {
|
|
return "";
|
|
}
|
|
|
|
String getNotNullable() {
|
|
return "";
|
|
}
|
|
|
|
void setNullableToNotNullableIsBAD(@Nullable String s) {
|
|
notNullable = null; // BAD
|
|
notNullable = s; // BAD
|
|
notNullable = getNullable(); // BAD (even though getNullable() does not really return null)
|
|
}
|
|
|
|
void setNullableToNullableIsOK(@Nullable String s) {
|
|
nullable = null; // OK
|
|
nullable = s; // OK
|
|
nullable = getNullable(); // OK
|
|
}
|
|
|
|
void setNotNullableToNotNullableIsOK(String s) {
|
|
notNullable = "abc"; // OK
|
|
notNullable = s; // OK
|
|
notNullable = getNotNullable(); // OK
|
|
}
|
|
}
|
|
|
|
class MixedInitializers extends Activity {
|
|
|
|
private String field1 = "1";
|
|
private String field2;
|
|
private String field3;
|
|
|
|
MixedInitializers() {
|
|
field2 = "2";
|
|
}
|
|
|
|
protected void onCreate(Bundle bundle) {
|
|
field3 = "3";
|
|
}
|
|
}
|
|
|
|
class TestInitializerBuilder {
|
|
String required1;
|
|
String required2;
|
|
@Nullable String optional;
|
|
|
|
// No FIELD_NOT_INITIALIZED error should be reported, because of the @Initializer annotations.
|
|
TestInitializerBuilder() {}
|
|
|
|
// This is an initializer and must always be called before build().
|
|
@Initializer
|
|
TestInitializerBuilder setRequired1(String required1) {
|
|
this.required1 = required1;
|
|
return this;
|
|
}
|
|
|
|
// This is an initializer and must always be called before build().
|
|
@Initializer
|
|
TestInitializerBuilder setRequired2(String required2) {
|
|
this.required2 = required2;
|
|
return this;
|
|
}
|
|
|
|
TestInitializerBuilder setOptional(String optional) {
|
|
this.optional = optional;
|
|
return this;
|
|
}
|
|
|
|
TestInitializer build() {
|
|
// Fail hard if the required fields are not initialzed
|
|
Assertions.assertCondition(required1 != null && required2 != null);
|
|
|
|
return new TestInitializer(this);
|
|
}
|
|
|
|
@Cleanup
|
|
void testCleanup() {
|
|
this.required1 = null;
|
|
this.required2 = null;
|
|
this.optional = null;
|
|
}
|
|
}
|
|
|
|
class TestInitializer {
|
|
String required1; // should always be set
|
|
String required2; // should always be set
|
|
@Nullable String optional; // optionally set
|
|
|
|
TestInitializer(TestInitializerBuilder b) {
|
|
required1 = b.required1;
|
|
required2 = b.required2;
|
|
optional = b.optional;
|
|
}
|
|
|
|
static void testInitializerClientA() {
|
|
TestInitializerBuilder b = new TestInitializerBuilder();
|
|
b.setRequired1("hello");
|
|
b.setRequired2("world");
|
|
TestInitializer x = b.build();
|
|
}
|
|
|
|
static void testInitializerClientB() {
|
|
TestInitializerBuilder b = new TestInitializerBuilder();
|
|
b.setRequired1("a");
|
|
b.setRequired2("b");
|
|
b.setOptional("c");
|
|
TestInitializer x = b.build();
|
|
}
|
|
}
|