blob: 577ea90b35bede265fc9373aa6b9a52b59adc343 [file] [log] [blame]
package org.checkerframework.checker.nullness;
import com.sun.source.tree.MethodInvocationTree;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.ExecutableElement;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType;
import org.checkerframework.javacutil.TreeUtils;
/**
* Utility class for handling {@link java.lang.System#getProperty(String)} and related invocations.
*
* <p>The result of the method call is is assumed to be non-null if the argument is a literal key
* that is guaranteed to be present in the system properties (according to the documentation of
* {@link java.lang.System#getProperty(String)}), as in {@code
* System.getProperties("line.separator")}.
*/
public class SystemGetPropertyHandler {
/**
* If true, client code may clear system properties, and this class (SystemGetPropertyHandler) has
* no effect.
*/
private final boolean permitClearProperty;
/** The processing environment. */
private final ProcessingEnvironment env;
/** The factory for constructing and looking up types. */
private final NullnessAnnotatedTypeFactory factory;
/** The System.getProperty(String) method. */
private final ExecutableElement systemGetProperty;
/** The System.setProperty(String) method. */
private final ExecutableElement systemSetProperty;
/**
* System properties that are defined at startup on every JVM.
*
* <p>This list is from the Javadoc of System.getProperties, for Java 11.
*/
public static final Collection<String> predefinedSystemProperties =
new HashSet<>(
Arrays.asList(
"java.version",
"java.version.date",
"java.vendor",
"java.vendor.url",
"java.vendor.version",
"java.home",
"java.vm.specification.version",
"java.vm.specification.vendor",
"java.vm.specification.name",
"java.vm.version",
"java.vm.vendor",
"java.vm.name",
"java.specification.version",
"java.specification.vendor",
"java.specification.name",
"java.class.version",
"java.class.path",
"java.library.path",
"java.io.tmpdir",
"java.compiler",
"os.name",
"os.arch",
"os.version",
"file.separator",
"path.separator",
"line.separator",
"user.name",
"user.home",
"user.dir"));
/**
* Creates a SystemGetPropertyHandler.
*
* @param env the processing environment
* @param factory the factory for constructing and looking up types
* @param permitClearProperty if true, client code may clear system properties, and this object
* does nothing
*/
public SystemGetPropertyHandler(
ProcessingEnvironment env,
NullnessAnnotatedTypeFactory factory,
boolean permitClearProperty) {
this.env = env;
this.factory = factory;
this.permitClearProperty = permitClearProperty;
systemGetProperty = TreeUtils.getMethod("java.lang.System", "getProperty", 1, env);
systemSetProperty = TreeUtils.getMethod("java.lang.System", "setProperty", 2, env);
}
/**
* Apply rules regarding System.getProperty and related methods.
*
* @param tree a method invocation
* @param method the method being invoked
*/
public void handle(MethodInvocationTree tree, AnnotatedExecutableType method) {
if (permitClearProperty) {
return;
}
if (TreeUtils.isMethodInvocation(tree, systemGetProperty, env)
|| TreeUtils.isMethodInvocation(tree, systemSetProperty, env)) {
String literal = NullnessVisitor.literalFirstArgument(tree);
if (literal != null && predefinedSystemProperties.contains(literal)) {
AnnotatedTypeMirror type = method.getReturnType();
type.replaceAnnotation(factory.NONNULL);
}
}
}
}