private static boolean parameterCanBeNull(Symbol variableSymbol, boolean nullableParameters) { if (variableSymbol.type().isPrimitive()) { return false; } return isAnnotatedNullable(variableSymbol) || (nullableParameters && !isAnnotatedNonNull(variableSymbol)); }
private static boolean isGloballyAnnotatedWithEclipseNonNullByDefault(Symbol.MethodSymbol symbol, String parameter) { List<SymbolMetadata.AnnotationValue> valuesForGlobalAnnotation = valuesForGlobalAnnotation(symbol, ORG_ECLIPSE_JDT_ANNOTATION_NON_NULL_BY_DEFAULT); if (valuesForGlobalAnnotation == null) { return false; } return valuesForGlobalAnnotation.isEmpty() || checkAnnotationParameter(valuesForGlobalAnnotation, "value", parameter); } }
private static boolean isExpectedValue(Object annotationValue, String expectedValue) { if (annotationValue instanceof Tree) { // from sources return containsValue((Tree) annotationValue, expectedValue); } // from binaries if (annotationValue instanceof Object[]) { return containsValue((Object[]) annotationValue, expectedValue); } return expectedValue.equals(((Symbol) annotationValue).name()); }
@CheckForNull public static String nonNullAnnotationOnParameters(Symbol.MethodSymbol method) { if (valuesForGlobalAnnotation(method, JAVAX_ANNOTATION_PARAMETERS_ARE_NONNULL_BY_DEFAULT) != null) { return JAVAX_ANNOTATION_PARAMETERS_ARE_NONNULL_BY_DEFAULT; } else if (valuesForGlobalAnnotation(method, ORG_SPRINGFRAMEWORK_LANG_NON_NULL_API) != null) { return ORG_SPRINGFRAMEWORK_LANG_NON_NULL_API; } else if (isGloballyAnnotatedWithEclipseNonNullByDefault(method, "PARAMETER")) { return ORG_ECLIPSE_JDT_ANNOTATION_NON_NULL_BY_DEFAULT; } return null; }
@CheckForNull private static String nonNullReturnTypeAnnotation(Symbol symbol) { if (symbol.isMethodSymbol() && !isUsingNullable(symbol)) { Symbol.MethodSymbol methodSymbol = (Symbol.MethodSymbol) symbol; if (isGloballyAnnotatedWithEclipseNonNullByDefault(methodSymbol, "RETURN_TYPE")) { return ORG_ECLIPSE_JDT_ANNOTATION_NON_NULL_BY_DEFAULT; } else if (valuesForGlobalAnnotation(methodSymbol, ORG_SPRINGFRAMEWORK_LANG_NON_NULL_API) != null) { return ORG_SPRINGFRAMEWORK_LANG_NON_NULL_API; } } return null; }
private static boolean isNonNullMethodInvocation(ExpressionTree expr) { return expr.is(Tree.Kind.METHOD_INVOCATION) && isAnnotatedNonNull(((MethodInvocationTree) expr).symbol()); }
private Iterable<ProgramState> startingStates(MethodTree tree, ProgramState currentState) { Stream<ProgramState> stateStream = Stream.of(currentState); boolean isEqualsMethod = EQUALS.matches(tree); boolean nonNullParameters = isGloballyAnnotatedParameterNonNull(methodTree.symbol()); boolean nullableParameters = isGloballyAnnotatedParameterNullable(methodTree.symbol()); boolean hasMethodBehavior = methodBehavior != null; for (final VariableTree variableTree : tree.parameters()) { // create final SymbolicValue sv = constraintManager.createSymbolicValue(variableTree); Symbol variableSymbol = variableTree.symbol(); if (hasMethodBehavior) { methodBehavior.addParameter(sv); } stateStream = stateStream.map(ps -> ps.put(variableSymbol, sv)); if (isEqualsMethod || parameterCanBeNull(variableSymbol, nullableParameters)) { stateStream = stateStream.flatMap((ProgramState ps) -> Stream.concat( sv.setConstraint(ps, ObjectConstraint.NULL).stream(), sv.setConstraint(ps, ObjectConstraint.NOT_NULL).stream() )); } else if (nonNullParameters || isAnnotatedNonNull(variableSymbol)) { stateStream = stateStream.flatMap(ps -> sv.setConstraint(ps, ObjectConstraint.NOT_NULL).stream()); } } return stateStream.collect(Collectors.toList()); }
private static boolean isUsingNonNull(Symbol symbol) { if (isNullableThroughNonNull(symbol)) { return false; } SymbolMetadata metadata = symbol.metadata(); return NONNULL_ANNOTATIONS.stream().anyMatch(metadata::isAnnotatedWith) || nonNullReturnTypeAnnotation(symbol) != null || nonNullFieldAnnotation(symbol) != null; }
@CheckForNull public static String nonNullAnnotation(Symbol symbol) { SymbolMetadata metadata = symbol.metadata(); if (isAnnotatedNullable(symbol)) { return null; } Optional<String> result = NONNULL_ANNOTATIONS.stream().filter(metadata::isAnnotatedWith).findFirst(); if (result.isPresent()) { return result.get(); } String nonNullReturnAnnotation = nonNullReturnTypeAnnotation(symbol); if (nonNullReturnAnnotation != null) { return nonNullReturnAnnotation; } return nonNullFieldAnnotation(symbol); }
public static boolean isAnnotatedNonNull(Symbol symbol) { if (isAnnotatedNullable(symbol)) { return false; } return isUsingNonNull(symbol) || ((SymbolMetadataResolve) symbol.metadata()).metaAnnotations().stream().anyMatch(NullableAnnotationUtils::isUsingNonNull); }
private static boolean checkAnnotationParameter(List<SymbolMetadata.AnnotationValue> valuesForAnnotation, String fieldName, String expectedValue) { return valuesForAnnotation.stream() .filter(annotationValue -> fieldName.equals(annotationValue.name())) .anyMatch(annotationValue -> isExpectedValue(annotationValue.value(), expectedValue)); }
private static boolean isNullableThroughNonNull(Symbol symbol) { List<SymbolMetadata.AnnotationValue> valuesForAnnotation = symbol.metadata().valuesForAnnotation("javax.annotation.Nonnull"); if (valuesForAnnotation == null || valuesForAnnotation.isEmpty()) { return false; } return checkAnnotationParameter(valuesForAnnotation, "when", "MAYBE") || checkAnnotationParameter(valuesForAnnotation, "when", "UNKNOWN"); }
private static boolean isUsingNullable(Symbol symbol) { SymbolMetadata metadata = symbol.metadata(); return NULLABLE_ANNOTATIONS.stream().anyMatch(metadata::isAnnotatedWith) || isNullableThroughNonNull(symbol); }
private static boolean parameterIsNullable(Symbol.MethodSymbol method, Symbol argumentSymbol) { return isAnnotatedNullable(argumentSymbol) || EQUALS_METHODS.anyMatch(method); } }
private static boolean isNonNullMethodInvocation(ExpressionTree expr) { return expr.is(Tree.Kind.METHOD_INVOCATION) && isAnnotatedNonNull(((MethodInvocationTree) expr).symbol()); }
private Iterable<ProgramState> startingStates(MethodTree tree, ProgramState currentState) { Stream<ProgramState> stateStream = Stream.of(currentState); boolean isEqualsMethod = EQUALS.matches(tree); boolean nonNullParameters = isGloballyAnnotatedParameterNonNull(methodTree.symbol()); boolean nullableParameters = isGloballyAnnotatedParameterNullable(methodTree.symbol()); boolean hasMethodBehavior = methodBehavior != null; for (final VariableTree variableTree : tree.parameters()) { // create final SymbolicValue sv = constraintManager.createSymbolicValue(variableTree); Symbol variableSymbol = variableTree.symbol(); if (hasMethodBehavior) { methodBehavior.addParameter(sv); } stateStream = stateStream.map(ps -> ps.put(variableSymbol, sv)); if (isEqualsMethod || parameterCanBeNull(variableSymbol, nullableParameters)) { stateStream = stateStream.flatMap((ProgramState ps) -> Stream.concat( sv.setConstraint(ps, ObjectConstraint.NULL).stream(), sv.setConstraint(ps, ObjectConstraint.NOT_NULL).stream() )); } else if (nonNullParameters || isAnnotatedNonNull(variableSymbol)) { stateStream = stateStream.flatMap(ps -> sv.setConstraint(ps, ObjectConstraint.NOT_NULL).stream()); } } return stateStream.collect(Collectors.toList()); }
private static boolean isUsingNonNull(Symbol symbol) { if (isNullableThroughNonNull(symbol)) { return false; } SymbolMetadata metadata = symbol.metadata(); return NONNULL_ANNOTATIONS.stream().anyMatch(metadata::isAnnotatedWith) || nonNullReturnTypeAnnotation(symbol) != null || nonNullFieldAnnotation(symbol) != null; }
@CheckForNull private static String nonNullReturnTypeAnnotation(Symbol symbol) { if (symbol.isMethodSymbol() && !isUsingNullable(symbol)) { Symbol.MethodSymbol methodSymbol = (Symbol.MethodSymbol) symbol; if (isGloballyAnnotatedWithEclipseNonNullByDefault(methodSymbol, "RETURN_TYPE")) { return ORG_ECLIPSE_JDT_ANNOTATION_NON_NULL_BY_DEFAULT; } else if (valuesForGlobalAnnotation(methodSymbol, ORG_SPRINGFRAMEWORK_LANG_NON_NULL_API) != null) { return ORG_SPRINGFRAMEWORK_LANG_NON_NULL_API; } } return null; }
@CheckForNull public static String nonNullAnnotation(Symbol symbol) { SymbolMetadata metadata = symbol.metadata(); if (isAnnotatedNullable(symbol)) { return null; } Optional<String> result = NONNULL_ANNOTATIONS.stream().filter(metadata::isAnnotatedWith).findFirst(); if (result.isPresent()) { return result.get(); } String nonNullReturnAnnotation = nonNullReturnTypeAnnotation(symbol); if (nonNullReturnAnnotation != null) { return nonNullReturnAnnotation; } return nonNullFieldAnnotation(symbol); }
public static boolean isAnnotatedNonNull(Symbol symbol) { if (isAnnotatedNullable(symbol)) { return false; } return isUsingNonNull(symbol) || ((SymbolMetadataResolve) symbol.metadata()).metaAnnotations().stream().anyMatch(NullableAnnotationUtils::isUsingNonNull); }