|
|
|
/*
|
|
|
|
* Copyright (c) 2017 - present Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*/
|
|
|
|
package codetoanalyze.java.checkers;
|
|
|
|
|
|
|
|
import com.google.common.base.Preconditions;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
|
|
|
|
public class NullableViolation {
|
|
|
|
|
|
|
|
class T {
|
|
|
|
int x;
|
|
|
|
|
|
|
|
void doSomething() {}
|
|
|
|
}
|
|
|
|
|
|
|
|
static native @Nullable T returnsNullable();
|
|
|
|
|
|
|
|
void dereferenceNullableReturnValueBad() {
|
|
|
|
T t = returnsNullable();
|
|
|
|
t.x = 42; // reports here
|
|
|
|
}
|
|
|
|
|
|
|
|
void dereferenceNullableReturnValueOkay() {
|
|
|
|
T t = returnsNullable();
|
|
|
|
if (t != null) {
|
|
|
|
t.x = 42; // does not report here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dereferenceNullableMethodBad() {
|
|
|
|
returnsNullable().doSomething(); // reports here
|
|
|
|
}
|
|
|
|
|
|
|
|
void dereferenceNullableMethodCheckedForNullOkay() {
|
|
|
|
if (returnsNullable() != null) {
|
|
|
|
returnsNullable().doSomething(); // does not report here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void nullableMethodCheckedForNullAndReturnOkay() {
|
|
|
|
if (returnsNullable() == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
returnsNullable().doSomething(); // does not report here
|
|
|
|
}
|
|
|
|
|
|
|
|
void dereferenceNullableMethodIncorrectlyCheckedForNullBad() {
|
|
|
|
if (returnsNullable() == null) {
|
|
|
|
returnsNullable().doSomething(); // reports here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dereferenceNullableMethodInElseBranchBad() {
|
|
|
|
if (returnsNullable() != null) {
|
|
|
|
} else {
|
|
|
|
returnsNullable().doSomething(); // reports here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
native boolean star();
|
|
|
|
|
|
|
|
void dereferenceNullableMethodAlwaysCheckedForNullOkay() {
|
|
|
|
if (star() && returnsNullable() != null) {
|
|
|
|
returnsNullable().doSomething(); // does not report here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dereferenceNullableMethodNotAlwaysCheckedForNullBad() {
|
|
|
|
if (star() || returnsNullable() != null) {
|
|
|
|
returnsNullable().doSomething(); // reports here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void usePreconditionsCheckNotNullOnVariableOkay() {
|
|
|
|
T t = returnsNullable();
|
|
|
|
Preconditions.checkNotNull(t);
|
|
|
|
t.doSomething(); // does not report here
|
|
|
|
}
|
|
|
|
|
|
|
|
void usePreconditionsCheckNotNullOnMethodOkay() {
|
|
|
|
Preconditions.checkNotNull(returnsNullable()).doSomething(); // does not report here
|
|
|
|
}
|
|
|
|
|
|
|
|
void usePreconditionsCheckNotNullRepeatedCallOkay() {
|
|
|
|
Preconditions.checkNotNull(returnsNullable());
|
|
|
|
returnsNullable().doSomething(); // does not report here
|
|
|
|
}
|
|
|
|
|
|
|
|
native @Nullable Object getNullableObject();
|
|
|
|
|
|
|
|
void pointerAssignmentWithSubtype() {
|
|
|
|
Object object = getNullableObject();
|
|
|
|
object = "Hello";
|
|
|
|
}
|
|
|
|
|
|
|
|
void deferenceAliasOfNullableValueCheckedForNullOkay() {
|
|
|
|
T t = returnsNullable();
|
|
|
|
T s = t;
|
|
|
|
if (t != null) {
|
|
|
|
s.x = 42;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dereferenceWithAssignmentExpressionsOkay() {
|
|
|
|
T t;
|
|
|
|
while ((t = returnsNullable()) != null) {
|
|
|
|
t.doSomething();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|