mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
[java, highlighting, import-module] Support Feature level check for Module Import Declarations IDEA-355536
GitOrigin-RevId: 36dcbb509e788a3243f93a52c83cd24ae0dd6985
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9af85109da
commit
e927f5ac3e
@@ -845,6 +845,13 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitImportModuleStatement(@NotNull PsiImportModuleStatement statement) {
|
||||
super.visitImportModuleStatement(statement);
|
||||
if (!hasErrorResults()) add(checkFeature(statement, JavaFeature.MODULE_IMPORT_DECLARATIONS));
|
||||
if (!hasErrorResults()) add(ModuleHighlightUtil.checkModuleReference(statement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitKeyword(@NotNull PsiKeyword keyword) {
|
||||
super.visitKeyword(keyword);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
@@ -214,33 +214,23 @@ final class ModuleHighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkModuleReference(@NotNull PsiImportModuleStatement statement) {
|
||||
PsiJavaModuleReferenceElement refElement = statement.getModuleReference();
|
||||
if (refElement == null) return null;
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
assert ref != null : refElement.getParent();
|
||||
PsiJavaModule target = ref.resolve();
|
||||
if (target != null) return null;
|
||||
return getUnresolvedJavaModuleReason(statement, refElement);
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkModuleReference(@NotNull PsiRequiresStatement statement) {
|
||||
PsiJavaModuleReferenceElement refElement = statement.getReferenceElement();
|
||||
if (refElement != null) {
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
assert ref != null : refElement.getParent();
|
||||
PsiJavaModule target = ref.resolve();
|
||||
if (target == null) {
|
||||
if (ref.multiResolve(true).length == 0) {
|
||||
if (IncompleteModelUtil.isIncompleteModel(statement)) {
|
||||
return HighlightUtil.getPendingReferenceHighlightInfo(refElement);
|
||||
}
|
||||
String message = JavaErrorBundle.message("module.not.found", refElement.getReferenceText());
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(refElement).descriptionAndTooltip(message);
|
||||
}
|
||||
else if (ref.multiResolve(false).length > 1) {
|
||||
String message = JavaErrorBundle.message("module.ambiguous", refElement.getReferenceText());
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(refElement).descriptionAndTooltip(message);
|
||||
}
|
||||
else {
|
||||
String message = JavaErrorBundle.message("module.not.on.path", refElement.getReferenceText());
|
||||
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(refElement).descriptionAndTooltip(message);
|
||||
List<IntentionAction> registrar = new ArrayList<>();
|
||||
QuickFixFactory.getInstance().registerOrderEntryFixes(ref, registrar);
|
||||
QuickFixAction.registerQuickFixActions(info, null, registrar);
|
||||
return info;
|
||||
}
|
||||
}
|
||||
if (target == null) return getUnresolvedJavaModuleReason(statement, refElement);
|
||||
PsiJavaModule container = (PsiJavaModule)statement.getParent();
|
||||
if (target == container) {
|
||||
String message = JavaErrorBundle.message("module.cyclic.dependence", container.getName());
|
||||
@@ -260,6 +250,37 @@ final class ModuleHighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static HighlightInfo.Builder getUnresolvedJavaModuleReason(@NotNull PsiElement parent, @NotNull PsiJavaModuleReferenceElement refElement) {
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
assert ref != null : refElement.getParent();
|
||||
|
||||
ResolveResult[] results = ref.multiResolve(true);
|
||||
switch (results.length) {
|
||||
case 0:
|
||||
if (IncompleteModelUtil.isIncompleteModel(parent)) {
|
||||
return HighlightUtil.getPendingReferenceHighlightInfo(refElement);
|
||||
} else {
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF)
|
||||
.range(refElement)
|
||||
.descriptionAndTooltip(JavaErrorBundle.message("module.not.found", refElement.getReferenceText()));
|
||||
}
|
||||
case 1:
|
||||
String message = JavaErrorBundle.message("module.not.on.path", refElement.getReferenceText());
|
||||
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF)
|
||||
.range(refElement)
|
||||
.descriptionAndTooltip(message);
|
||||
List<IntentionAction> registrar = new ArrayList<>();
|
||||
QuickFixFactory.getInstance().registerOrderEntryFixes(ref, registrar);
|
||||
QuickFixAction.registerQuickFixActions(info, null, registrar);
|
||||
return info;
|
||||
default:
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING)
|
||||
.range(refElement)
|
||||
.descriptionAndTooltip(JavaErrorBundle.message("module.ambiguous", refElement.getReferenceText()));
|
||||
}
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkHostModuleStrength(@NotNull PsiPackageAccessibilityStatement statement) {
|
||||
PsiElement parent;
|
||||
if (statement.getRole() == Role.OPENS &&
|
||||
|
||||
@@ -272,8 +272,11 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe
|
||||
Set<String> unresolvedImports = new HashSet<>(importStatements.length);
|
||||
for (PsiImportStatementBase statement : importStatements) {
|
||||
if (statement instanceof PsiImportModuleStatement importModuleStatement) {
|
||||
PsiJavaModuleReference ref = importModuleStatement.getModuleReference();
|
||||
if (ref != null && ref.resolve() == null) unresolvedImports.add(importModuleStatement.getReferenceName());
|
||||
PsiJavaModuleReferenceElement refElement = importModuleStatement.getModuleReference();
|
||||
if (refElement != null) {
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
if (ref != null && ref.resolve() == null) unresolvedImports.add(importModuleStatement.getReferenceName());
|
||||
}
|
||||
} else {
|
||||
PsiJavaCodeReferenceElement ref = statement.getImportReference();
|
||||
String name = ref == null ? null : ref.getReferenceName();
|
||||
|
||||
@@ -33,9 +33,9 @@ public interface PsiImportModuleStatement extends PsiImportStatementBase {
|
||||
/**
|
||||
* Returns the reference which specifies the imported module.
|
||||
*
|
||||
* @return the reference to the module imported, or null if the reference is not resolvable or missing.
|
||||
* @return the reference element to the module imported, or null if the reference element is not resolvable or missing.
|
||||
*/
|
||||
@Nullable PsiJavaModuleReference getModuleReference();
|
||||
@Nullable PsiJavaModuleReferenceElement getModuleReference();
|
||||
|
||||
@Override
|
||||
default boolean isOnDemand() {
|
||||
|
||||
@@ -20,7 +20,7 @@ public class PsiImportModuleStatementImpl extends PsiImportStatementBaseImpl imp
|
||||
public static final ArrayFactory<PsiImportModuleStatementImpl> ARRAY_FACTORY =
|
||||
count -> count == 0 ? EMPTY_ARRAY : new PsiImportModuleStatementImpl[count];
|
||||
|
||||
private SoftReference<PsiJavaModuleReference> myReference;
|
||||
private SoftReference<PsiJavaModuleReferenceElement> myRefElement;
|
||||
|
||||
public PsiImportModuleStatementImpl(PsiImportStatementStub stub) {
|
||||
super(stub, JavaStubElementTypes.IMPORT_MODULE_STATEMENT);
|
||||
@@ -32,35 +32,38 @@ public class PsiImportModuleStatementImpl extends PsiImportStatementBaseImpl imp
|
||||
|
||||
@Override
|
||||
public @Nullable PsiJavaModule resolveTargetModule() {
|
||||
PsiJavaModuleReference moduleReference = getModuleReference();
|
||||
if (moduleReference == null) return null;
|
||||
return moduleReference.resolve();
|
||||
PsiJavaModuleReferenceElement refElement = getModuleReference();
|
||||
if (refElement == null) return null;
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
if (ref == null) return null;
|
||||
return ref.resolve();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReferenceName() {
|
||||
PsiJavaModuleReference moduleReference = getModuleReference();
|
||||
if (moduleReference == null) return null;
|
||||
return moduleReference.getCanonicalText();
|
||||
PsiJavaModuleReferenceElement refElement = getModuleReference();
|
||||
if (refElement == null) return null;
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
if (ref == null) return null;
|
||||
return ref.getCanonicalText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PsiJavaModuleReference getModuleReference() {
|
||||
public @Nullable PsiJavaModuleReferenceElement getModuleReference() {
|
||||
PsiImportStatementStub stub = getStub();
|
||||
if (stub != null) {
|
||||
String refText = nullize(stub.getImportReferenceText());
|
||||
if (refText == null) return null;
|
||||
PsiJavaModuleReference ref = dereference(myReference);
|
||||
if (ref == null) {
|
||||
ref = JavaPsiFacade.getInstance(getProject()).getParserFacade().createModuleReferenceFromText(refText, this).getReference();
|
||||
myReference = new SoftReference<>(ref);
|
||||
PsiJavaModuleReferenceElement refElement = dereference(myRefElement);
|
||||
if (refElement == null) {
|
||||
refElement = JavaPsiFacade.getInstance(getProject()).getParserFacade().createModuleReferenceFromText(refText, this);
|
||||
myRefElement = new SoftReference<>(refElement);
|
||||
}
|
||||
return ref;
|
||||
return refElement;
|
||||
}
|
||||
else {
|
||||
myReference = null;
|
||||
PsiJavaModuleReferenceElement refElement = PsiTreeUtil.getChildOfType(this, PsiJavaModuleReferenceElement.class);
|
||||
return refElement != null ? refElement.getReference() : null;
|
||||
myRefElement = null;
|
||||
return PsiTreeUtil.getChildOfType(this, PsiJavaModuleReferenceElement.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +79,9 @@ public class PsiImportModuleStatementImpl extends PsiImportStatementBaseImpl imp
|
||||
|
||||
@Override
|
||||
public PsiElement resolve() {
|
||||
PsiJavaModuleReference ref = getModuleReference();
|
||||
PsiJavaModuleReferenceElement refElement = getModuleReference();
|
||||
if (refElement == null) return null;
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
return ref != null ? ref.resolve() : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.platform.backend.workspace.WorkspaceModel
|
||||
import com.intellij.platform.workspace.jps.entities.ModuleId
|
||||
import com.intellij.platform.workspace.jps.entities.modifyModuleEntity
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.psi.JavaCompilerConfigurationProxy
|
||||
import com.intellij.psi.PsiJavaModule
|
||||
import com.intellij.psi.PsiManager
|
||||
@@ -27,6 +28,7 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.ProjectScope
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import com.intellij.testFramework.DumbModeTestUtils
|
||||
import com.intellij.testFramework.IdeaTestUtil
|
||||
import com.intellij.testFramework.workspaceModel.updateProjectModel
|
||||
import junit.framework.TestCase
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@@ -50,6 +52,27 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
fun testModuleImportDeclarationLevelCheck() {
|
||||
IdeaTestUtil.withLevel(module, LanguageLevel.JDK_23) {
|
||||
highlight("Test.java", """
|
||||
<error descr="Module Import Declarations are not supported at language level '23'">import module java.sql;</error>
|
||||
class Test {}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
fun testModuleImportDeclarationUnresolvedModule() {
|
||||
IdeaTestUtil.withLevel(module, LanguageLevel.JDK_23_PREVIEW) {
|
||||
highlight("Test.java", """
|
||||
import module M2;
|
||||
import module <error descr="Module is not in dependencies: M3">M3</error>;
|
||||
import module <error descr="Module not found: M4">M4</error>;
|
||||
|
||||
class Test {}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
fun testPackageStatement() {
|
||||
highlight("package pkg;")
|
||||
highlight("""
|
||||
|
||||
Reference in New Issue
Block a user