Update nullaway and add a Contract for StringUtils. (#3432)

* Update nullaway and add a Contract for StringUtils.

* RUNTIME

* SOURCE

* Cleanup
This commit is contained in:
Anuraag Agrawal 2021-08-12 14:50:39 +09:00 committed by GitHub
parent cb5198ba99
commit 182455023a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 127 additions and 5 deletions

View File

@ -6,6 +6,7 @@
package io.opentelemetry.api.baggage.propagation;
import java.util.BitSet;
import javax.annotation.Nullable;
/**
* Represents single element of a W3C baggage header (key or value). Allows tracking parsing of a
@ -36,7 +37,7 @@ class Element {
private boolean trailingSpace;
private int start;
private int end;
private String value;
@Nullable private String value;
static Element createKeyElement() {
return new Element(EXCLUDED_KEY_CHARS);
@ -56,6 +57,7 @@ class Element {
reset(0);
}
@Nullable
String getValue() {
return value;
}

View File

@ -7,6 +7,7 @@ package io.opentelemetry.api.baggage.propagation;
import io.opentelemetry.api.baggage.BaggageBuilder;
import io.opentelemetry.api.baggage.BaggageEntryMetadata;
import javax.annotation.Nullable;
/**
* Implements single-pass Baggage parsing in accordance with https://w3c.github.io/baggage/ Key /
@ -82,7 +83,11 @@ class Parser {
break;
case KEY: // none
}
baggageBuilder.put(key.getValue(), value.getValue(), BaggageEntryMetadata.create(meta));
putBaggage(
baggageBuilder,
key.getValue(),
value.getValue(),
BaggageEntryMetadata.create(meta));
reset(i + 1);
break;
}
@ -107,20 +112,32 @@ class Parser {
case META:
{
String rest = baggageHeader.substring(metaStart).trim();
baggageBuilder.put(key.getValue(), value.getValue(), BaggageEntryMetadata.create(rest));
putBaggage(
baggageBuilder, key.getValue(), value.getValue(), BaggageEntryMetadata.create(rest));
break;
}
case VALUE:
{
if (!skipToNext) {
value.tryTerminating(baggageHeader.length(), baggageHeader);
baggageBuilder.put(key.getValue(), value.getValue());
putBaggage(
baggageBuilder, key.getValue(), value.getValue(), BaggageEntryMetadata.empty());
break;
}
}
}
}
private static void putBaggage(
BaggageBuilder baggage,
@Nullable String key,
@Nullable String value,
BaggageEntryMetadata metadata) {
if (key != null && value != null) {
baggage.put(key, value, metadata);
}
}
/**
* Resets parsing state, preparing to start a new list element (see spec).
*

View File

@ -0,0 +1,100 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright 2000-2021 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opentelemetry.api.internal;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specifies some aspects of the method behavior depending on the arguments. Can be used by tools
* for advanced data flow analysis. Note that this annotation just describes how the code works and
* doesn't add any functionality by means of code generation.
*
* <p>Method contract has the following syntax:<br>
*
* <pre>{@code
* contract ::= (clause ';')* clause
* clause ::= args '->' effect
* args ::= ((arg ',')* arg )?
* arg ::= value-constraint
* value-constraint ::= '_' | 'null' | '!null' | 'false' | 'true'
* effect ::= value-constraint | 'fail' | 'this' | 'new' | 'param<N>'
* }</pre>
*
* <p>The constraints denote the following:<br>
*
* <ul>
* <li>_ - any value
* <li>null - null value
* <li>!null - a value statically proved to be not-null
* <li>true - true boolean value
* <li>false - false boolean value
* </ul>
*
* <p>The additional return values denote the following:<br>
*
* <ul>
* <li>fail - the method throws an exception, if the arguments satisfy argument constraints
* <li>new - (supported in IntelliJ IDEA since version 2018.2) the method returns a non-null new
* object which is distinct from any other object existing in the heap prior to method
* execution. If method is also pure, then we can be sure that the new object is not stored to
* any field/array and will be lost if method return value is not used.
* <li>this - (supported in IntelliJ IDEA since version 2018.2) the method returns its qualifier
* value (not applicable for static methods)
* <li>param1, param2, ... - (supported in IntelliJ IDEA since version 2018.2) the method returns
* its first (second, ...) parameter value
* </ul>
*
* <p>Examples:
*
* <p>{@code @Contract("_, null -> null")} - the method returns null if its second argument is null
* <br>
* {@code @Contract("_, null -> null; _, !null -> !null")} - the method returns null if its second
* argument is null and not-null otherwise<br>
* {@code @Contract("true -> fail")} - a typical {@code assertFalse} method which throws an
* exception if {@code true} is passed to it<br>
* {@code @Contract("_ -> this")} - the method always returns its qualifier (e.g. {@link
* StringBuilder#append(String)}). {@code @Contract("null -> fail; _ -> param1")} - the method
* throws an exception if the first argument is null, otherwise it returns the first argument (e.g.
* {@code Objects.requireNonNull}).<br>
* {@code @Contract("!null, _ -> param1; null, !null -> param2; null, null -> fail")} - the method
* returns the first non-null argument, or throws an exception if both arguments are null (e.g.
* {@code Objects.requireNonNullElse} in Java 9).<br>
*
* <p>This annotation is the same provided with Jetbrains annotations and used by Nullaway for
* verifying nullness. We copy the annotation to avoid an external dependency.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface Contract {
/**
* Contains the contract clauses describing causal relations between call arguments and the
* returned value.
*/
String value() default "";
}

View File

@ -27,6 +27,7 @@ public final class StringUtils {
* @param string a string reference to check
* @return {@code true} if the string is null or is the empty string
*/
@Contract("null -> true")
public static boolean isNullOrEmpty(@Nullable String string) {
return string == null || string.isEmpty();
}

View File

@ -64,6 +64,8 @@ tasks {
// Allow underscore in test-type method names
disable("MemberName")
}
option("NullAway:CustomContractAnnotations", "io.opentelemetry.api.internal.Contract")
}
errorprone.nullaway {

View File

@ -80,7 +80,7 @@ val DEPENDENCIES = listOf(
"com.squareup.okhttp3:okhttp:4.9.1",
"com.sun.net.httpserver:http:20070405",
"com.tngtech.archunit:archunit-junit4:0.19.0",
"com.uber.nullaway:nullaway:0.9.1",
"com.uber.nullaway:nullaway:0.9.2",
"edu.berkeley.cs.jqf:jqf-fuzz:1.7",
"eu.rekawek.toxiproxy:toxiproxy-java:2.1.4",
"io.github.netmikey.logunit:logunit-jul:1.1.0",