diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java index 76a6b1841a2..41d8f3518ca 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -4485,7 +4485,7 @@ public int generateMethodInfoAttributes(MethodBinding methodBinding) { } } if ((methodBinding.tagBits & TagBits.HasMissingType) != 0) { - this.missingTypes = methodBinding.collectMissingTypes(this.missingTypes); + this.missingTypes = methodBinding.collectMissingTypes(this.missingTypes, true); } return attributesNumber; } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java index ac94a2af8eb..4822ee81283 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -505,7 +505,7 @@ public TypeBinding resolveType(BlockScope scope) { scope.problemReporter().invalidConstructor(this, this.binding); return this.resolvedType; } - if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { + if ((this.binding.tagBits & TagBits.HasMissingType) != 0 && isMissingTypeRelevant()) { scope.problemReporter().missingTypeInConstructor(this, this.binding); } if (isMethodUseDeprecated(this.binding, scope, true, this)) { @@ -539,6 +539,20 @@ public TypeBinding resolveType(BlockScope scope) { return this.resolvedType; } +protected boolean isMissingTypeRelevant() { + if (this.binding != null && this.binding.isVarargs()) { + if (this.arguments.length < this.binding.parameters.length) { + // are all but the irrelevant varargs type present? + for (int i = 0; i < this.arguments.length; i++) { + if ((this.binding.parameters[i].tagBits & TagBits.HasMissingType) != 0) + return true; // this one *is* relevant - actually this case is already detected during findConstructorBinding() + } + return false; + } + } + return true; +} + protected void checkPreConstructorContext(BlockScope scope) { if (this.inPreConstructorContext && this.type != null && this.type.resolvedType instanceof ReferenceBinding currentType diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index 9bc7180ee50..ce2c97d35a9 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -995,7 +995,7 @@ public TypeBinding resolveType(BlockScope scope) { this.binding = scope.environment().updatePolymorphicMethodReturnType((PolymorphicMethodBinding) this.binding, TypeBinding.VOID); } } - if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { + if ((this.binding.tagBits & TagBits.HasMissingType) != 0 && isMissingTypeRelevant()) { scope.problemReporter().missingTypeInMethod(this, this.binding); } if (!this.binding.isStatic()) { @@ -1112,6 +1112,25 @@ protected boolean isUnnecessaryReceiverCast(BlockScope scope, TypeBinding uncast || MethodVerifier.doesMethodOverride(otherMethod, this.binding, scope.environment()); } +protected boolean isMissingTypeRelevant() { + if ((this.bits & ASTNode.InsideExpressionStatement) != 0) { + if (this.binding.collectMissingTypes(null, false) == null) + return false; // only irrelevant return type is missing + } + if ((this.binding.returnType.tagBits & TagBits.HasMissingType) == 0 + && this.binding.isVarargs()) { + if (this.arguments.length < this.binding.parameters.length) { + // are all but the irrelevant varargs type present? + for (int i = 0; i < this.arguments.length; i++) { + if ((this.binding.parameters[i].tagBits & TagBits.HasMissingType) != 0) + return true; // this one *is* relevant - actually this case is already detected during findMethodBinding() + } + return false; + } + } + return true; +} + protected TypeBinding handleNullnessCodePatterns(BlockScope scope, TypeBinding returnType) { // j.u.s.Stream.filter() may modify nullness of stream elements: if (this.binding.isWellknownMethod(TypeConstants.JAVA_UTIL_STREAM__STREAM, TypeConstants.FILTER) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java index 2aae1b181d1..0a32307c3d6 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -586,7 +586,7 @@ private TypeBinding resolveTypeForQualifiedAllocationExpression(BlockScope scope scope.problemReporter().invalidConstructor(this, constructorBinding); return this.resolvedType; } - if ((constructorBinding.tagBits & TagBits.HasMissingType) != 0) { + if ((constructorBinding.tagBits & TagBits.HasMissingType) != 0 && isMissingTypeRelevant()) { scope.problemReporter().missingTypeInConstructor(this, constructorBinding); } if (this.enclosingInstance != null) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java index d2c917ee2c7..43d1afd2b5f 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -1951,33 +1951,39 @@ MethodBinding resolveTypesFor(MethodBinding method) { if ((method.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0) return method; + boolean tolerateSave = this.environment.mayTolerateMissingType; + this.environment.mayTolerateMissingType |= this.environment.globalOptions.complianceLevel >= ClassFileConstants.JDK1_8; // tolerance only implemented for 1.8+ + try { - if (!method.isConstructor()) { - TypeBinding resolvedType = resolveType(method.returnType, this.environment, true /* raw conversion */); - method.returnType = resolvedType; - if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) { - method.tagBits |= TagBits.HasMissingType; + if (!method.isConstructor()) { + TypeBinding resolvedType = resolveType(method.returnType, this.environment, true /* raw conversion */); + method.returnType = resolvedType; + if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) { + method.tagBits |= TagBits.HasMissingType; + } } - } - for (int i = method.parameters.length; --i >= 0;) { - TypeBinding resolvedType = resolveType(method.parameters[i], this.environment, true /* raw conversion */); - method.parameters[i] = resolvedType; - if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) { - method.tagBits |= TagBits.HasMissingType; + for (int i = method.parameters.length; --i >= 0;) { + TypeBinding resolvedType = resolveType(method.parameters[i], this.environment, true /* raw conversion */); + method.parameters[i] = resolvedType; + if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) { + method.tagBits |= TagBits.HasMissingType; + } } - } - for (int i = method.thrownExceptions.length; --i >= 0;) { - ReferenceBinding resolvedType = (ReferenceBinding) resolveType(method.thrownExceptions[i], this.environment, true /* raw conversion */); - method.thrownExceptions[i] = resolvedType; - if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) { - method.tagBits |= TagBits.HasMissingType; + for (int i = method.thrownExceptions.length; --i >= 0;) { + ReferenceBinding resolvedType = (ReferenceBinding) resolveType(method.thrownExceptions[i], this.environment, true /* raw conversion */); + method.thrownExceptions[i] = resolvedType; + if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) { + method.tagBits |= TagBits.HasMissingType; + } } + for (int i = method.typeVariables.length; --i >= 0;) { + method.typeVariables[i].resolve(); + } + method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved; + return method; + } finally { + this.environment.mayTolerateMissingType = tolerateSave; } - for (int i = method.typeVariables.length; --i >= 0;) { - method.typeVariables[i].resolve(); - } - method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved; - return method; } @Override AnnotationBinding[] retrieveAnnotations(Binding binding) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java index 9dea4749782..c7723579ac1 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -63,13 +63,10 @@ public CaptureBinding(WildcardBinding wildcard, ReferenceBinding sourceType, int this.environment.typeSystem.cacheDerivedType(this, unannotated, this); // propagate from wildcard to capture - use super version, because our own method propagates type annotations in the opposite direction: super.setTypeAnnotations(wildcard.getTypeAnnotations(), wildcard.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); - if (wildcard.hasNullTypeAnnotations()) - this.tagBits |= TagBits.HasNullTypeAnnotation; + this.tagBits |= wildcard.tagBits & (TagBits.HasNullTypeAnnotation|TagBits.HasMissingType); } else { computeId(this.environment); - if(wildcard.hasNullTypeAnnotations()) { - this.tagBits |= (wildcard.tagBits & TagBits.AnnotationNullMASK) | TagBits.HasNullTypeAnnotation; - } + this.tagBits |= wildcard.tagBits & (TagBits.AnnotationNullMASK|TagBits.HasNullTypeAnnotation|TagBits.HasMissingType); } } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java index 37cb04ee363..d7d0c3e3272 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java @@ -44,6 +44,10 @@ public ConstraintExceptionFormula(FunctionalExpression left, TypeBinding type) { @Override public Object reduce(InferenceContext18 inferenceContext) { + if ((this.right.tagBits & TagBits.HasMissingType) != 0) { + inferenceContext.hasIgnoredMissingType = true; + return TRUE; + } // JLS 18.2.5 Scope scope = inferenceContext.scope; if (!this.right.isFunctionalInterface(scope)) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java index 29094d54ba7..2bce82c25e1 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java @@ -59,6 +59,10 @@ class ConstraintExpressionFormula extends ConstraintFormula { @Override public Object reduce(InferenceContext18 inferenceContext) throws InferenceFailureException { + if ((this.right.tagBits & TagBits.HasMissingType) != 0) { + inferenceContext.hasIgnoredMissingType = true; + return TRUE; + } if (this.relation == POTENTIALLY_COMPATIBLE) { /* 15.12.2.1: ... The definition of potential applicability goes beyond a basic arity check to also take into account the presence and "shape" of functional interface diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java index 3149d02f0d1..7b7346deacf 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java @@ -63,6 +63,10 @@ private ConstraintTypeFormula(TypeBinding exprType, TypeBinding right, int relat // return: ReductionResult or ConstraintFormula[] @Override public Object reduce(InferenceContext18 inferenceContext) { + if ((this.left.tagBits & TagBits.HasMissingType) != 0 || (this.right.tagBits & TagBits.HasMissingType) != 0) { + inferenceContext.hasIgnoredMissingType = true; + return TRUE; + } switch (this.relation) { case COMPATIBLE: // 18.2.2: diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java index 8eef8e72500..96595c5f56b 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java @@ -180,6 +180,8 @@ public class InferenceContext18 { // the following two flags control to what degree we continue with incomplete information: private boolean isInexactVarargsInference = false; boolean prematureOverloadResolution = false; + // during reduction we ignore missing types but record that fact here: + boolean hasIgnoredMissingType; public static boolean isSameSite(InvocationSite site1, InvocationSite site2) { if (site1 == site2) @@ -754,6 +756,7 @@ private boolean addConstraintsToC_OneExpr(Expression expri, Set collectMissingTypes(List missingTypes) { +public List collectMissingTypes(List missingTypes, boolean considerReturnType) { if ((this.tagBits & TagBits.HasMissingType) != 0) { - missingTypes = this.returnType.collectMissingTypes(missingTypes); + if (considerReturnType) { + missingTypes = this.returnType.collectMissingTypes(missingTypes); + } for (TypeBinding parameter : this.parameters) { missingTypes = parameter.collectMissingTypes(missingTypes); } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java index 6f4940b978d..83f5fe5f450 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java @@ -135,7 +135,7 @@ public static MethodBinding computeCompatibleMethod(MethodBinding originalMethod ParameterizedGenericMethodBinding substitute = inferFromArgumentTypes(scope, originalMethod, arguments, parameters, inferenceContext); if (substitute != null && substitute.returnType.isCompatibleWith(expectedType)) { // Do not use the new solution if it results in incompatibilities in parameter types - if ((scope.parameterCompatibilityLevel(substitute, arguments, false)) > Scope.NOT_COMPATIBLE) { + if ((scope.parameterCompatibilityLevel(substitute, arguments, false)) > Scope.NOT_COMPATIBLE) { // don't worry about COMPATIBLE_IGNORING_MISSING_TYPE in 1.7 context methodSubstitute = substitute; } else { inferenceContext = oldContext; @@ -307,6 +307,9 @@ public static MethodBinding computeCompatibleMethod18(MethodBinding originalMeth if (invocationSite instanceof Invocation && allArgumentsAreProper && (expectedType == null || expectedType.isProperType(true))) infCtx18.forwardResults(result, (Invocation) invocationSite, methodSubstitute, expectedType); try { + if (infCtx18.hasIgnoredMissingType) { + return new ProblemMethodBinding(originalMethod, originalMethod.selector, parameters, ProblemReasons.MissingTypeInSignature); + } if (hasReturnProblem) { // illegally working from the provisional result? MethodBinding problemMethod = infCtx18.getReturnProblemMethodIfNeeded(expectedType, methodSubstitute); if (problemMethod instanceof ProblemMethodBinding) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java index 0e392932587..b4576ac2880 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java @@ -66,7 +66,7 @@ public ParameterizedMethodBinding(final ParameterizedTypeBinding parameterizedDe for (int i = 0; i < length; i++) { // copy original type variable to relocate TypeVariableBinding originalVariable = originalVariables[i]; substitutedVariables[i] = new TypeVariableBinding(originalVariable.sourceName, this, originalVariable.rank, parameterizedDeclaringClass.environment); - substitutedVariables[i].tagBits |= (originalVariable.tagBits & (TagBits.AnnotationNullMASK|TagBits.HasNullTypeAnnotation)); + substitutedVariables[i].tagBits |= (originalVariable.tagBits & (TagBits.AnnotationNullMASK|TagBits.HasNullTypeAnnotation|TagBits.HasMissingType)); } this.typeVariables = substitutedVariables; @@ -209,7 +209,7 @@ public ParameterizedMethodBinding(final ReferenceBinding declaringClass, MethodB this, originalVariable.rank, environment); - substitutedVariables[i].tagBits |= (originalVariable.tagBits & (TagBits.AnnotationNullMASK|TagBits.HasNullTypeAnnotation)); + substitutedVariables[i].tagBits |= (originalVariable.tagBits & (TagBits.AnnotationNullMASK|TagBits.HasNullTypeAnnotation|TagBits.HasMissingType)); } this.typeVariables = substitutedVariables; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java index 5c550bf6247..fff08aa31cb 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java @@ -52,4 +52,5 @@ public interface ProblemReasons { final int InterfaceMethodInvocationNotBelow18 = 29; final int NotAccessible = 30; // JLS 6.6.1 - module aspects final int ErrorAlreadyReported = 31; + final int MissingTypeInSignature = 32; } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java index ce12830d0be..244c093b1e9 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java @@ -108,6 +108,7 @@ public char[] readableName() { public final static int COMPATIBLE = 0; public final static int AUTOBOX_COMPATIBLE = 1; public final static int VARARGS_COMPATIBLE = 2; + public final static int COMPATIBLE_IGNORING_MISSING_TYPE = -2; /* Type Compatibilities */ public static final int EQUAL_OR_MORE_SPECIFIC = -1; @@ -871,13 +872,16 @@ protected final MethodBinding computeCompatibleMethod(MethodBinding method, Type } - if ((parameterCompatibilityLevel(method, arguments, tiebreakingVarargsMethods)) > NOT_COMPATIBLE) { + int level = parameterCompatibilityLevel(method, arguments, tiebreakingVarargsMethods); + if (level > NOT_COMPATIBLE) { if (method.hasPolymorphicSignature(this)) { // generate polymorphic method and set polymorphic tagbits as well method.tagBits |= TagBits.AnnotationPolymorphicSignature; return this.environment().createPolymorphicMethod(method, arguments, this); } return method; + } else if (level == COMPATIBLE_IGNORING_MISSING_TYPE) { + return new ProblemMethodBinding(method, method.selector, method.parameters, ProblemReasons.MissingTypeInSignature); } // if method is generic and type arguments have been supplied, only then answer a problem // of ParameterizedMethodTypeMismatch, else a non-generic method was invoked using type arguments @@ -978,7 +982,7 @@ protected boolean connectTypeVariables(TypeParameter[] typeParameters, boolean c } else { typeVariable.setSuperInterfaces(new ReferenceBinding[] {superRefType}); } - typeVariable.tagBits |= superType.tagBits & TagBits.ContainsNestedTypeReferences; + typeVariable.tagBits |= superType.tagBits & (TagBits.ContainsNestedTypeReferences | TagBits.HasMissingType); typeVariable.setFirstBound(superRefType); // first bound used to compute erasure } } @@ -993,7 +997,7 @@ protected boolean connectTypeVariables(TypeParameter[] typeParameters, boolean c typeVariable.tagBits |= TagBits.HierarchyHasProblems; continue nextBound; } else { - typeVariable.tagBits |= superType.tagBits & TagBits.ContainsNestedTypeReferences; + typeVariable.tagBits |= superType.tagBits & (TagBits.ContainsNestedTypeReferences | TagBits.HasMissingType); boolean didAlreadyComplain = !typeRef.resolvedType.isValidBinding(); if (isFirstBoundTypeVariable && j == 0) { problemReporter().noAdditionalBoundAfterTypeVariable(typeRef); @@ -1764,6 +1768,8 @@ public MethodBinding findMethod0(ReferenceBinding receiverType, char[] selector, if (candidatesCount == 0) candidates = new MethodBinding[foundSize]; candidates[candidatesCount++] = compatibleMethod; + } else if (compatibleMethod.problemId() == ProblemReasons.MissingTypeInSignature) { + return compatibleMethod; // use this method for error message to give a hint about the missing type } else if (problemMethod == null) { problemMethod = compatibleMethod; } @@ -2495,6 +2501,8 @@ public MethodBinding getConstructor0(ReferenceBinding receiverType, TypeBinding[ if (compatibleMethod != null) { if (compatibleMethod.isValidBinding()) compatible[compatibleIndex++] = compatibleMethod; + else if (compatibleMethod.problemId() == ProblemReasons.MissingTypeInSignature) + return compatibleMethod; // use this method for error message to give a hint about the missing type else if (problemMethod == null) problemMethod = compatibleMethod; } @@ -4648,6 +4656,10 @@ protected final MethodBinding mostSpecificMethodBinding(MethodBinding[] visible, int compatibleCount = 0; for (int i = 0; i < visibleSize; i++) if ((compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes, invocationSite)) != NOT_COMPATIBLE) { + if (compatibilityLevels[i] == COMPATIBLE_IGNORING_MISSING_TYPE) { + // cannot conclusively select any candidate, use the method with missing types in the error message + return new ProblemMethodBinding(visible[i], visible[i].selector, visible[i].parameters, ProblemReasons.Ambiguous); + } if (i != compatibleCount) { visible[compatibleCount] = visible[i]; compatibilityLevels[compatibleCount] = compatibilityLevels[i]; @@ -5144,13 +5156,17 @@ public int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] argum TypeBinding param = ((ArrayBinding) parameters[lastIndex]).elementsType(); for (int i = lastIndex; i < argLength; i++) { TypeBinding arg = (tiebreakingVarargsMethods && (i == (argLength - 1))) ? ((ArrayBinding)arguments[i]).elementsType() : arguments[i]; - if (TypeBinding.notEquals(param, arg) && parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method) == NOT_COMPATIBLE) - return NOT_COMPATIBLE; + if (TypeBinding.notEquals(param, arg)) { + level = parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method); + if (level == NOT_COMPATIBLE) + return NOT_COMPATIBLE; + } } } else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo(); return NOT_COMPATIBLE; } - level = VARARGS_COMPATIBLE; // varargs support needed + if (level != COMPATIBLE_IGNORING_MISSING_TYPE) // preserve any COMPATIBLE_IGNORING_MISSING_TYPE + level = VARARGS_COMPATIBLE; // varargs support needed } } else if (paramLength != argLength) { return NOT_COMPATIBLE; @@ -5161,10 +5177,13 @@ public int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] argum TypeBinding arg = (tiebreakingVarargsMethods && (i == (argLength - 1))) ? ((ArrayBinding)arguments[i]).elementsType() : arguments[i]; if (TypeBinding.notEquals(arg,param)) { int newLevel = parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method); - if (newLevel == NOT_COMPATIBLE) + if (newLevel == NOT_COMPATIBLE) { return NOT_COMPATIBLE; - if (newLevel > level) + } else if (newLevel == COMPATIBLE_IGNORING_MISSING_TYPE) { level = newLevel; + } else if (newLevel > level && level != COMPATIBLE_IGNORING_MISSING_TYPE) { + level = newLevel; + } } } return level; @@ -5193,6 +5212,8 @@ private int parameterCompatibilityLevel(TypeBinding arg, TypeBinding param, Look // only called if env.options.sourceLevel >= ClassFileConstants.JDK1_5 if (arg == null || param == null) return NOT_COMPATIBLE; + if ((param.tagBits & TagBits.HasMissingType) != 0) + return COMPATIBLE_IGNORING_MISSING_TYPE; if (arg instanceof PolyTypeBinding && !((PolyTypeBinding) arg).expression.isPertinentToApplicability(param, method)) { if (arg.isPotentiallyCompatibleWith(param, this)) return COMPATIBLE; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java index f7ef22e0f74..df64ebf3a43 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -43,6 +43,7 @@ package org.eclipse.jdt.internal.compiler.lookup; import java.util.Arrays; +import java.util.List; import java.util.Set; import java.util.function.Consumer; @@ -344,6 +345,25 @@ public int boundsCount() { public boolean canBeInstantiated() { return false; } + + @Override + public List collectMissingTypes(List missingTypes) { + if ((this.tagBits & TagBits.HasMissingType) != 0 && !this.inRecursiveFunction) { + this.inRecursiveFunction = true; + try { + if (this.superclass != null) { + missingTypes = this.superclass.collectMissingTypes(missingTypes); + } + for (ReferenceBinding superIfc : this.superInterfaces) { + missingTypes = superIfc.collectMissingTypes(missingTypes); + } + } finally { + this.inRecursiveFunction = false; + } + } + return missingTypes; + } + /** * Collect the substitutes into a map for certain type variables inside the receiver type * e.g. {@code Collection.collectSubstitutes(Collection>, Map)} will populate Map with: {@code T --> List} @@ -805,7 +825,7 @@ ReferenceBinding resolve() { TypeBinding oldSuperclass = this.superclass, oldFirstInterface = null; if (this.superclass != null) { ReferenceBinding resolveType = (ReferenceBinding) BinaryTypeBinding.resolveType(this.superclass, this.environment, true /* raw conversion */); - this.tagBits |= resolveType.tagBits & TagBits.ContainsNestedTypeReferences; + this.tagBits |= resolveType.tagBits & (TagBits.ContainsNestedTypeReferences | TagBits.HasMissingType); long superNullTagBits = resolveType.tagBits & TagBits.AnnotationNullMASK; if (superNullTagBits != 0L) { if (nullTagBits == 0L) { @@ -824,7 +844,7 @@ ReferenceBinding resolve() { oldFirstInterface = interfaces[0]; for (int i = length; --i >= 0;) { ReferenceBinding resolveType = (ReferenceBinding) BinaryTypeBinding.resolveType(interfaces[i], this.environment, true /* raw conversion */); - this.tagBits |= resolveType.tagBits & TagBits.ContainsNestedTypeReferences; + this.tagBits |= resolveType.tagBits & (TagBits.ContainsNestedTypeReferences | TagBits.HasMissingType); long superNullTagBits = resolveType.tagBits & TagBits.AnnotationNullMASK; if (superNullTagBits != 0L) { if (nullTagBits == 0L) { @@ -1074,8 +1094,8 @@ public TypeBinding setFirstBound(TypeBinding firstBound) { annotatedType.firstBound = firstBound; } } - if (firstBound != null && firstBound.hasNullTypeAnnotations()) - this.tagBits |= TagBits.HasNullTypeAnnotation; + if (firstBound != null) + this.tagBits |= firstBound.tagBits & (TagBits.HasNullTypeAnnotation|TagBits.HasMissingType); return firstBound; } /* An annotated type variable use differs from its declaration exactly in its annotations and in nothing else. diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index 84265a3f95c..cae43ed23bb 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -4164,6 +4164,10 @@ public void invalidConstructor(Statement statement, MethodBinding targetConstruc problemConstructor = (ProblemMethodBinding) targetConstructor; contradictoryNullAnnotationsInferred(problemConstructor.closestMatch, statement); return; + case ProblemReasons.MissingTypeInSignature: + problemConstructor = (ProblemMethodBinding) targetConstructor; + missingTypeInConstructor(statement, problemConstructor.closestMatch); + return; case ProblemReasons.NoError : // 0 default : needImplementation(statement); // want to fail to see why we were here... @@ -4785,6 +4789,10 @@ public void invalidMethod(MessageSend messageSend, MethodBinding method, Scope s problemMethod = (ProblemMethodBinding) method; contradictoryNullAnnotationsInferred(problemMethod.closestMatch, messageSend); return; + case ProblemReasons.MissingTypeInSignature: + problemMethod = (ProblemMethodBinding) method; + missingTypeInMethod(messageSend, problemMethod.closestMatch); + return; case ProblemReasons.NoError : // 0 default : needImplementation(messageSend); // want to fail to see why we were here... @@ -6943,7 +6951,7 @@ public void missingSynchronizedOnInheritedMethod(MethodBinding currentMethod, Me currentMethod.sourceEnd()); } public void missingTypeInConstructor(ASTNode location, MethodBinding constructor) { - List missingTypes = constructor.collectMissingTypes(null); + List missingTypes = constructor.collectMissingTypes(null, true); if (missingTypes == null) { System.err.println("The constructor " + constructor + " is wrongly tagged as containing missing types"); //$NON-NLS-1$ //$NON-NLS-2$ return; @@ -6976,7 +6984,7 @@ public void missingTypeInConstructor(ASTNode location, MethodBinding constructor public void missingTypeInLambda(LambdaExpression lambda, MethodBinding method) { int nameSourceStart = lambda.sourceStart(); int nameSourceEnd = lambda.diagnosticsSourceEnd(); - List missingTypes = method.collectMissingTypes(null); + List missingTypes = method.collectMissingTypes(null, true); if (missingTypes == null) { System.err.println("The lambda expression " + method + " is wrongly tagged as containing missing types"); //$NON-NLS-1$ //$NON-NLS-2$ return; @@ -7003,7 +7011,7 @@ public void missingTypeInMethod(ASTNode astNode, MethodBinding method) { nameSourceStart = astNode.sourceStart; nameSourceEnd = astNode.sourceEnd; } - List missingTypes = method.collectMissingTypes(null); + List missingTypes = method.collectMissingTypes(null, true); if (missingTypes == null) { System.err.println("The method " + method + " is wrongly tagged as containing missing types"); //$NON-NLS-1$ //$NON-NLS-2$ return; diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/DependencyTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/DependencyTests.java index 8c5354ee834..07de7950983 100644 --- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/DependencyTests.java +++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/DependencyTests.java @@ -25,6 +25,9 @@ @SuppressWarnings({"rawtypes", "unchecked"}) public class DependencyTests extends BuilderTests { + static { +// TESTS_NAMES = new String[] {"testMissingClassFile"}; + } public DependencyTests(String name) { super(name); } @@ -857,7 +860,7 @@ public void testMethodVisibility() throws JavaModelException { } public void testMissingClassFile() throws JavaModelException { - IPath project1Path = env.addProject("Project1"); //$NON-NLS-1$ + IPath project1Path = env.addProject("Project1", "1.8"); // tolerance of missing types not fully implemented below 1.8 env.addExternalJars(project1Path, Util.getJavaClassLibs()); // remove old package fragment root so that names don't collide @@ -871,7 +874,7 @@ public void testMissingClassFile() throws JavaModelException { "public class MissingClass {}" //$NON-NLS-1$ ); - IPath project2Path = env.addProject("Project2"); //$NON-NLS-1$ + IPath project2Path = env.addProject("Project2", "1.8"); // tolerance of missing types not fully implemented below 1.8 env.addExternalJars(project2Path, Util.getJavaClassLibs()); env.addRequiredProject(project2Path, project1Path); @@ -890,7 +893,7 @@ public void testMissingClassFile() throws JavaModelException { "}\n" //$NON-NLS-1$ ); - IPath project3Path = env.addProject("Project3"); //$NON-NLS-1$ + IPath project3Path = env.addProject("Project3", "1.8"); // tolerance of missing types not fully implemented below 1.8 env.addExternalJars(project3Path, Util.getJavaClassLibs()); env.addRequiredProject(project3Path, project2Path); // missing required Project1 so MissingClass cannot be found @@ -906,19 +909,20 @@ public void testMissingClassFile() throws JavaModelException { "import p2.A;\n" + "public class B {\n"+ //$NON-NLS-1$ " public static void main(String[] args) {\n" + //$NON-NLS-1$ - " new A().foo(new String());\n" + //$NON-NLS-1$ + " new A().foo(new B());\n" + // applicability test would like to see MissingClass + " new A().foo(new String());\n" + // exact match to fully resolved method " }\n" + //$NON-NLS-1$ "}\n" //$NON-NLS-1$ ); fullBuild(); - expectingOnlyProblemsFor(new IPath[] {project3Path, bPath}); - expectingSpecificProblemFor(project3Path, new Problem("Project3", "The project was not built since its build path is incomplete. Cannot find the class file for p1.MissingClass. Fix the build path then try building this project", project3Path, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$ - expectingSpecificProblemFor(bPath, new Problem("B", "The type p1.MissingClass cannot be resolved. It is indirectly referenced from required type p2.A", bPath, 86, 111, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlyProblemsFor(new IPath[] {bPath}); + expectingSpecificProblemFor(bPath, new Problem("B", "The method foo(MissingClass) from the type A refers to the missing type MissingClass", bPath, 94, 97, CategorizedProblem.CAT_MEMBER, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$ env.addClass(root2, "p2", "A", //$NON-NLS-1$ //$NON-NLS-2$ "package p2;\n"+ //$NON-NLS-1$ "public class A {\n"+ //$NON-NLS-1$ + " public void foo(Object data) {}\n"+ //$NON-NLS-1$ " public void foo(String data) {}\n"+ //$NON-NLS-1$ "}\n" //$NON-NLS-1$ ); diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java index 8babfccacaf..2e8d7c58d7a 100644 --- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java +++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java @@ -33,6 +33,10 @@ @SuppressWarnings({"rawtypes", "unchecked"}) public class MultiProjectTests extends BuilderTests { + static { +// TESTS_NAMES = new String[] { "test461074_error_1_8" }; + } + public MultiProjectTests(String name) { super(name); } @@ -2221,4 +2225,76 @@ public void test461074_error() throws JavaModelException { env.removeProject(p2); env.removeProject(p3); } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=461074, "indirectly referenced from required .class files" error for unreachable reference of type in overriding method declaration in a library on classpath +public void test461074_error_1_8() throws JavaModelException { + // as of https://github.com/eclipse-jdt/eclipse.jdt.core/pull/2543 and at 1.8+ we tolerate the missing type + //---------------------------- + // Project1 + //---------------------------- + IPath p1 = env.addProject("SampleMissing", "1.8"); //$NON-NLS-1$ + env.addExternalJars(p1, Util.getJavaClassLibs()); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p1, ""); //$NON-NLS-1$ + IPath root1 = env.addPackageFragmentRoot(p1, "src"); //$NON-NLS-1$ + env.setOutputFolder(p1, "bin"); //$NON-NLS-1$ + + env.addClass(root1, "pack.missing", "MissingType", //$NON-NLS-1$ //$NON-NLS-2$ + "package pack.missing;\n" + + "public class MissingType {\n" + + "}\n" + ); + + //---------------------------- + // Project2 + //---------------------------- + IPath p2 = env.addProject("SampleLib", "1.8"); //$NON-NLS-1$ + env.addExternalJars(p2, Util.getJavaClassLibs()); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p2, ""); //$NON-NLS-1$ + IPath root2 = env.addPackageFragmentRoot(p2, "src"); //$NON-NLS-1$ + env.setOutputFolder(p2, "bin"); //$NON-NLS-1$ + + env.addClass(root2, "pack.lib", "TopClass", //$NON-NLS-1$ //$NON-NLS-2$ + "package pack.lib;\n" + + "public abstract class TopClass {\n" + + " abstract Object get();\n" + + "}\n" + ); + env.addClass(root2, "pack.lib", "SuperClass", //$NON-NLS-1$ //$NON-NLS-2$ + "package pack.lib;\n" + + "import pack.missing.MissingType;\n" + + "public class SuperClass extends TopClass {\n" + + " @Override\n" + + " MissingType get() { return null; }\n" + + "}\n" + ); + + //---------------------------- + // Project3 + //---------------------------- + IPath p3 = env.addProject("SampleTest", "1.8"); //$NON-NLS-1$ + env.addExternalJars(p3, Util.getJavaClassLibs()); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p3, ""); //$NON-NLS-1$ + IPath root3 = env.addPackageFragmentRoot(p3, "src"); //$NON-NLS-1$ + env.setOutputFolder(p3, "bin"); //$NON-NLS-1$ + + env.addClass(root3, "pack.test", "Test", //$NON-NLS-1$ //$NON-NLS-2$ + "package pack.test;\n" + + "import pack.lib.SuperClass;\n" + + "public class Test extends SuperClass {/*empty*/}\n" + ); + + // for Project1 + env.addRequiredProject(p2, p1); + env.addRequiredProject(p3, p2); + env.waitForManualRefresh(); + fullBuild(); + env.waitForAutoBuild(); + expectingNoProblemsFor(p3); + env.setBuildOrder(null); + env.removeProject(p1); + env.removeProject(p2); + env.removeProject(p3); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AnnotationTest.java index 466557801e5..ffe8ed0767d 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AnnotationTest.java @@ -7973,8 +7973,8 @@ public void test237() { "----------\n" + "2. ERROR in X.java (at line 6)\n" + " List ls = get();\n" + - " ^^^^^\n" + - "Type mismatch: cannot convert from B to List\n" + + " ^^^\n" + + "The method get() from the type X refers to the missing type ArrayList\n" + "----------\n"); } public void test238() { diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java index 2b0f686803c..f2cf8999f6b 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java @@ -43243,6 +43243,11 @@ public void test1222() { " public class X {\n" + " ^^^^\n" + "Zork cannot be resolved to a type\n" + + "----------\n" + + "2. ERROR in X.java (at line 4)\n" + + " Runnable r = x2.get();\n" + + " ^^^\n" + + "The method get() from the type X refers to the missing type Zork\n" + "----------\n"); } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=211718 diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java index 1386fe9ad27..1c3fe0eb91f 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java @@ -9173,45 +9173,40 @@ public void testBug525580() { "----------\n" + "2. ERROR in org\\a\\a\\g\\d.java (at line 6)\n" + " T t = (e) cls.newInstance();\n" + - " ^^^^^^^^^^^^^^^^^^^^^\n" + - "e cannot be resolved to a type\n" + - "----------\n" + - "3. ERROR in org\\a\\a\\g\\d.java (at line 6)\n" + - " T t = (e) cls.newInstance();\n" + " ^\n" + "e cannot be resolved to a type\n" + "----------\n" + - "4. ERROR in org\\a\\a\\g\\d.java (at line 7)\n" + + "3. ERROR in org\\a\\a\\g\\d.java (at line 7)\n" + " while (size >= 0) {\n" + " ^^^^\n" + "size cannot be resolved to a variable\n" + "----------\n" + - "5. ERROR in org\\a\\a\\g\\d.java (at line 8)\n" + - " T a = ((b) this.e.m.get(size)).a();\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Type mismatch: cannot convert from e to T\n" + - "----------\n" + - "6. ERROR in org\\a\\a\\g\\d.java (at line 8)\n" + + "4. ERROR in org\\a\\a\\g\\d.java (at line 8)\n" + " T a = ((b) this.e.m.get(size)).a();\n" + " ^\n" + "e cannot be resolved or is not a field\n" + "----------\n" + - "7. ERROR in org\\a\\a\\g\\d.java (at line 8)\n" + + "5. ERROR in org\\a\\a\\g\\d.java (at line 8)\n" + " T a = ((b) this.e.m.get(size)).a();\n" + " ^^^^\n" + "size cannot be resolved to a variable\n" + "----------\n" + - "8. ERROR in org\\a\\a\\g\\d.java (at line 15)\n" + + "6. ERROR in org\\a\\a\\g\\d.java (at line 8)\n" + + " T a = ((b) this.e.m.get(size)).a();\n" + + " ^\n" + + "The method a() from the type d.b refers to the missing type e\n" + + "----------\n" + + "7. ERROR in org\\a\\a\\g\\d.java (at line 15)\n" + " T a();\n" + " ^\n" + "e cannot be resolved to a type\n" + "----------\n" + - "9. ERROR in org\\a\\a\\g\\d.java (at line 17)\n" + + "8. ERROR in org\\a\\a\\g\\d.java (at line 17)\n" + " T b();\n" + " ^\n" + "j cannot be resolved to a type\n" + "----------\n" + - "10. WARNING in org\\a\\a\\g\\d.java (at line 17)\n" + + "9. WARNING in org\\a\\a\\g\\d.java (at line 17)\n" + " T b();\n" + " ^^^\n" + "This method has a constructor name\n" + @@ -9292,8 +9287,8 @@ public void testBug525580_comment28() { "----------\n" + "3. ERROR in xxxxxx\\iiibii.java (at line 9)\n" + " return b041D041D041D041DН041DН(new xxxxxx.jjajaa(b, b2));\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Type mismatch: cannot convert from jajaja to jajaja\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^\n" + + "The method b041D041D041D041DН041DН(jjajaa) from the type iiibii refers to the missing type jajaja\n" + "----------\n" + "----------\n" + "1. ERROR in xxxxxx\\jjajaa.java (at line 3)\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LookupTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LookupTest.java index 9ab267f7327..a011541d5e1 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LookupTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LookupTest.java @@ -1907,7 +1907,7 @@ public void test059() { " Zork bb() {\n" + " }\n" + " void cc() {\n" + - " this.bb();\n" + + " Object o = this.bb();\n" + " }\n" + " public static void main(String[] args) {\n" + " System.out.println(\"SUCCESS\");\n" + @@ -1921,8 +1921,8 @@ public void test059() { "Zork cannot be resolved to a type\n" + "----------\n" + "2. ERROR in X.java (at line 10)\n" + - " this.bb();\n" + - " ^^\n" + + " Object o = this.bb();\n" + + " ^^\n" + "The method bb() from the type X refers to the missing type Zork\n" + "----------\n"); } @@ -1940,7 +1940,7 @@ public void test060() { " Zork bb() {\n" + " }\n" + " void cc() {\n" + - " this.bb();\n" + + " Object o = this.bb();\n" + " }\n" + " public static void main(String[] args) {\n" + " System.out.println(\"SUCCESS\");\n" + @@ -1959,8 +1959,8 @@ public void test060() { "Zork cannot be resolved to a type\n" + "----------\n" + "3. ERROR in X.java (at line 10)\n" + - " this.bb();\n" + - " ^^\n" + + " Object o = this.bb();\n" + + " ^^\n" + "The method bb() from the type X refers to the missing type Zork\n" + "----------\n"); } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java index 5af1988a49f..d0205b01945 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java @@ -454,6 +454,7 @@ public void test004() { } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=196200 - variation public void test005() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 this.runConformTest( new String[] { "p/OtherFoo.java", //----------------------------------------------------------------------- @@ -485,8 +486,9 @@ public void test005() { "public class X {\n" + " void foo() {\n" + " p.OtherFoo ofoo = new p.OtherFoo();\n" + - " ofoo.bar();\n" + + " Object o = ofoo.bar();\n" + " q1.q2.Zork z;\n" + + " ofoo.bar();\n" + // not a problem " }\n" + "} \n", }, @@ -496,16 +498,11 @@ public void test005() { // compiler results "----------\n" + /* expected compiler log */ "1. ERROR in X.java (at line 4)\n" + - " ofoo.bar();\n" + - " ^^^^^^^^^^\n" + - "The type q1.q2.Zork cannot be resolved. It is indirectly referenced from required type p.OtherFoo\n" + - "----------\n" + - "2. ERROR in X.java (at line 4)\n" + - " ofoo.bar();\n" + - " ^^^\n" + + " Object o = ofoo.bar();\n" + + " ^^^\n" + "The method bar() from the type OtherFoo refers to the missing type Zork\n" + "----------\n" + - "3. ERROR in X.java (at line 5)\n" + + "2. ERROR in X.java (at line 5)\n" + " q1.q2.Zork z;\n" + " ^^^^^^^^^^\n" + "q1.q2.Zork cannot be resolved to a type\n" + @@ -515,6 +512,7 @@ public void test005() { } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=196200 - variation public void test006() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 this.runConformTest( new String[] { "p/OtherFoo.java", //----------------------------------------------------------------------- @@ -562,17 +560,7 @@ public void test006() { " ^^\n" + "The import q1 cannot be resolved\n" + "----------\n" + - "2. ERROR in X.java (at line 5)\n" + - " ofoo.bar();\n" + - " ^^^^^^^^^^\n" + - "The type q1.q2.Zork cannot be resolved. It is indirectly referenced from required type p.OtherFoo\n" + - "----------\n" + - "3. ERROR in X.java (at line 5)\n" + - " ofoo.bar();\n" + - " ^^^\n" + - "The method bar() from the type OtherFoo refers to the missing type Zork\n" + - "----------\n" + - "4. ERROR in X.java (at line 6)\n" + + "2. ERROR in X.java (at line 6)\n" + " Zork z;\n" + " ^^^^\n" + "Zork cannot be resolved to a type\n" + @@ -582,6 +570,7 @@ public void test006() { } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=196200 - variation public void test007() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 this.runConformTest( new String[] { "p/OtherFoo.java", //----------------------------------------------------------------------- @@ -614,7 +603,7 @@ public void test007() { "public class X {\n" + " void foo() {\n" + " p.OtherFoo ofoo = new p.OtherFoo();\n" + - " ofoo.bar();\n" + + " Object o = ofoo.bar();\n" + " Zork z;\n" + " }\n" + "} \n", @@ -630,16 +619,11 @@ public void test007() { "The import q1 cannot be resolved\n" + "----------\n" + "2. ERROR in X.java (at line 5)\n" + - " ofoo.bar();\n" + - " ^^^^^^^^^^\n" + - "The type q1.q2.Zork cannot be resolved. It is indirectly referenced from required type p.OtherFoo\n" + - "----------\n" + - "3. ERROR in X.java (at line 5)\n" + - " ofoo.bar();\n" + - " ^^^\n" + + " Object o = ofoo.bar();\n" + + " ^^^\n" + "The method bar() from the type OtherFoo refers to the missing type Zork\n" + "----------\n" + - "4. ERROR in X.java (at line 6)\n" + + "3. ERROR in X.java (at line 6)\n" + " Zork z;\n" + " ^^^^\n" + "Zork cannot be resolved to a type\n" + @@ -3451,8 +3435,8 @@ public void test074() { "The method bar1() from the type X refers to the missing type Zork\n" + "----------\n" + "2. ERROR in X.java (at line 5)\n" + - " bar2();\n" + - " ^^^^\n" + + " Object o = bar2();\n" + + " ^^^^\n" + "The method bar2() from the type X refers to the missing type Zork\n" + "----------\n" + "3. ERROR in X.java (at line 6)\n" + @@ -3493,7 +3477,7 @@ public void test074() { "public class X {\n" + " void foo() {\n" + " bar1().foo();\n" + - " bar2();\n" + + " Object o = bar2();\n" + " bar3(null);\n" + " bar4(null,null);\n" + " }\n" + @@ -8828,4 +8812,1482 @@ public void testBug576735() { "----------\n"; runner.runNegativeTest(); } +public void testMissingClassNeededForOverloadResolution() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public void m(A a) {} + public void m(Object s) {} + public void m(Object s1, String s2) {} + public void other() {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + b.other(); // no need to see A for other() + b.m(this, ""); // overload selected by arity + } + } + """ + }; + runner.runConformTest(); + + runner.testFiles = new String[] { + "p2/D.java", + """ + package p2; + import p1.B; + public class D { + void test(B b) { + b.m(this); // cannot select without seeing class A + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\D.java (at line 5) + b.m(this); // cannot select without seeing class A + ^ + The method m(A) from the type B refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_pickByLateArg() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/MissingType.java", + """ + package p1; + public class MissingType {} + """, + "p1/B.java", + """ + package p1; + import java.util.Date; + public interface B { + public void m(String s, MissingType m, Date d); + public void m(String s, Object o, Integer i); + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "MissingType.class")); + runner.shouldFlushOutputDirectory = false; + + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + b.m("Hello", new Object(), 42); // last arg rules out the overload with MissingType + } + } + """ + }; + runner.runConformTest(); +} +public void testMissingClassNeededForOverloadResolution_ctor() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public B(A a) {} + public B(Object s) {} + public B(Object s1, String s2) {} + public B() {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + new B(); // no need to see A for B() + new B(this, ""); // overload selected by arity + } + } + """ + }; + runner.runConformTest(); + + runner.testFiles = new String[] { + "p2/D.java", + """ + package p2; + import p1.B; + public class D { + void test(B b) { + new B(this); // cannot select without seeing class A + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\D.java (at line 5) + new B(this); // cannot select without seeing class A + ^^^^^^^^^^^ + The constructor B(A) refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs1a() { + // varargs arg: B vs Missing + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A1.java", + """ + package p1; + public class A1 {} + """, + "p1/A2.java", + """ + package p1; + public class A2 {} + """, + "p1/B.java", + """ + package p1; + public class B { + public void m(Object o1, B... s) {} + public void m(Object o1, A1... a) {} + public void m(Object o1, A2... a) {} + } + """ + }; + runner.runConformTest(); + + // delete binary files A1, A2 (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A1.class")); + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A2.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + b.m(this); // simply ambiguous as we don't even look at A1 or A2 + b.m(this, null); + b.m(this, b); + b.m(this, b, b); + b.m(this, new B[0]); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + b.m(this); // simply ambiguous as we don't even look at A1 or A2 + ^ + The method m(Object, B[]) is ambiguous for the type B + ---------- + 2. ERROR in p2\\C.java (at line 6) + b.m(this, null); + ^ + The method m(Object, A1...) from the type B refers to the missing type A1 + ---------- + 3. ERROR in p2\\C.java (at line 7) + b.m(this, b); + ^ + The method m(Object, A1...) from the type B refers to the missing type A1 + ---------- + 4. ERROR in p2\\C.java (at line 8) + b.m(this, b, b); + ^ + The method m(Object, A1...) from the type B refers to the missing type A1 + ---------- + 5. ERROR in p2\\C.java (at line 9) + b.m(this, new B[0]); + ^ + The method m(Object, A1...) from the type B refers to the missing type A1 + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs1a_ctor() { + // varargs arg: B vs Missing + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A1.java", + """ + package p1; + public class A1 {} + """, + "p1/A2.java", + """ + package p1; + public class A2 {} + """, + "p1/B.java", + """ + package p1; + public class B { + public B(Object o1, B... s) {} + public B(Object o1, A1... a) {} + public B(Object o1, A2... a) {} + } + """ + }; + runner.runConformTest(); + + // delete binary files A1, A2 (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A1.class")); + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A2.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + new B(this); // simply ambiguous as we don't even look at A1 or A2 + new B(this, null); + new B(this, b); + new B(this, b, b); + new B(this, new B[0]); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + new B(this); // simply ambiguous as we don't even look at A1 or A2 + ^^^^^^^^^^^ + The constructor B(Object, B[]) is ambiguous + ---------- + 2. ERROR in p2\\C.java (at line 6) + new B(this, null); + ^^^^^^^^^^^^^^^^^ + The constructor B(Object, A1...) refers to the missing type A1 + ---------- + 3. ERROR in p2\\C.java (at line 7) + new B(this, b); + ^^^^^^^^^^^^^^ + The constructor B(Object, A1...) refers to the missing type A1 + ---------- + 4. ERROR in p2\\C.java (at line 8) + new B(this, b, b); + ^^^^^^^^^^^^^^^^^ + The constructor B(Object, A1...) refers to the missing type A1 + ---------- + 5. ERROR in p2\\C.java (at line 9) + new B(this, new B[0]); + ^^^^^^^^^^^^^^^^^^^^^ + The constructor B(Object, A1...) refers to the missing type A1 + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs1b() { + // like testMissingClassNeededForOverloadResolution_varargs1a, but no preceding regular parameter + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A1.java", + """ + package p1; + public class A1 {} + """, + "p1/A2.java", + """ + package p1; + public class A2 {} + """, + "p1/B.java", + """ + package p1; + public class B { + public void m(String... s) {} + public void m(A1... a) {} + public void m(A2... a) {} + } + """ + }; + runner.runConformTest(); + + // delete binary files A1, A1 (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A1.class")); + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A2.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + b.m(); // simply ambiguous as we don't even look at A1 or A2 + b.m(null); + b.m(b); + b.m(b, b); + b.m(new B[0]); + b.m(""); // would like to check against A1 / A2 + b.m("", ""); // would like to check against A1 / A2 + b.m(new String[0]); // exact match + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + b.m(); // simply ambiguous as we don't even look at A1 or A2 + ^ + The method m(String[]) is ambiguous for the type B + ---------- + 2. ERROR in p2\\C.java (at line 6) + b.m(null); + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + 3. ERROR in p2\\C.java (at line 7) + b.m(b); + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + 4. ERROR in p2\\C.java (at line 8) + b.m(b, b); + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + 5. ERROR in p2\\C.java (at line 9) + b.m(new B[0]); + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + 6. ERROR in p2\\C.java (at line 10) + b.m(""); // would like to check against A1 / A2 + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + 7. ERROR in p2\\C.java (at line 11) + b.m("", ""); // would like to check against A1 / A2 + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs1c() { + // varargs arg: only missing types competing + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A1.java", + """ + package p1; + public class A1 {} + """, + "p1/A2.java", + """ + package p1; + public class A2 {} + """, + "p1/B.java", + """ + package p1; + public class B { + public void m(Object o1, A1... a) {} + public void m(Object o1, A2... a) {} + } + """ + }; + runner.runConformTest(); + + // delete binary files A1, A1 (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A1.class")); + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A2.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + b.m(this); // simply ambiguous as we don't even look at A1 or A2 + b.m(this, null); + b.m(this, b); + b.m(this, b, b); + b.m(this, new B[0]); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + b.m(this); // simply ambiguous as we don't even look at A1 or A2 + ^ + The method m(Object, A1[]) is ambiguous for the type B + ---------- + 2. ERROR in p2\\C.java (at line 6) + b.m(this, null); + ^ + The method m(Object, A1...) from the type B refers to the missing type A1 + ---------- + 3. ERROR in p2\\C.java (at line 7) + b.m(this, b); + ^ + The method m(Object, A1...) from the type B refers to the missing type A1 + ---------- + 4. ERROR in p2\\C.java (at line 8) + b.m(this, b, b); + ^ + The method m(Object, A1...) from the type B refers to the missing type A1 + ---------- + 5. ERROR in p2\\C.java (at line 9) + b.m(this, new B[0]); + ^ + The method m(Object, A1...) from the type B refers to the missing type A1 + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs1d() { + // like testMissingClassNeededForOverloadResolution_varargs1c, but no preceding regular parameter + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A1.java", + """ + package p1; + public class A1 {} + """, + "p1/A2.java", + """ + package p1; + public class A2 {} + """, + "p1/B.java", + """ + package p1; + public class B { + public void m(A1... a) {} + public void m(A2... a) {} + } + """ + }; + runner.runConformTest(); + + // delete binary files A1, A1 (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A1.class")); + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A2.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + b.m(); // simply ambiguous as we don't even look at A1 or A2 + b.m(null); + b.m(b); + b.m(b, b); + b.m(new B[0]); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + b.m(); // simply ambiguous as we don't even look at A1 or A2 + ^ + The method m(A1[]) is ambiguous for the type B + ---------- + 2. ERROR in p2\\C.java (at line 6) + b.m(null); + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + 3. ERROR in p2\\C.java (at line 7) + b.m(b); + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + 4. ERROR in p2\\C.java (at line 8) + b.m(b, b); + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + 5. ERROR in p2\\C.java (at line 9) + b.m(new B[0]); + ^ + The method m(A1...) from the type B refers to the missing type A1 + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs2() { + // different arities + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public void m(Object o1, String s, A... a) {} + public void m(Object o1) {} + public void n(Object o1, A... a) {} + public void n(Object o1) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + b.m(this, ""); // overload selected by arity, trailing A[] is irrelevant + b.m(this); // overload selected by arity, no reference to A + } + } + """ + }; + runner.runConformTest(); + + runner.testFiles = new String[] { + "p2/D.java", + """ + package p2; + import p1.B; + public class D { + void test(B b) { + b.n(this, null); // passing null into A[] is not OK + b.n(this, null, null); // passing null into A is not OK (could potentially be accepted) + b.n(this); // resolvable in strict mode, ignore the varargs method + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\D.java (at line 5) + b.n(this, null); // passing null into A[] is not OK + ^ + The method n(Object, A...) from the type B refers to the missing type A + ---------- + 2. ERROR in p2\\D.java (at line 6) + b.n(this, null, null); // passing null into A is not OK (could potentially be accepted) + ^ + The method n(Object, A...) from the type B refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs2_ctorOK() { + // different arities + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public B(Object o1, String s, A... a) {} + public B(Object o1) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test() { + new B(this, ""); // overload selected by arity, trailing A[] is irrelevant + new B(this); // overload selected by arity, no reference to A + } + } + """ + }; + runner.runConformTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs2_qualCtorOK() { + // different arities + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/Outer.java", + """ + package p1; + public class Outer { + public class B { + public B(Object o1, String s, A... a) {} + public B(Object o1) {} + } + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.Outer; + public class C { + void test(Outer outer) { + outer.new B(this, ""); // overload selected by arity, trailing A[] is irrelevant + outer.new B(this); // overload selected by arity, no reference to A + } + } + """ + }; + runner.runConformTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs2_ctorNOK() { + // different arities + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.customOptions = getCompilerOptions(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public B(Object o1, A... a) {} + public B(Object o1) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.customOptions.put(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, CompilerOptions.IGNORE); + + runner.testFiles = new String[] { + "p2/D.java", + """ + package p2; + import p1.B; + public class D { + void test(B b) { + new B(this, null); // passing null into A[] is not OK + new B(this, null, null); // passing null into A is not OK (could potentially be accepted) + new B(this); // resolvable in strict mode, ignore the varargs method + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\D.java (at line 5) + new B(this, null); // passing null into A[] is not OK + ^^^^^^^^^^^^^^^^^ + The constructor B(Object, A...) refers to the missing type A + ---------- + 2. ERROR in p2\\D.java (at line 6) + new B(this, null, null); // passing null into A is not OK (could potentially be accepted) + ^^^^^^^^^^^^^^^^^^^^^^^ + The constructor B(Object, A...) refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs3() { + // missing type in non-varargs position + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public void m(A a, String... args) {} + public void m(Object s, Number... args) {} + public void m(Object s1, String s2) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + b.m(this, ""); // two overloads could apply (not knowing A) + b.m(this, 3); // overload effectively selected by 2nd arg + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + b.m(this, ""); // two overloads could apply (not knowing A) + ^ + The method m(A, String...) from the type B refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClassNeededForOverloadResolution_varargs3_ctor() { + // missing type in non-varargs position + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public B(A a, String... args) {} + public B(Object s, Number... args) {} + public B(Object s1, String s2) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + new B(this, ""); // two overloads could apply (not knowing A) + new B(this, 3); // overload effectively selected by 2nd arg + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + new B(this, ""); // two overloads could apply (not knowing A) + ^^^^^^^^^^^^^^^ + The constructor B(A, String...) refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_returnType_OK() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A { + public A() { System.out.print("new A()"); } + } + """, + "p1/B.java", + """ + package p1; + public class B { + public A m(Object o) { + System.out.print("B.m()"); + return new A(); + } + } + """ + }; + runner.runConformTest(); + + // temporarily move A.class to A.moved (i.e. simulate removing it from classpath for the next compile) + File classFileA = new File(OUTPUT_DIR, "p1" + File.separator + "A.class"); + File movedFileA = new File(OUTPUT_DIR, "p1" + File.separator + "A.moved"); + classFileA.renameTo(movedFileA); + runner.shouldFlushOutputDirectory = false; + + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C extends B { + void test(B b) { + b.m(this); + } + } + """ + }; + runner.expectedErrorString = "java.lang.NoClassDefFoundError: p1/A\n"; + runner.runConformTest(); + + runner.testFiles = new String[] { + "p2/Main.java", + """ + package p2; + import p1.B; + public class Main { + public static void main(String... args) { + new C().test(new B()); + System.out.print("SUCCESS"); + } + } + """ + }; + // restore A.class and expect execution of Main to succeed + movedFileA.renameTo(classFileA); + runner.expectedOutputString = "B.m()new A()SUCCESS"; + runner.shouldFlushOutputDirectory = false; + runner.expectedErrorString = null; + runner.runConformTest(); +} +public void testMissingClass_returnType_NOK() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public A m(Object o) { return new A(); } + public void n(A a) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + import java.util.function.Function; + public class C extends B { + void test(B b) { + B b2 = b.m(this); + b.n(b.m(this)); + boolean f = b.m(this) == b; + f = b.m(this) instanceof B; + Function fun = b.m(this)::foo; + Object o = b.m(this).new Inner(); + } + @Override + public B m(Object o) { return super.m(o); } + class Inner {} + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 6) + B b2 = b.m(this); + ^ + The method m(Object) from the type B refers to the missing type A + ---------- + 2. ERROR in p2\\C.java (at line 7) + b.n(b.m(this)); + ^ + The method m(Object) from the type B refers to the missing type A + ---------- + 3. ERROR in p2\\C.java (at line 8) + boolean f = b.m(this) == b; + ^ + The method m(Object) from the type B refers to the missing type A + ---------- + 4. ERROR in p2\\C.java (at line 9) + f = b.m(this) instanceof B; + ^ + The method m(Object) from the type B refers to the missing type A + ---------- + 5. ERROR in p2\\C.java (at line 10) + Function fun = b.m(this)::foo; + ^ + The method m(Object) from the type B refers to the missing type A + ---------- + 7. ERROR in p2\\C.java (at line 11) + Object o = b.m(this).new Inner(); + ^ + The method m(Object) from the type B refers to the missing type A + ---------- + 8. ERROR in p2\\C.java (at line 14) + public B m(Object o) { return super.m(o); } + ^ + The return type is incompatible with B.m(Object) + ---------- + 9. ERROR in p2\\C.java (at line 14) + public B m(Object o) { return super.m(o); } + ^ + The method m(Object) from the type B refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_exception() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A extends Exception {} + """, + "p1/B.java", + """ + package p1; + import p1.A; + public class B { + public void m() throws A {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + class C { + void test(B b) { + b.m(); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + b.m(); + ^ + The method m() from the type B refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_exception_ctor() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A extends Exception {} + """, + "p1/B.java", + """ + package p1; + import p1.A; + public class B { + public B() throws A {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + class C { + void test() { + new B(); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + new B(); + ^^^^^^^ + The constructor B() refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_typeVariableBound() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + import p1.A; + public class B { + public void m(Number n) {} // would match, but ... + public void m(T t) {} // ... don't rule out method with missing type + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + class C { + void test(B b) { + b.m(Integer.valueOf(13)); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + b.m(Integer.valueOf(13)); + ^ + The method m(T) from the type B refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_typeVariableBound_OK() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + import p1.A; + public class B { + public B(Number n) {} // would match, but ... + public B(T t) {} // ... don't rule out method with missing type + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + class C { + void test(B b) { + new B(Integer.valueOf(13)); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + new B(Integer.valueOf(13)); + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + The constructor B(T) refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_typeVariableBound2() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + import p1.A; + public class B { + public void m(T t) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + class C { + void test(B b) { + b.m(this); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 1) + package p2; + ^ + The type p1.A cannot be resolved. It is indirectly referenced from required type p1.B + ---------- + 2. ERROR in p2\\C.java (at line 4) + void test(B b) { + ^ + Bound mismatch: The type C is not a valid substitute for the bounded parameter of the type B + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_typeVariableBound2_ctor() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + import p1.A; + public class B { + public B(T t) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + class C { + B test() { + new B<>(this); + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 1) + package p2; + ^ + The type p1.A cannot be resolved. It is indirectly referenced from required type p1.B + ---------- + 2. ERROR in p2\\C.java (at line 4) + B test() { + ^ + Bound mismatch: The type C is not a valid substitute for the bounded parameter of the type B + ---------- + 3. ERROR in p2\\C.java (at line 5) + new B<>(this); + ^^^^^^^^^^^^^ + Cannot infer type arguments for B<> + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_samMissingParameterType_OK() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/F.java", + """ + package p1; + import p1.A; + public interface F { + public void m(A a); + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.F; + class C { + F test() { + return a -> {}; + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + return a -> {}; + ^^^^ + This lambda expression refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_samMissingParameterType_NOK() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/F.java", + """ + package p1; + import p1.A; + public interface F { + public void m(A a); + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.F; + class C { + F test() { + return a -> bar(a); + } + void bar(C c) {} + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + return a -> bar(a); + ^^^^^^^^^^^ + This lambda expression refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} +public void testMissingClass_samMissingReturnType() { + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/F.java", + """ + package p1; + import p1.A; + public interface F { + public A m(); + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + + runner.shouldFlushOutputDirectory = false; + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.F; + class C { + F test() { + return () -> null; + } + } + """ + }; + runner.expectedCompilerLog = """ + ---------- + 1. ERROR in p2\\C.java (at line 5) + return () -> null; + ^^^^^^^^^^ + This lambda expression refers to the missing type A + ---------- + """; + runner.runNegativeTest(); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java index dc26c3ecc47..0e054e5469e 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java @@ -2836,7 +2836,7 @@ public void testBug564638_041() { "2. ERROR in X.java (at line 5)\n" + " this(t);\n" + " ^^^^^^^^\n" + - "The parameterized constructor X(permits) of type X is not applicable for the arguments (Integer)\n" + + "The constructor X(permits) refers to the missing type permits\n" + "----------\n"); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -2863,7 +2863,7 @@ public void testBug564638_042() { "3. ERROR in X.java (at line 5)\n" + " this(t);\n" + " ^^^^^^^^\n" + - "The parameterized constructor X(permits) of type X is not applicable for the arguments (Integer)\n" + + "The constructor X(permits) refers to the missing type permits\n" + "----------\n", null, true, @@ -2887,7 +2887,7 @@ public void testBug564638_043() { "1. ERROR in X.java (at line 5)\n" + " new X(t).foo();\n" + " ^^^^^^^^^^^^^^^^^\n" + - "The parameterized constructor X(permits) of type X is not applicable for the arguments (Integer)\n" + + "The constructor X(permits) refers to the missing type permits\n" + "----------\n" + "2. ERROR in X.java (at line 5)\n" + " new X(t).foo();\n" + @@ -2915,7 +2915,7 @@ public void testBug564638_044() { "1. ERROR in X.java (at line 5)\n" + " new X(t).foo();\n" + " ^^^^^^^^^^^^^^^^^\n" + - "The parameterized constructor X(permits) of type X is not applicable for the arguments (Integer)\n" + + "The constructor X(permits) refers to the missing type permits\n" + "----------\n" + "2. ERROR in X.java (at line 5)\n" + " new X(t).foo();\n" + @@ -2949,7 +2949,7 @@ public void testBug564638_045() { "2. ERROR in X.java (at line 6)\n" + " x.foo(0);\n" + " ^^^\n" + - "The parameterized method foo(permits) of type X is not applicable for the arguments (Integer)\n" + + "The method foo(permits) from the type X refers to the missing type permits\n" + "----------\n"); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -2977,7 +2977,7 @@ public void testBug564638_046() { "3. ERROR in X.java (at line 6)\n" + " x.foo(0);\n" + " ^^^\n" + - "The parameterized method foo(permits) of type X is not applicable for the arguments (Integer)\n" + + "The method foo(permits) from the type X refers to the missing type permits\n" + "----------\n", null, true, @@ -4459,7 +4459,7 @@ public void testBug564638b_041() { "2. ERROR in X.java (at line 5)\n" + " this(t);\n" + " ^^^^^^^^\n" + - "The parameterized constructor X(sealed) of type X is not applicable for the arguments (Integer)\n" + + "The constructor X(sealed) refers to the missing type sealed\n" + "----------\n"); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -4486,7 +4486,7 @@ public void testBug564638b_042() { "3. ERROR in X.java (at line 5)\n" + " this(t);\n" + " ^^^^^^^^\n" + - "The parameterized constructor X(sealed) of type X is not applicable for the arguments (Integer)\n" + + "The constructor X(sealed) refers to the missing type sealed\n" + "----------\n", null, true, @@ -4510,7 +4510,7 @@ public void testBug564638b_043() { "1. ERROR in X.java (at line 5)\n" + " new X(t).foo();\n" + " ^^^^^^^^^^^^^^^^\n" + - "The parameterized constructor X(sealed) of type X is not applicable for the arguments (Integer)\n" + + "The constructor X(sealed) refers to the missing type sealed\n" + "----------\n" + "2. ERROR in X.java (at line 5)\n" + " new X(t).foo();\n" + @@ -4538,7 +4538,7 @@ public void testBug564638b_044() { "1. ERROR in X.java (at line 5)\n" + " new X(t).foo();\n" + " ^^^^^^^^^^^^^^^^\n" + - "The parameterized constructor X(sealed) of type X is not applicable for the arguments (Integer)\n" + + "The constructor X(sealed) refers to the missing type sealed\n" + "----------\n" + "2. ERROR in X.java (at line 5)\n" + " new X(t).foo();\n" + @@ -4572,7 +4572,7 @@ public void testBug564638b_045() { "2. ERROR in X.java (at line 6)\n" + " x.foo(0);\n" + " ^^^\n" + - "The parameterized method foo(sealed) of type X is not applicable for the arguments (Integer)\n" + + "The method foo(sealed) from the type X refers to the missing type sealed\n" + "----------\n"); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -4600,7 +4600,7 @@ public void testBug564638b_046() { "3. ERROR in X.java (at line 6)\n" + " x.foo(0);\n" + " ^^^\n" + - "The parameterized method foo(sealed) of type X is not applicable for the arguments (Integer)\n" + + "The method foo(sealed) from the type X refers to the missing type sealed\n" + "----------\n", null, true, diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST3Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST3Test.java index ba8f5097e98..0f86b176244 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST3Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST3Test.java @@ -6995,8 +6995,8 @@ public void test0295() throws JavaModelException { assertNotNull("No compilation unit", result); //$NON-NLS-1$ assertTrue("result is not a compilation unit", result instanceof CompilationUnit); //$NON-NLS-1$ CompilationUnit compilationUnit = (CompilationUnit) result; - assertEquals("Wrong size", 2, compilationUnit.getMessages().length); //$NON-NLS-1$ - assertEquals("Wrong size", 2, compilationUnit.getProblems().length); //$NON-NLS-1$ + assertEquals("Wrong size", 1, compilationUnit.getMessages().length); //$NON-NLS-1$ + assertEquals("Wrong size", 1, compilationUnit.getProblems().length); //$NON-NLS-1$ ASTNode node = getASTNode(compilationUnit, 0, 1, 0); assertTrue("Not an ExpressionStatement", node instanceof ExpressionStatement); //$NON-NLS-1$ ExpressionStatement expressionStatement = (ExpressionStatement) node; diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST4Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST4Test.java index 936cff67fcc..5118af8d577 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST4Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST4Test.java @@ -6995,8 +6995,8 @@ public void test0295() throws JavaModelException { assertNotNull("No compilation unit", result); //$NON-NLS-1$ assertTrue("result is not a compilation unit", result instanceof CompilationUnit); //$NON-NLS-1$ CompilationUnit compilationUnit = (CompilationUnit) result; - assertEquals("Wrong size", 2, compilationUnit.getMessages().length); //$NON-NLS-1$ - assertEquals("Wrong size", 2, compilationUnit.getProblems().length); //$NON-NLS-1$ + assertEquals("Wrong size", 1, compilationUnit.getMessages().length); //$NON-NLS-1$ + assertEquals("Wrong size", 1, compilationUnit.getProblems().length); //$NON-NLS-1$ ASTNode node = getASTNode(compilationUnit, 0, 1, 0); assertTrue("Not an ExpressionStatement", node instanceof ExpressionStatement); //$NON-NLS-1$ ExpressionStatement expressionStatement = (ExpressionStatement) node; diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST8Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST8Test.java index 4e1bc1df2f6..431e6334cdb 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST8Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST8Test.java @@ -6993,8 +6993,8 @@ public void test0295() throws JavaModelException { assertNotNull("No compilation unit", result); //$NON-NLS-1$ assertTrue("result is not a compilation unit", result instanceof CompilationUnit); //$NON-NLS-1$ CompilationUnit compilationUnit = (CompilationUnit) result; - assertEquals("Wrong size", 2, compilationUnit.getMessages().length); //$NON-NLS-1$ - assertEquals("Wrong size", 2, compilationUnit.getProblems().length); //$NON-NLS-1$ + assertEquals("Wrong size", 1, compilationUnit.getMessages().length); //$NON-NLS-1$ + assertEquals("Wrong size", 1, compilationUnit.getProblems().length); //$NON-NLS-1$ ASTNode node = getASTNode(compilationUnit, 0, 1, 0); assertTrue("Not an ExpressionStatement", node instanceof ExpressionStatement); //$NON-NLS-1$ ExpressionStatement expressionStatement = (ExpressionStatement) node; diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java index 84291dfa06c..ac7ffe183c6 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java @@ -7160,8 +7160,8 @@ public void test0295() throws JavaModelException { assertNotNull("No compilation unit", result); //$NON-NLS-1$ assertTrue("result is not a compilation unit", result instanceof CompilationUnit); //$NON-NLS-1$ CompilationUnit compilationUnit = (CompilationUnit) result; - assertEquals("Wrong size", 2, compilationUnit.getMessages().length); //$NON-NLS-1$ - assertEquals("Wrong size", 2, compilationUnit.getProblems().length); //$NON-NLS-1$ + assertEquals("Wrong size", 1, compilationUnit.getMessages().length); //$NON-NLS-1$ + assertEquals("Wrong size", 1, compilationUnit.getProblems().length); //$NON-NLS-1$ ASTNode node = getASTNode(compilationUnit, 0, 1, 0); assertTrue("Not an ExpressionStatement", node instanceof ExpressionStatement); //$NON-NLS-1$ ExpressionStatement expressionStatement = (ExpressionStatement) node; diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java index 2db09a5979b..2d17b43bb7c 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java @@ -160,10 +160,14 @@ private String buildBindingKey(String contents) throws JavaModelException { } private IBinding[] createBindings(String contents, IJavaElement element) throws JavaModelException { + return createBindings(contents, element, false); + } + private IBinding[] createBindings(String contents, IJavaElement element, boolean recoverBindings) throws JavaModelException { this.workingCopy.getBuffer().setContents(contents); this.workingCopy.makeConsistent(null); ASTParser parser = ASTParser.newParser(JLS3_INTERNAL); parser.setProject(getJavaProject("P")); + parser.setBindingsRecovery(recoverBindings); IJavaElement[] elements = new IJavaElement[] {element}; return parser.createBindings(elements, null); } @@ -1175,6 +1179,22 @@ public void testCreateBindings14a() throws JavaModelException { IBinding[] bindings = createBindings( "public class X {\n" + "}", + this.workingCopy.getType("X").getTypeParameter("T"), + true // recover bindings, java.lang.Number is missing from jclMin! + ); + assertBindingsEqual( + "LX;:TT;", + bindings); + } + + /* + * Ensures that the correct IBindings are created for a given set of IJavaElement + * (type parameter with bound) + */ + public void testCreateBindings14a2() throws JavaModelException { + IBinding[] bindings = createBindings( + "public class X {\n" + // j.l.Exception is present + "}", this.workingCopy.getType("X").getTypeParameter("T") ); assertBindingsEqual( diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests2.java index 355c86465d9..cb991bf3b25 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests2.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests2.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 IBM Corporation and others. + * Copyright (c) 2014, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -210,6 +210,7 @@ public void testBug123836c() throws CoreException { // create the common project and create an interface project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); createFile("/P/Test.java", + "import java.io.Serializable;\n" + "class Test {\n"+ " void calc(Property prop, Property p2) {\n"+ " prop.compute(null);\n"+ @@ -232,6 +233,36 @@ public void testBug123836c() throws CoreException { deleteProject(project); } } + public void testBug123836c_missingImport() throws CoreException { + // original version with missing import, will now give POTENTIAL_MATCH + IJavaProject project = null; + try + { + // create the common project and create an interface + project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); + createFile("/P/Test.java", + "class Test {\n"+ + " void calc(Property prop, Property p2) {\n"+ + " prop.compute(null);\n"+ + " p2.compute(null);\n"+ + " }\n"+ + "}\n"+ + "abstract class Property {\n"+ + " public abstract void compute(E e);\n"+ + "}\n"+ + "class StringProperty extends Property {\n"+ + " @Override public void compute(String e) {\n"+ + " System.out.println(e);\n"+ + " }"); + IType type = getCompilationUnit("/P/Test.java").getType("StringProperty"); + IMethod method = type.getMethod("compute", new String[]{"QString;"}); + search(method, REFERENCES, EXACT_RULE, SearchEngine.createWorkspaceScope(), this.resultCollector); + assertSearchResults("Test.java void Test.calc(Property, Property) [compute(null)] EXACT_MATCH\n" + + "Test.java void Test.calc(Property, Property) [compute(null)] POTENTIAL_MATCH"); + } finally { + deleteProject(project); + } + } // Test inner class public void testBug123836d() throws CoreException { IJavaProject project = null; @@ -240,6 +271,7 @@ public void testBug123836d() throws CoreException { // create the common project and create an interface project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); createFile("/P/Test.java", + "import java.io.Serializable;\n" + "class Test {\n"+ " void calc(Property prop, Property p2) {\n"+ " prop.compute(null);\n"+ @@ -271,6 +303,7 @@ public void testBug123836e() throws CoreException { // create the common project and create an interface project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); createFile("/P/Test.java", + "import java.io.Serializable;\n" + "class Test {\n"+ " void calc(Property prop, Property p2) {\n"+ " prop.compute(null);\n"+ @@ -301,6 +334,7 @@ public void testBug123836f() throws CoreException { // create the common project and create an interface project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); createFile("/P/Test.java", + "import java.io.Serializable;\n" + "class Test {\n"+ " void calc(Property prop, Property p2) {\n"+ " prop.compute(null);\n"+ @@ -331,6 +365,7 @@ public void testBug123836g() throws CoreException { // create the common project and create an interface project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); createFile("/P/Test.java", + "import java.io.Serializable;\n" + "class Test {\n"+ " {\n" + " new Property() {\n" + @@ -361,6 +396,7 @@ public void testBug123836h() throws CoreException { // create the common project and create an interface project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); createFile("/P/Test.java", + "import java.io.Serializable;\n" + "class Test {\n"+ " static {\n" + " new Property() {\n" + @@ -391,6 +427,7 @@ public void testBug123836i() throws CoreException { // create the common project and create an interface project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); createFile("/P/Test.java", + "import java.io.Serializable;\n" + "class Test {\n"+ " Property p = new Property() {\n" + " @Override public void compute(String e) {}\n" + @@ -418,6 +455,7 @@ public void testBug123836j() throws CoreException { // create the common project and create an interface project = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "","1.5"); createFile("/P/Test.java", + "import java.io.Serializable;\n" + "class Test {\n"+ " void calc(Property prop, Property p2) {\n"+ " prop.compute(null);\n"+ diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java index 632e7e6fafd..a1f0f895cd7 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java @@ -75,7 +75,7 @@ public static Test suite() { protected void setUp() throws Exception { super.setUp(); - IJavaProject proj= createJavaProject(PROJECT, new String[] {"src"}, new String[] {"JCL_LIB"}, "bin", "1.8"); + IJavaProject proj= createJavaProject(PROJECT, new String[] {"src"}, new String[] {"JCL18_LIB"}, "bin", "1.8"); proj.setOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.SPACE); proj.setOption(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "4"); proj.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); @@ -794,6 +794,7 @@ public void testBug474270_since_8() throws Exception { parser.setSource(cu); parser.setResolveBindings(true); parser.setStatementsRecovery(true); + parser.setBindingsRecovery(true); CompilationUnit astRoot = (CompilationUnit) parser.createAST(null); TypeDeclaration type= (TypeDeclaration) astRoot.types().get(1); MethodDeclaration [] methods = type.getMethods();