void checkAgainstInheritedMethods( MethodBinding currentMethod, MethodBinding[] methods, int length, MethodBinding[] allInheritedMethods) { CompilerOptions options = type.scope.compilerOptions(); // need to find the overridden methods to avoid blaming this type for issues which are already // reported against a supertype // but cannot ignore an overridden inherited method completely when it comes to checking for // bridge methods int[] overriddenInheritedMethods = length > 1 ? findOverriddenInheritedMethods(methods, length) : null; nextMethod: for (int i = length; --i >= 0; ) { MethodBinding inheritedMethod = methods[i]; if (overriddenInheritedMethods == null || overriddenInheritedMethods[i] == 0) { if (currentMethod.isStatic() != inheritedMethod .isStatic()) { // Cannot override a static method or hide an instance method problemReporter(currentMethod).staticAndInstanceConflict(currentMethod, inheritedMethod); continue nextMethod; } // want to tag currentMethod even if return types are not equal if (inheritedMethod.isAbstract()) { currentMethod.modifiers |= ExtraCompilerModifiers.AccImplementing | ExtraCompilerModifiers.AccOverriding; // with the above change an abstract method is tagged as implementing the inherited // abstract method // if (!currentMethod.isAbstract() && inheritedMethod.isAbstract()) { // if ((currentMethod.modifiers & CompilerModifiers.AccOverriding) == 0) // currentMethod.modifiers |= CompilerModifiers.AccImplementing; } else { currentMethod.modifiers |= ExtraCompilerModifiers.AccOverriding; } if (!areReturnTypesCompatible(currentMethod, inheritedMethod)) { if (!(currentMethod.returnType != null && currentMethod.returnType.isObjectLiteralType() && inheritedMethod.returnType != null && inheritedMethod.returnType.isObjectLiteralType())) if (reportIncompatibleReturnTypeError(currentMethod, inheritedMethod)) continue nextMethod; } if (!isAsVisible(currentMethod, inheritedMethod)) problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod); if (options.reportDeprecationWhenOverridingDeprecatedMethod && inheritedMethod.isViewedAsDeprecated()) { if (!currentMethod.isViewedAsDeprecated() || options.reportDeprecationInsideDeprecatedCode) { problemReporter(currentMethod) .overridesDeprecatedMethod(currentMethod, inheritedMethod); } } } checkForBridgeMethod(currentMethod, inheritedMethod, allInheritedMethods); } }
void checkAgainstInheritedMethods( MethodBinding currentMethod, MethodBinding[] methods, int length) { nextMethod: for (int i = length; --i >= 0; ) { MethodBinding inheritedMethod = methods[i]; if (currentMethod.isStatic() != inheritedMethod .isStatic()) { // Cannot override a static method or hide an instance method this.problemReporter(currentMethod) .staticAndInstanceConflict(currentMethod, inheritedMethod); continue nextMethod; } if (!currentMethod.isAbstract() && inheritedMethod.isAbstract()) { if ((currentMethod.modifiers & CompilerModifiers.AccOverriding) == 0) currentMethod.modifiers |= CompilerModifiers.AccImplementing; } else { currentMethod.modifiers |= CompilerModifiers.AccOverriding; } if (!areReturnTypesEqual(currentMethod, inheritedMethod)) { this.problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod); } else { if (currentMethod.thrownExceptions != NoExceptions) this.checkExceptions(currentMethod, inheritedMethod); if (inheritedMethod.isFinal()) this.problemReporter(currentMethod) .finalMethodCannotBeOverridden(currentMethod, inheritedMethod); if (!this.isAsVisible(currentMethod, inheritedMethod)) this.problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod); if (environment.options.reportDeprecationWhenOverridingDeprecatedMethod && inheritedMethod.isViewedAsDeprecated()) { if (!currentMethod.isViewedAsDeprecated() || environment.options.reportDeprecationInsideDeprecatedCode) { // check against the other inherited methods to see if they hide this inheritedMethod ReferenceBinding declaringClass = inheritedMethod.declaringClass; if (declaringClass.isInterface()) for (int j = length; --j >= 0; ) if (i != j && methods[j].declaringClass.implementsInterface(declaringClass, false)) continue nextMethod; this.problemReporter(currentMethod) .overridesDeprecatedMethod(currentMethod, inheritedMethod); } } } } }
// helper method for findSingleStaticImport() private MethodBinding findStaticMethod(ReferenceBinding currentType, char[] selector) { if (!currentType.canBeSeenBy(this)) return null; do { currentType.initializeForStaticImports(); MethodBinding[] methods = currentType.getMethods(selector); if (methods != Binding.NO_METHODS) { for (int i = methods.length; --i >= 0; ) { MethodBinding method = methods[i]; if (method.isStatic() && method.canBeSeenBy(this.fPackage)) return method; } } } while ((currentType = currentType.superclass()) != null); return null; }
void checkConcreteInheritedMethod(MethodBinding concreteMethod, MethodBinding[] abstractMethods) { // Remember that interfaces can only define public instance methods if (concreteMethod.isStatic()) // Cannot inherit a static method which is specified as an instance method by an interface problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods); if (!concreteMethod.isPublic()) { int index = 0, length = abstractMethods.length; if (concreteMethod.isProtected()) { for (; index < length; index++) if (abstractMethods[index].isPublic()) break; } else if (concreteMethod.isDefault()) { for (; index < length; index++) if (!abstractMethods[index].isDefault()) break; } if (index < length) problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods); } }
/** * Create raw generic method for raw type (double substitution from type vars with raw type * arguments, and erasure of method variables) Only invoked for non-static generic methods of raw * type */ public ParameterizedGenericMethodBinding( MethodBinding originalMethod, RawTypeBinding rawType, LookupEnvironment environment) { TypeVariableBinding[] originalVariables = originalMethod.typeVariables; int length = originalVariables.length; TypeBinding[] rawArguments = new TypeBinding[length]; for (int i = 0; i < length; i++) { rawArguments[i] = environment.convertToRawType( originalVariables[i].erasure(), false /*do not force conversion of enclosing types*/); } this.isRaw = true; this.tagBits = originalMethod.tagBits; this.environment = environment; this.modifiers = originalMethod.modifiers; this.selector = originalMethod.selector; this.declaringClass = rawType == null ? originalMethod.declaringClass : rawType; this.typeVariables = Binding.NO_TYPE_VARIABLES; this.typeArguments = rawArguments; this.originalMethod = originalMethod; boolean ignoreRawTypeSubstitution = rawType == null || originalMethod.isStatic(); this.parameters = Scope.substitute( this, ignoreRawTypeSubstitution ? originalMethod.parameters // no substitution if original was static : Scope.substitute(rawType, originalMethod.parameters)); this.thrownExceptions = Scope.substitute( this, ignoreRawTypeSubstitution ? originalMethod.thrownExceptions // no substitution if original was static : Scope.substitute(rawType, originalMethod.thrownExceptions)); // error case where exception type variable would have been substituted by a non-reference type // (207573) if (this.thrownExceptions == null) this.thrownExceptions = Binding.NO_EXCEPTIONS; this.returnType = Scope.substitute( this, ignoreRawTypeSubstitution ? originalMethod.returnType // no substitution if original was static : Scope.substitute(rawType, originalMethod.returnType)); this.wasInferred = false; // not resulting from method invocation inferrence this.parameterNonNullness = originalMethod.parameterNonNullness; }
/* collect matching methods from one supertype. */ private void collectOverriddenMethods( MethodBinding original, char[] selector, int suggestedParameterLength, ReferenceBinding superType, Set ifcsSeen, List result) { MethodBinding[] ifcMethods = superType.getMethods(selector, suggestedParameterLength); int length = ifcMethods.length; boolean added = false; for (int i = 0; i < length; i++) { MethodBinding currentMethod = ifcMethods[i]; if (currentMethod.isStatic()) continue; if (MethodVerifier.doesMethodOverride(original, currentMethod, this.environment)) { result.add(currentMethod); added = true; // when overriding one or more methods from superType don't traverse to transitive // superTypes } } if (!added) findAllOverriddenMethods( original, selector, suggestedParameterLength, superType, ifcsSeen, result); }
public static boolean checkInvocationArguments( BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding method, Expression[] arguments, TypeBinding[] argumentTypes, boolean argsContainCast, InvocationSite invocationSite) { TypeBinding[] params = method.parameters; int paramLength = params.length; boolean isRawMemberInvocation = !method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && method.hasSubstitutedParameters(); boolean uncheckedBoundCheck = (method.tagBits & TagBits.HasUncheckedTypeArgumentForBoundCheck) != 0; MethodBinding rawOriginalGenericMethod = null; if (!isRawMemberInvocation) { if (method instanceof ParameterizedGenericMethodBinding) { ParameterizedGenericMethodBinding paramMethod = (ParameterizedGenericMethodBinding) method; if (paramMethod.isRaw && method.hasSubstitutedParameters()) { rawOriginalGenericMethod = method.original(); } } } int invocationStatus = INVOCATION_ARGUMENT_OK; if (arguments == null) { if (method.isVarargs()) { TypeBinding parameterType = ((ArrayBinding) params[paramLength - 1]) .elementsType(); // no element was supplied for vararg parameter if (!parameterType.isReifiable()) { scope .problemReporter() .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite); } } } else { if (method.isVarargs()) { // 4 possibilities exist for a call to the vararg method foo(int i, long ... value) : // foo(1), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new long[] {1, 2}) int lastIndex = paramLength - 1; for (int i = 0; i < lastIndex; i++) { TypeBinding originalRawParam = rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i]; invocationStatus |= checkInvocationArgument( scope, arguments[i], params[i], argumentTypes[i], originalRawParam); } int argLength = arguments.length; if (lastIndex < argLength) { // vararg argument was provided TypeBinding parameterType = params[lastIndex]; TypeBinding originalRawParam = null; if (paramLength != argLength || parameterType.dimensions() != argumentTypes[lastIndex].dimensions()) { parameterType = ((ArrayBinding) parameterType) .elementsType(); // single element was provided for vararg parameter if (!parameterType.isReifiable()) { scope .problemReporter() .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite); } originalRawParam = rawOriginalGenericMethod == null ? null : ((ArrayBinding) rawOriginalGenericMethod.parameters[lastIndex]) .elementsType(); } for (int i = lastIndex; i < argLength; i++) { invocationStatus |= checkInvocationArgument( scope, arguments[i], parameterType, argumentTypes[i], originalRawParam); } } if (paramLength == argLength) { // 70056 int varargsIndex = paramLength - 1; ArrayBinding varargsType = (ArrayBinding) params[varargsIndex]; TypeBinding lastArgType = argumentTypes[varargsIndex]; int dimensions; if (lastArgType == TypeBinding.NULL) { if (!(varargsType.leafComponentType().isBaseType() && varargsType.dimensions() == 1)) scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } else if (varargsType.dimensions <= (dimensions = lastArgType.dimensions())) { if (lastArgType.leafComponentType().isBaseType()) { dimensions--; } if (varargsType.dimensions < dimensions) { scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } else if (varargsType.dimensions == dimensions && lastArgType != varargsType && lastArgType.leafComponentType().erasure() != varargsType.leafComponentType.erasure() && lastArgType.isCompatibleWith(varargsType.elementsType()) && lastArgType.isCompatibleWith(varargsType)) { scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } } } } else { for (int i = 0; i < paramLength; i++) { TypeBinding originalRawParam = rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i]; invocationStatus |= checkInvocationArgument( scope, arguments[i], params[i], argumentTypes[i], originalRawParam); } } if (argsContainCast) { CastExpression.checkNeedForArgumentCasts( scope, receiver, receiverType, method, arguments, argumentTypes, invocationSite); } } if ((invocationStatus & INVOCATION_ARGUMENT_WILDCARD) != 0) { scope .problemReporter() .wildcardInvocation((ASTNode) invocationSite, receiverType, method, argumentTypes); } else if (!method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && method.hasSubstitutedParameters()) { scope.problemReporter().unsafeRawInvocation((ASTNode) invocationSite, method); } else if (rawOriginalGenericMethod != null || uncheckedBoundCheck || ((invocationStatus & INVOCATION_ARGUMENT_UNCHECKED) != 0 && method instanceof ParameterizedGenericMethodBinding /*&& method.returnType != scope.environment().convertToRawType(method.returnType.erasure(), true)*/ )) { scope .problemReporter() .unsafeRawGenericMethodInvocation((ASTNode) invocationSite, method, argumentTypes); return true; } return false; }
void checkInheritedMethods(MethodBinding[] methods, int length) { MethodBinding first = methods[0]; int index = length; while (--index > 0 && areReturnTypesEqual(first, methods[index])) { /*empty*/ } if (index > 0) { // All inherited methods do NOT have the same vmSignature this.problemReporter() .inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); return; } MethodBinding concreteMethod = null; if (!type.isInterface()) { // ignore concrete methods for interfaces for (int i = length; --i >= 0; ) { // Remember that only one of the methods can be non-abstract if (!methods[i].isAbstract()) { concreteMethod = methods[i]; break; } } } if (concreteMethod == null) { if (this.type.isClass() && !this.type.isAbstract()) { for (int i = length; --i >= 0; ) { if (mustImplementAbstractMethod(methods[i])) { TypeDeclaration typeDeclaration = this.type.scope.referenceContext; if (typeDeclaration != null) { MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(methods[0]); missingAbstractMethod .scope .problemReporter() .abstractMethodMustBeImplemented(this.type, methods[0]); } else { this.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]); } return; } } } return; } MethodBinding[] abstractMethods = new MethodBinding[length - 1]; index = 0; for (int i = length; --i >= 0; ) if (methods[i] != concreteMethod) abstractMethods[index++] = methods[i]; // Remember that interfaces can only define public instance methods if (concreteMethod.isStatic()) // Cannot inherit a static method which is specified as an instance method by an interface this.problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods); if (!concreteMethod.isPublic()) // Cannot reduce visibility of a public method specified by an interface this.problemReporter() .inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods); if (concreteMethod.thrownExceptions != NoExceptions) for (int i = abstractMethods.length; --i >= 0; ) this.checkExceptions(concreteMethod, abstractMethods[i]); }
/** * Check and fill in implicit annotations from overridden methods and from default. Precondition: * caller has checked whether annotation-based null analysis is enabled. */ public void checkImplicitNullAnnotations( MethodBinding currentMethod, AbstractMethodDeclaration srcMethod, boolean complain, Scope scope) { // check inherited nullness from superclass and superInterfaces try { ReferenceBinding currentType = currentMethod.declaringClass; if (currentType.id == TypeIds.T_JavaLangObject) { return; } boolean usesTypeAnnotations = scope.environment().usesNullTypeAnnotations(); boolean needToApplyReturnNonNullDefault = currentMethod.hasNonNullDefaultFor( Binding.DefaultLocationReturnType, usesTypeAnnotations); boolean needToApplyParameterNonNullDefault = currentMethod.hasNonNullDefaultFor(Binding.DefaultLocationParameter, usesTypeAnnotations); boolean needToApplyNonNullDefault = needToApplyReturnNonNullDefault | needToApplyParameterNonNullDefault; // compatibility & inheritance do not consider constructors / static methods: boolean isInstanceMethod = !currentMethod.isConstructor() && !currentMethod.isStatic(); complain &= isInstanceMethod; if (!needToApplyNonNullDefault && !complain && !(this.inheritNullAnnotations && isInstanceMethod)) { return; // short cut, no work to be done } if (isInstanceMethod) { List superMethodList = new ArrayList(); // need super types connected: if (currentType instanceof SourceTypeBinding && !currentType.isHierarchyConnected() && !currentType.isAnonymousType()) { ((SourceTypeBinding) currentType).scope.connectTypeHierarchy(); } int paramLen = currentMethod.parameters.length; findAllOverriddenMethods( currentMethod.original(), currentMethod.selector, paramLen, currentType, new HashSet(), superMethodList); // prepare interim storage for nullness info so we don't pollute currentMethod before we // know its conflict-free: InheritedNonNullnessInfo[] inheritedNonNullnessInfos = new InheritedNonNullnessInfo[paramLen + 1]; // index 0 is for the return type for (int i = 0; i < paramLen + 1; i++) inheritedNonNullnessInfos[i] = new InheritedNonNullnessInfo(); int length = superMethodList.size(); for (int i = length; --i >= 0; ) { MethodBinding currentSuper = (MethodBinding) superMethodList.get(i); if ((currentSuper.tagBits & TagBits.IsNullnessKnown) == 0) { // recurse to prepare currentSuper checkImplicitNullAnnotations( currentSuper, null, false, scope); // TODO (stephan) complain=true if currentSuper is source method?? } checkNullSpecInheritance( currentMethod, srcMethod, needToApplyReturnNonNullDefault, needToApplyParameterNonNullDefault, complain, currentSuper, null, scope, inheritedNonNullnessInfos); needToApplyNonNullDefault = false; } // transfer collected information into currentMethod: InheritedNonNullnessInfo info = inheritedNonNullnessInfos[0]; if (!info.complained) { long tagBits = 0; if (info.inheritedNonNullness == Boolean.TRUE) { tagBits = TagBits.AnnotationNonNull; } else if (info.inheritedNonNullness == Boolean.FALSE) { tagBits = TagBits.AnnotationNullable; } if (tagBits != 0) { if (!usesTypeAnnotations) { currentMethod.tagBits |= tagBits; } else { if (!currentMethod.returnType.isBaseType()) { LookupEnvironment env = scope.environment(); currentMethod.returnType = env.createAnnotatedType( currentMethod.returnType, env.nullAnnotationsFromTagBits(tagBits)); } } } } for (int i = 0; i < paramLen; i++) { info = inheritedNonNullnessInfos[i + 1]; if (!info.complained && info.inheritedNonNullness != null) { Argument currentArg = srcMethod == null ? null : srcMethod.arguments[i]; if (!usesTypeAnnotations) recordArgNonNullness( currentMethod, paramLen, i, currentArg, info.inheritedNonNullness); else recordArgNonNullness18( currentMethod, i, currentArg, info.inheritedNonNullness, scope.environment()); } } } if (needToApplyNonNullDefault) { if (!usesTypeAnnotations) currentMethod.fillInDefaultNonNullness(srcMethod); else currentMethod.fillInDefaultNonNullness18(srcMethod, scope.environment()); } } finally { currentMethod.tagBits |= TagBits.IsNullnessKnown; } }