/** * Check whether this type reference conforms to the null constraints defined for the * corresponding type variable. */ protected void checkNullConstraints( Scope scope, Substitution substitution, TypeBinding[] variables, int rank) { if (variables != null && variables.length > rank) { TypeBinding variable = variables[rank]; if (variable.hasNullTypeAnnotations()) { if (NullAnnotationMatching.analyse( variable, this.resolvedType, null, substitution, -1, null, CheckMode.BOUND_CHECK) .isAnyMismatch()) scope.problemReporter().nullityMismatchTypeArgument(variable, this.resolvedType, this); } } checkIllegalNullAnnotation(scope); }
// additional parameter strict: if true we do not tolerate incompatibly missing annotations on // type parameters (for overriding analysis) public static NullAnnotationMatching analyse( TypeBinding requiredType, TypeBinding providedType, int nullStatus, boolean strict) { int severity = 0; TypeBinding superTypeHint = null; if (requiredType instanceof ArrayBinding) { long[] requiredDimsTagBits = ((ArrayBinding) requiredType).nullTagBitsPerDimension; if (requiredDimsTagBits != null) { int dims = requiredType.dimensions(); if (requiredType.dimensions() == providedType.dimensions()) { long[] providedDimsTagBits = ((ArrayBinding) providedType).nullTagBitsPerDimension; if (providedDimsTagBits == null) { severity = 1; // required is annotated, provided not, need unchecked conversion } else { for (int i = 0; i <= dims; i++) { long requiredBits = validNullTagBits(requiredDimsTagBits[i]); long providedBits = validNullTagBits(providedDimsTagBits[i]); if (i > 0) nullStatus = -1; // don't use beyond the outermost dimension severity = Math.max( severity, computeNullProblemSeverity(requiredBits, providedBits, nullStatus, strict)); if (severity == 2) return NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH; } } } else if (providedType.id == TypeIds.T_null) { if (dims > 0 && requiredDimsTagBits[0] == TagBits.AnnotationNonNull) return NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH; } } } else if (requiredType.hasNullTypeAnnotations() || providedType.hasNullTypeAnnotations()) { long requiredBits = requiredNullTagBits(requiredType); if (requiredBits != TagBits.AnnotationNullable // nullable lhs accepts everything, ... || nullStatus == -1) // only at detail/recursion even nullable must be matched exactly { long providedBits = providedNullTagBits(providedType); severity = computeNullProblemSeverity( requiredBits, providedBits, nullStatus, strict && nullStatus == -1); } if (severity < 2) { TypeBinding providedSuper = providedType.findSuperTypeOriginatingFrom(requiredType); if (providedSuper != providedType) // $IDENTITY-COMPARISON$ superTypeHint = providedSuper; if (requiredType.isParameterizedType() && providedSuper instanceof ParameterizedTypeBinding) { // TODO(stephan): handle providedType.isRaw() TypeBinding[] requiredArguments = ((ParameterizedTypeBinding) requiredType).arguments; TypeBinding[] providedArguments = ((ParameterizedTypeBinding) providedSuper).arguments; if (requiredArguments != null && providedArguments != null && requiredArguments.length == providedArguments.length) { for (int i = 0; i < requiredArguments.length; i++) { NullAnnotationMatching status = analyse(requiredArguments[i], providedArguments[i], -1, strict); severity = Math.max(severity, status.severity); if (severity == 2) return new NullAnnotationMatching(severity, superTypeHint); } } } TypeBinding requiredEnclosing = requiredType.enclosingType(); TypeBinding providedEnclosing = providedType.enclosingType(); if (requiredEnclosing != null && providedEnclosing != null) { NullAnnotationMatching status = analyse(requiredEnclosing, providedEnclosing, -1, strict); severity = Math.max(severity, status.severity); } } } if (severity == 0) return NullAnnotationMatching.NULL_ANNOTATIONS_OK; return new NullAnnotationMatching(severity, superTypeHint); }