protected int findNullTypeAnnotationMismatch(TypeBinding requiredType, TypeBinding providedType) { int severity = 0; 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 = requiredDimsTagBits[i] & TagBits.AnnotationNullMASK; long providedBits = providedDimsTagBits[i] & TagBits.AnnotationNullMASK; if (requiredBits != 0 && requiredBits != providedBits) { if (providedBits == 0) severity = 1; // need unchecked conversion regarding type detail else return 2; // mismatching annotations } } } } } } return severity; }
public void resolveReceiver() { if (this.receiver == null) return; if (this.receiver.modifiers != 0) { this.scope .problemReporter() .illegalModifiers( this.receiver.declarationSourceStart, this.receiver.declarationSourceEnd); } TypeBinding resolvedReceiverType = this.receiver.type.resolvedType; if (this.binding == null || resolvedReceiverType == null || !resolvedReceiverType.isValidBinding()) { return; } ReferenceBinding declaringClass = this.binding.declaringClass; /* neither static methods nor methods in anonymous types can have explicit 'this' */ if (this.isStatic() || declaringClass.isAnonymousType()) { this.scope.problemReporter().disallowedThisParameter(this.receiver); return; // No need to do further validation } ReferenceBinding enclosingReceiver = this.scope.enclosingReceiverType(); if (this.isConstructor()) { /* Only non static member types or local types can declare explicit 'this' params in constructors */ if (declaringClass.isStatic() || (declaringClass.tagBits & (TagBits.IsLocalType | TagBits.IsMemberType)) == 0) { /* neither member nor local type */ this.scope.problemReporter().disallowedThisParameter(this.receiver); return; // No need to do further validation } enclosingReceiver = enclosingReceiver.enclosingType(); } char[][] tokens = (this.receiver.qualifyingName == null) ? null : this.receiver.qualifyingName.getName(); if (this.isConstructor()) { if (tokens == null || tokens.length > 1 || !CharOperation.equals(enclosingReceiver.sourceName(), tokens[0])) { this.scope .problemReporter() .illegalQualifierForExplicitThis(this.receiver, enclosingReceiver); this.receiver.qualifyingName = null; } } else if (tokens != null && tokens.length > 0) { this.scope.problemReporter().illegalQualifierForExplicitThis2(this.receiver); this.receiver.qualifyingName = null; } if (TypeBinding.notEquals(enclosingReceiver, resolvedReceiverType)) { this.scope.problemReporter().illegalTypeForExplicitThis(this.receiver, enclosingReceiver); } if (this.receiver.type.hasNullTypeAnnotation(AnnotationPosition.ANY)) { this.scope.problemReporter().nullAnnotationUnsupportedLocation(this.receiver.type); } }
public TypeBinding resolveType(BlockScope scope) { this.constant = Constant.NotAConstant; TypeBinding expressionType = this.expression.resolveType(scope); TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/); if (expressionType == null || checkedType == null) return null; if (!checkedType.isReifiable()) { scope.problemReporter().illegalInstanceOfGenericType(checkedType, this); } else if ((expressionType != TypeBinding.NULL && expressionType.isBaseType()) // disallow autoboxing || !checkCastTypesCompatibility(scope, checkedType, expressionType, null)) { scope.problemReporter().notCompatibleTypesError(this, expressionType, checkedType); } return this.resolvedType = TypeBinding.BOOLEAN; }
protected boolean isBoxingCompatible( TypeBinding expressionType, TypeBinding targetType, Expression expression, Scope scope) { if (scope.isBoxingCompatibleWith(expressionType, targetType)) return true; return expressionType .isBaseType() // narrowing then boxing ? Only allowed for some target types see 362279 && !targetType.isBaseType() && !targetType.isTypeVariable() && scope.compilerOptions().sourceLevel >= org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_5 // autoboxing && (targetType.id == TypeIds.T_JavaLangByte || targetType.id == TypeIds.T_JavaLangShort || targetType.id == TypeIds.T_JavaLangCharacter) && expression.isConstantValueOfTypeAssignableToType( expressionType, scope.environment().computeBoxingType(targetType)); }
/** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */ protected void analyseArguments( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, MethodBinding methodBinding, Expression[] arguments) { // compare actual null-status against parameter annotations of the called method: if (arguments != null) { CompilerOptions compilerOptions = currentScope.compilerOptions(); boolean considerTypeAnnotations = compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 && compilerOptions.isAnnotationBasedNullAnalysisEnabled; boolean hasJDK15NullAnnotations = methodBinding.parameterNonNullness != null; int numParamsToCheck = methodBinding.parameters.length; if (considerTypeAnnotations || hasJDK15NullAnnotations) { // check if varargs need special treatment: boolean passThrough = false; if (methodBinding.isVarargs()) { int varArgPos = numParamsToCheck - 1; // this if-block essentially copied from generateArguments(..): if (numParamsToCheck == arguments.length) { TypeBinding varArgsType = methodBinding.parameters[varArgPos]; TypeBinding lastType = arguments[varArgPos].resolvedType; if (lastType == TypeBinding.NULL || (varArgsType.dimensions() == lastType.dimensions() && lastType.isCompatibleWith(varArgsType))) passThrough = true; // pass directly as-is } if (!passThrough) numParamsToCheck--; // with non-passthrough varargs last param is fed from individual // args -> don't check } } if (considerTypeAnnotations) { for (int i = 0; i < numParamsToCheck; i++) { TypeBinding expectedType = methodBinding.parameters[i]; Expression argument = arguments[i]; // prefer check based on type annotations: int severity = findNullTypeAnnotationMismatch(expectedType, argument.resolvedType); if (severity > 0) { // immediate reporting: currentScope .problemReporter() .nullityMismatchingTypeAnnotation( argument, argument.resolvedType, expectedType, severity == 1, currentScope.environment()); // next check flow-based null status against null JDK15-style annotations: } else if (hasJDK15NullAnnotations && methodBinding.parameterNonNullness[i] == Boolean.TRUE) { int nullStatus = argument.nullStatus( flowInfo, flowContext); // slight loss of precision: should also use the null info from // the receiver. if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided flowContext.recordNullityMismatch( currentScope, argument, argument.resolvedType, expectedType, nullStatus); } } } else if (hasJDK15NullAnnotations) { for (int i = 0; i < numParamsToCheck; i++) { if (methodBinding.parameterNonNullness[i] == Boolean.TRUE) { TypeBinding expectedType = methodBinding.parameters[i]; Expression argument = arguments[i]; int nullStatus = argument.nullStatus( flowInfo, flowContext); // slight loss of precision: should also use the null info from // the receiver. if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided flowContext.recordNullityMismatch( currentScope, argument, argument.resolvedType, expectedType, nullStatus); } } } } }
/** Generate invocation arguments, considering varargs methods */ public void generateArguments( MethodBinding binding, Expression[] arguments, BlockScope currentScope, CodeStream codeStream) { if (binding.isVarargs()) { // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) : // foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2}) TypeBinding[] params = binding.parameters; int paramLength = params.length; int varArgIndex = paramLength - 1; for (int i = 0; i < varArgIndex; i++) { arguments[i].generateCode(currentScope, codeStream, true); } ArrayBinding varArgsType = (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex].erasure(); int elementsTypeID = varArgsType.elementsType().id; int argLength = arguments == null ? 0 : arguments.length; if (argLength > paramLength) { // right number but not directly compatible or too many arguments - wrap extra into array // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4) // need to gen elements into an array, then gen each remaining element into created array codeStream.generateInlinedValue(argLength - varArgIndex); codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array for (int i = varArgIndex; i < argLength; i++) { codeStream.dup(); codeStream.generateInlinedValue(i - varArgIndex); arguments[i].generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } } else if (argLength == paramLength) { // right number of arguments - could be inexact - pass argument as is TypeBinding lastType = arguments[varArgIndex].resolvedType; if (lastType == TypeBinding.NULL || (varArgsType.dimensions() == lastType.dimensions() && lastType.isCompatibleWith(varArgsType))) { // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is arguments[varArgIndex].generateCode(currentScope, codeStream, true); } else { // right number but not directly compatible or too many arguments - wrap extra into array // need to gen elements into an array, then gen each remaining element into created array codeStream.generateInlinedValue(1); codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array codeStream.dup(); codeStream.generateInlinedValue(0); arguments[varArgIndex].generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } } else { // not enough arguments - pass extra empty array // scenario: foo(1) --> foo(1, new int[0]) // generate code for an empty array of parameterType codeStream.generateInlinedValue(0); codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array } } else if (arguments != null) { // standard generation for method arguments for (int i = 0, max = arguments.length; i < max; i++) arguments[i].generateCode(currentScope, codeStream, true); } }
public TypeBinding resolveType(BlockScope scope) { // Build an array type reference using the current dimensions // The parser does not check for the fact that dimension may be null // only at the -end- like new int [4][][]. The parser allows new int[][4][] // so this must be checked here......(this comes from a reduction to LL1 grammar) TypeBinding referenceType = type.resolveType(scope, true /* check bounds*/); // will check for null after dimensions are checked constant = Constant.NotAConstant; if (referenceType == VoidBinding) { scope.problemReporter().cannotAllocateVoidArray(this); referenceType = null; } // check the validity of the dimension syntax (and test for all null dimensions) int explicitDimIndex = -1; loop: for (int i = dimensions.length; --i >= 0; ) { if (dimensions[i] != null) { if (explicitDimIndex < 0) explicitDimIndex = i; } else if (explicitDimIndex > 0) { // should not have an empty dimension before an non-empty one scope.problemReporter().incorrectLocationForNonEmptyDimension(this, explicitDimIndex); break loop; } } // explicitDimIndex < 0 says if all dimensions are nulled // when an initializer is given, no dimension must be specified if (initializer == null) { if (explicitDimIndex < 0) { scope.problemReporter().mustDefineDimensionsOrInitializer(this); } // allow new List<?>[5] - only check for generic array when no initializer, since also checked // inside initializer resolution if (referenceType != null && !referenceType.isReifiable()) { scope.problemReporter().illegalGenericArray(referenceType, this); } } else if (explicitDimIndex >= 0) { scope.problemReporter().cannotDefineDimensionsAndInitializer(this); } // dimensions resolution for (int i = 0; i <= explicitDimIndex; i++) { if (dimensions[i] != null) { TypeBinding dimensionType = dimensions[i].resolveTypeExpecting(scope, IntBinding); if (dimensionType != null) { dimensions[i].computeConversion(scope, IntBinding, dimensionType); } } } // building the array binding if (referenceType != null) { if (dimensions.length > 255) { scope.problemReporter().tooManyDimensions(this); } this.resolvedType = scope.createArrayType(referenceType, dimensions.length); // check the initializer if (initializer != null) { if ((initializer.resolveTypeExpecting(scope, this.resolvedType)) != null) initializer.binding = (ArrayBinding) this.resolvedType; } } return this.resolvedType; }
public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) { // Array initializers can only occur on the right hand side of an assignment // expression, therefore the expected type contains the valid information // concerning the type that must be enforced by the elements of the array initializer. // this method is recursive... (the test on isArrayType is the stop case) this.constant = Constant.NotAConstant; if (expectedType instanceof ArrayBinding) { // allow new List<?>[5] if ((this.bits & IsAnnotationDefaultValue) == 0) { // annotation default value need only to be commensurate JLS9.7 // allow new List<?>[5] - only check for generic array when no initializer, since also // checked inside initializer resolution TypeBinding leafComponentType = expectedType.leafComponentType(); if (!leafComponentType.isReifiable()) { scope.problemReporter().illegalGenericArray(leafComponentType, this); } } this.resolvedType = this.binding = (ArrayBinding) expectedType; if (this.expressions == null) return this.binding; TypeBinding elementType = this.binding.elementsType(); for (int i = 0, length = this.expressions.length; i < length; i++) { Expression expression = this.expressions[i]; expression.setExpectedType(elementType); TypeBinding expressionType = expression instanceof ArrayInitializer ? expression.resolveTypeExpecting(scope, elementType) : expression.resolveType(scope); if (expressionType == null) continue; // Compile-time conversion required? if (elementType != expressionType) // must call before computeConversion() and typeMismatchError() scope.compilationUnitScope().recordTypeConversion(elementType, expressionType); if (expression.isConstantValueOfTypeAssignableToType(expressionType, elementType) || expressionType.isCompatibleWith(elementType)) { expression.computeConversion(scope, elementType, expressionType); } else if (scope.isBoxingCompatibleWith(expressionType, elementType) || (expressionType.isBaseType() // narrowing then boxing ? && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing && !elementType.isBaseType() && expression.isConstantValueOfTypeAssignableToType( expressionType, scope.environment().computeBoxingType(elementType)))) { expression.computeConversion(scope, elementType, expressionType); } else { scope.problemReporter().typeMismatchError(expressionType, elementType, expression, null); } } return this.binding; } // infer initializer type for error reporting based on first element TypeBinding leafElementType = null; int dim = 1; if (this.expressions == null) { leafElementType = scope.getJavaLangObject(); } else { Expression expression = this.expressions[0]; while (expression != null && expression instanceof ArrayInitializer) { dim++; Expression[] subExprs = ((ArrayInitializer) expression).expressions; if (subExprs == null) { leafElementType = scope.getJavaLangObject(); expression = null; break; } expression = ((ArrayInitializer) expression).expressions[0]; } if (expression != null) { leafElementType = expression.resolveType(scope); } // fault-tolerance - resolve other expressions as well for (int i = 1, length = this.expressions.length; i < length; i++) { expression = this.expressions[i]; if (expression != null) { expression.resolveType(scope); } } } if (leafElementType != null) { this.resolvedType = scope.createArrayType(leafElementType, dim); if (expectedType != null) scope.problemReporter().typeMismatchError(this.resolvedType, expectedType, this, null); } return null; }
public TypeBinding resolveType(BlockScope scope) { this.constant = Constant.NotAConstant; if ((this.targetType = this.type.resolveType(scope, true /* check bounds*/)) == null) return null; /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=320463 https://bugs.eclipse.org/bugs/show_bug.cgi?id=312076 JLS3 15.8.2 forbids the type named in the class literal expression from being a parameterized type. And the grammar in 18.1 disallows (where X and Y are some concrete types) constructs of the form Outer<X>.class, Outer<X>.Inner.class, Outer.Inner<X>.class, Outer<X>.Inner<Y>.class etc. Corollary wise, we should resolve the type of the class literal expression to be a raw type as class literals exist only for the raw underlying type. */ LookupEnvironment environment = scope.environment(); this.targetType = environment.convertToRawType( this.targetType, true /* force conversion of enclosing types*/); if (this.targetType.isArrayType()) { ArrayBinding arrayBinding = (ArrayBinding) this.targetType; TypeBinding leafComponentType = arrayBinding.leafComponentType; if (leafComponentType == TypeBinding.VOID) { scope.problemReporter().cannotAllocateVoidArray(this); return null; } else if (leafComponentType.isTypeVariable()) { scope .problemReporter() .illegalClassLiteralForTypeVariable((TypeVariableBinding) leafComponentType, this); } } else if (this.targetType.isTypeVariable()) { scope .problemReporter() .illegalClassLiteralForTypeVariable((TypeVariableBinding) this.targetType, this); } // {ObjectTeams: do we need a RoleClassLiteralAccess? if (this.targetType instanceof ReferenceBinding) { ReferenceBinding targetRef = (ReferenceBinding) this.targetType; if (targetRef.isRole()) { if (this.verbatim) { this.targetType = RoleTypeCreator.maybeWrapUnqualifiedRoleType(scope, this.targetType, this); } else { SourceTypeBinding site = scope.enclosingSourceType(); if (scope.methodScope().isStatic // role class literal needs team instance && !site.isRole() // static role method are OK. && !RoleTypeBinding.isRoleWithExplicitAnchor(this.targetType)) // t.R.class? { scope.problemReporter().roleClassLiteralLacksTeamInstance(this, targetRef); return null; } ReferenceBinding teamBinding; if (RoleTypeBinding.isRoleWithExplicitAnchor(targetRef)) teamBinding = targetRef.enclosingType(); else teamBinding = TeamModel.findEnclosingTeamContainingRole(site, targetRef); if (teamBinding == null) scope.problemReporter().externalizedRoleClassLiteral(this, targetRef); else { TypeBinding methodType = RoleClassLiteralAccess.ensureGetClassMethod( teamBinding.getTeamModel(), targetRef.roleModel); // not affected by visibility check (for resilience) this.roleClassLiteralAccess = new RoleClassLiteralAccess(this, methodType); this.resolvedType = this.roleClassLiteralAccess.resolveType(scope); } return this.resolvedType; } } } // SH} ReferenceBinding classType = scope.getJavaLangClass(); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328689 if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { // Integer.class --> Class<Integer>, perform boxing of base types (int.class --> // Class<Integer>) TypeBinding boxedType = null; if (this.targetType.id == T_void) { boxedType = environment.getResolvedType(JAVA_LANG_VOID, scope); } else { boxedType = scope.boxing(this.targetType); } if (environment.usesNullTypeAnnotations()) boxedType = environment.createAnnotatedType( boxedType, new AnnotationBinding[] {environment.getNonNullAnnotation()}); this.resolvedType = environment.createParameterizedType( classType, new TypeBinding[] {boxedType}, null /*not a member*/); } else { this.resolvedType = classType; } return this.resolvedType; }