diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java index 884e8308905..47c30e56ea0 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -1701,6 +1701,28 @@ private ReferenceBinding findPermittedtype(TypeReference typeReference) { } typeReference.bits |= ASTNode.IgnoreRawTypeCheck; ReferenceBinding permittedType = (ReferenceBinding) typeReference.resolveType(this); + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1808#issuecomment-1918455864 + if (permittedType != null && permittedType.isMemberType() && permittedType.isPrivate()) { + String name = CharOperation.toString(permittedType.compoundName); + name = name.replace("$", "."); //$NON-NLS-1$ //$NON-NLS-2$ + char[][] compoundName = CharOperation.splitOn('.', name.toCharArray()); + ImportBinding[] imports = unitScope.imports; + boolean resolved = false; + for (ImportBinding importBinding: imports) { + if (CharOperation.equals(compoundName, importBinding.compoundName)) { + resolved = true; + break; + } + } + if (!resolved) { + MissingTypeBinding miss = new MissingTypeBinding(permittedType.fPackage, compoundName, + env); + typeReference.resolvedType = miss; + typeReference.resolveType(this); + problemReporter().invalidType(typeReference, miss); + return miss; + } + } return permittedType; } catch (AbortCompilation e) { SourceTypeBinding sourceType = this.referenceContext.binding; 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 4c51fc8e8bb..69d0dc6cdb5 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 @@ -3457,7 +3457,7 @@ final Binding getTypeOrPackage(char[] name, int mask, boolean needResolve) { if (memberType.problemId() == ProblemReasons.Ambiguous) { if (foundType == null || foundType.problemId() == ProblemReasons.NotVisible) // supercedes any potential InheritedNameHidesEnclosingName problem - return memberType; + return checkUsed(name, scope, memberType); // make the user qualify the type, likely wants the first inherited type return new ProblemReferenceBinding(new char[][]{name}, foundType, ProblemReasons.InheritedNameHidesEnclosingName); } @@ -3468,7 +3468,7 @@ final Binding getTypeOrPackage(char[] name, int mask, boolean needResolve) { // found a valid type in the 'immediate' scope (i.e. not inherited) // OR in 1.4 mode (inherited visible shadows enclosing) if (foundType == null || (inheritedHasPrecedence && foundType.problemId() == ProblemReasons.NotVisible)) - return memberType; + return checkUsed(name, scope, memberType); // if a valid type was found, complain when another is found in an 'immediate' enclosing type (i.e. not inherited) if (foundType.isValidBinding() && TypeBinding.notEquals(foundType, memberType)) return new ProblemReferenceBinding(new char[][]{name}, foundType, ProblemReasons.InheritedNameHidesEnclosingName); @@ -3656,6 +3656,26 @@ final Binding getTypeOrPackage(char[] name, int mask, boolean needResolve) { return foundType; } + private Binding checkUsed(char[] name, Scope scope, ReferenceBinding memberType) { + CompilationUnitScope unitScope = scope.compilationUnitScope(); + ImportBinding[] imports = unitScope.imports; + HashtableOfObject typeOrPackageCache = unitScope.typeOrPackageCache; + if (imports != null && typeOrPackageCache == null) { // walk single type imports since faultInImports() has not run yet + for (int i = 0, length = imports.length; i < length; i++) { + ImportBinding importBinding = imports[i]; + if (!importBinding.onDemand && CharOperation.equals(importBinding.getSimpleName(), name)) { + Binding resolvedImport = unitScope.resolveSingleImport(importBinding, Binding.TYPE); + if (resolvedImport instanceof TypeBinding) { + ImportReference importReference = importBinding.reference; + if (importReference != null && !isUnnecessarySamePackageImport(importBinding.resolvedImport, unitScope)) + importReference.bits |= ASTNode.Used; + } + } + } + } + return memberType; + } + private boolean isUnnecessarySamePackageImport(Binding resolvedImport, Scope unitScope) { if (resolvedImport instanceof ReferenceBinding) { ReferenceBinding referenceBinding = (ReferenceBinding) resolvedImport; diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest_17.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest_17.java index ab1697a6400..ce43927a540 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest_17.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest_17.java @@ -147,4 +147,46 @@ boolean match(String err) { return "StdErr: " + error + " StdOut: " + output; } + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1808 + public void testGH1808() { + this.runConformTest( + new String[] { + "p/X.java", + """ + package foo; + import foo.X.B; + public sealed interface X permits B { + record B(int data) implements X {} + } + """ + }, + "\"" + OUTPUT_DIR + File.separator + "p" + File.separator + "X.java\"" + + " -17 -g -preserveAllLocals -proceedOnError -referenceInfo ", + "", + "", + true); + } + public void testGH1808a() { + this.runNegativeTest( + new String[] { + "p/X.java", + """ + package foo; + public sealed interface X permits B { + record B(int data) {} + } + """ + }, + "\"" + OUTPUT_DIR + File.separator + "p" + File.separator + "X.java\"" + + " -17 -g -preserveAllLocals -proceedOnError -referenceInfo ", + "", + "----------\n" + + "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/p/X.java (at line 2)\n" + + " public sealed interface X permits B {\n" + + " ^\n" + + "B cannot be resolved to a type\n" + + "----------\n" + + "1 problem (1 error)\n", + true); + } }