mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] HighlightUtil.checkModuleReferenceAccess migrated
Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: 72eaed5e89969c19e29dee7a6921fa3b5f45c6c0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9dab6a4401
commit
d843df8aa8
+13
-3
@@ -512,9 +512,12 @@ module.file.wrong.name=Module declaration should be in a file named 'module-info
|
||||
module.file.duplicate='module-info.java' already exists in the module
|
||||
module.duplicate.requires=Duplicate ''requires'': {0}
|
||||
module.duplicate.exports=Duplicate ''exports'': {0}
|
||||
module.duplicate.exports.target=Duplicate ''exports'' target: {0}
|
||||
module.duplicate.opens=Duplicate ''opens'': {0}
|
||||
module.duplicate.opens.target=Duplicate ''opens'' target: {0}
|
||||
module.duplicate.uses=Duplicate ''uses'': {0}
|
||||
module.duplicate.provides=Duplicate ''provides'': {0}
|
||||
module.duplicate.implementation=Duplicate implementation: {0}
|
||||
module.file.wrong.location=Module declaration should be located in a module's source root
|
||||
module.opens.in.weak.module='opens' is not allowed in an open module
|
||||
module.service.enum=The service definition is an enum: {0}
|
||||
@@ -527,8 +530,15 @@ module.service.no.constructor=The service implementation does not have a public
|
||||
module.not.found=Module not found: {0}
|
||||
module.not.on.path=Module is not in dependencies: {0}
|
||||
module.cyclic.dependence=Cyclic dependency: {0}
|
||||
module.duplicate.exports.target=Duplicate ''exports'' target: {0}
|
||||
module.duplicate.opens.target=Duplicate ''opens'' target: {0}
|
||||
module.duplicate.implementation=Duplicate implementation: {0}
|
||||
module.reference.package.not.found=Package not found: {0}
|
||||
module.reference.package.empty=Package is empty: {0}
|
||||
module.access.from.named=Package ''{0}'' is declared in module ''{1}'', which does not export it to module ''{2}''
|
||||
module.access.from.unnamed=Package ''{0}'' is declared in module ''{1}'', which does not export it to the unnamed module
|
||||
module.access.to.unnamed=Package ''{0}'' is declared in the unnamed module, but module ''{1}'' does not read it
|
||||
module.access.package.bad.name=Package ''{0}'' is declared in module with an invalid name (''{1}'')
|
||||
module.access.bad.name=Module ''{0}'' has an invalid name
|
||||
module.access.package.not.in.graph=Package ''{0}'' is declared in module ''{1}'', which is not in the module graph
|
||||
module.access.not.in.graph=Module ''{0}'' is missing from the module graph
|
||||
module.access.package.does.not.read=Package ''{0}'' is declared in module ''{1}'', but module ''{2}'' does not read it
|
||||
module.access.does.not.read=Module ''{0}'' fails to read ''{1}''
|
||||
module.access.jps.dependency.problem=Module dependency for ''{0}'' is not specified in project structure
|
||||
|
||||
+38
-10
@@ -3,6 +3,8 @@ package com.intellij.java.codeserver.highlighting;
|
||||
|
||||
import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
|
||||
import com.intellij.java.codeserver.core.JavaServiceProviderUtil;
|
||||
import com.intellij.java.codeserver.core.JpmsModuleAccessInfo;
|
||||
import com.intellij.java.codeserver.core.JpmsModuleInfo;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKind;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
|
||||
import com.intellij.openapi.module.Module;
|
||||
@@ -217,15 +219,6 @@ final class ModuleChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkModuleReference(@NotNull PsiImportModuleStatement statement) {
|
||||
PsiJavaModuleReferenceElement refElement = statement.getModuleReference();
|
||||
if (refElement == null) return;
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
if (ref != null && ref.resolve() == null) {
|
||||
reportUnresolvedJavaModule(refElement);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportUnresolvedJavaModule(@NotNull PsiJavaModuleReferenceElement refElement) {
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
assert ref != null : refElement.getParent();
|
||||
@@ -236,7 +229,9 @@ final class ModuleChecker {
|
||||
? JavaErrorKinds.REFERENCE_PENDING.create(refElement)
|
||||
: JavaErrorKinds.MODULE_NOT_FOUND.create(refElement));
|
||||
case 1 -> myVisitor.report(JavaErrorKinds.MODULE_NOT_ON_PATH.create(refElement));
|
||||
default -> {}
|
||||
default -> {
|
||||
// ambiguous module is reported as warning
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,4 +298,37 @@ final class ModuleChecker {
|
||||
: JavaErrorKinds.MODULE_REFERENCE_PACKAGE_EMPTY;
|
||||
myVisitor.report(kind.create(statement));
|
||||
}
|
||||
|
||||
JavaErrorKind.Parameterized<PsiElement, JpmsModuleAccessInfo> accessError(@NotNull JpmsModuleAccessInfo.JpmsModuleAccessProblem problem) {
|
||||
return switch (problem) {
|
||||
case FROM_NAMED -> JavaErrorKinds.MODULE_ACCESS_FROM_NAMED;
|
||||
case FROM_UNNAMED -> JavaErrorKinds.MODULE_ACCESS_FROM_UNNAMED;
|
||||
case TO_UNNAMED -> JavaErrorKinds.MODULE_ACCESS_TO_UNNAMED;
|
||||
case PACKAGE_BAD_NAME -> JavaErrorKinds.MODULE_ACCESS_PACKAGE_BAD_NAME;
|
||||
case BAD_NAME -> JavaErrorKinds.MODULE_ACCESS_BAD_NAME;
|
||||
case PACKAGE_NOT_IN_GRAPH -> JavaErrorKinds.MODULE_ACCESS_PACKAGE_NOT_IN_GRAPH;
|
||||
case NOT_IN_GRAPH -> JavaErrorKinds.MODULE_ACCESS_NOT_IN_GRAPH;
|
||||
case PACKAGE_DOES_NOT_READ -> JavaErrorKinds.MODULE_ACCESS_PACKAGE_DOES_NOT_READ;
|
||||
case DOES_NOT_READ -> JavaErrorKinds.MODULE_ACCESS_DOES_NOT_READ;
|
||||
case JPS_DEPENDENCY_PROBLEM -> JavaErrorKinds.MODULE_ACCESS_JPS_DEPENDENCY_PROBLEM;
|
||||
};
|
||||
}
|
||||
|
||||
void checkModuleReference(@NotNull PsiImportModuleStatement statement) {
|
||||
PsiJavaModuleReferenceElement refElement = statement.getModuleReference();
|
||||
if (refElement == null) return;
|
||||
PsiJavaModuleReference ref = refElement.getReference();
|
||||
if (ref == null) return;
|
||||
PsiJavaModule target = ref.resolve();
|
||||
if (target == null) {
|
||||
reportUnresolvedJavaModule(refElement);
|
||||
return;
|
||||
}
|
||||
JpmsModuleAccessInfo moduleAccess = new JpmsModuleInfo.TargetModuleInfo(target, "").accessAt(myVisitor.file().getOriginalFile());
|
||||
JpmsModuleAccessInfo.JpmsModuleAccessProblem problem = moduleAccess.checkModuleAccess(statement);
|
||||
if (problem != null) {
|
||||
myVisitor.report(accessError(problem).create(statement, moduleAccess));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+33
@@ -6,6 +6,7 @@ import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.java.codeserver.core.JavaPreviewFeatureUtil;
|
||||
import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
|
||||
import com.intellij.java.codeserver.core.JpmsModuleAccessInfo;
|
||||
import com.intellij.java.codeserver.highlighting.JavaCompilationErrorBundle;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKind.Parameterized;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKind.Simple;
|
||||
@@ -1541,6 +1542,38 @@ public final class JavaErrorKinds {
|
||||
.withAnchor(st -> st.getPackageReference())
|
||||
.withRawDescription(st -> message("module.reference.package.empty", st.getPackageName()));
|
||||
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_FROM_NAMED =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.from.named")
|
||||
.withRawDescription((psi, info) -> message(
|
||||
"module.access.from.named", info.getTarget().getPackageName(), info.getTarget().getModule().getName(), info.getCurrent().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_FROM_UNNAMED =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.from.unnamed")
|
||||
.withRawDescription((psi, info) -> message("module.access.from.unnamed", info.getTarget().getPackageName(), info.getTarget().getModule().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_TO_UNNAMED =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.to.unnamed")
|
||||
.withRawDescription((psi, info) -> message("module.access.to.unnamed", info.getTarget().getPackageName(), info.getCurrent().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_PACKAGE_BAD_NAME =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.package.bad.name")
|
||||
.withRawDescription((psi, info) -> message("module.access.package.bad.name", info.getTarget().getPackageName(), info.getTarget().getModule().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_BAD_NAME =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.bad.name")
|
||||
.withRawDescription((psi, info) -> message("module.access.bad.name", info.getTarget().getModule().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_PACKAGE_NOT_IN_GRAPH =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.package.not.in.graph")
|
||||
.withRawDescription((psi, info) -> message("module.access.package.not.in.graph", info.getTarget().getPackageName(), info.getTarget().getModule().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_NOT_IN_GRAPH =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.not.in.graph")
|
||||
.withRawDescription((psi, info) -> message("module.access.not.in.graph", info.getTarget().getModule().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_PACKAGE_DOES_NOT_READ =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.package.does.not.read")
|
||||
.withRawDescription((psi, info) -> message("module.access.package.does.not.read", info.getTarget().getPackageName(), info.getTarget().getModule().getName(), info.getCurrent().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_DOES_NOT_READ =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.does.not.read")
|
||||
.withRawDescription((psi, info) -> message("module.access.does.not.read", info.getTarget().getModule().getName(), info.getCurrent().getName()));
|
||||
public static final Parameterized<PsiElement, JpmsModuleAccessInfo> MODULE_ACCESS_JPS_DEPENDENCY_PROBLEM =
|
||||
parameterized(PsiElement.class, JpmsModuleAccessInfo.class, "module.access.jps.dependency.problem")
|
||||
.withRawDescription((psi, info) -> message("module.access.jps.dependency.problem", info.getTarget().getModule().getName()));
|
||||
|
||||
private static @NotNull <Psi extends PsiElement> Simple<Psi> error(
|
||||
@NotNull @PropertyKey(resourceBundle = JavaCompilationErrorBundle.BUNDLE) String key) {
|
||||
return new Simple<>(key);
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.JavaModuleSystem;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -37,7 +40,4 @@ public interface JavaModuleSystemEx extends JavaModuleSystem {
|
||||
|
||||
@Nullable
|
||||
ErrorWithFixes checkAccess(@NotNull String targetPackageName, @Nullable PsiFile targetFile, @NotNull PsiElement place);
|
||||
|
||||
@Nullable
|
||||
ErrorWithFixes checkAccess(@NotNull PsiJavaModule module, @NotNull PsiElement place);
|
||||
}
|
||||
-20
@@ -106,26 +106,6 @@ public final class HighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkModuleReferenceAccess(@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;
|
||||
for (JavaModuleSystem moduleSystem : JavaModuleSystem.EP_NAME.getExtensionList()) {
|
||||
if (!(moduleSystem instanceof JavaModuleSystemEx javaModuleSystemEx)) continue;
|
||||
ErrorWithFixes fixes = javaModuleSystemEx.checkAccess(target, statement);
|
||||
if (fixes == null) continue;
|
||||
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
|
||||
.range(statement)
|
||||
.descriptionAndTooltip(fixes.message);
|
||||
fixes.fixes.forEach(fix -> info.registerFix(fix, null, null, null, null));
|
||||
return info;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isAccessible(@NotNull JavaModuleSystem system, @NotNull PsiElement target, @NotNull PsiElement place) {
|
||||
if (target instanceof PsiClass psiClass) return system.isAccessible(psiClass, place);
|
||||
if (target instanceof PsiPackage psiPackage) return system.isAccessible(psiPackage.getQualifiedName(), null, place);
|
||||
|
||||
-6
@@ -229,12 +229,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitImportModuleStatement(@NotNull PsiImportModuleStatement statement) {
|
||||
super.visitImportModuleStatement(statement);
|
||||
if (!hasErrorResults()) add(HighlightUtil.checkModuleReferenceAccess(statement));
|
||||
}
|
||||
|
||||
static @Nullable JavaResolveResult resolveOptimised(@NotNull PsiJavaCodeReferenceElement ref, @NotNull PsiFile containingFile) {
|
||||
try {
|
||||
if (ref instanceof PsiReferenceExpressionImpl) {
|
||||
|
||||
+38
@@ -14,6 +14,7 @@ import com.intellij.codeInspection.dataFlow.fix.RedundantInstanceofFix;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.java.codeserver.core.JavaPsiModifierUtil;
|
||||
import com.intellij.java.codeserver.core.JpmsModuleAccessInfo;
|
||||
import com.intellij.java.codeserver.highlighting.JavaErrorCollector;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaCompilationError;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKind;
|
||||
@@ -178,6 +179,43 @@ final class JavaErrorFixProvider {
|
||||
};
|
||||
fix(MODULE_REFERENCE_PACKAGE_NOT_FOUND, createClassInPackage);
|
||||
fix(MODULE_REFERENCE_PACKAGE_EMPTY, createClassInPackage);
|
||||
|
||||
JavaFixProvider<PsiElement, JpmsModuleAccessInfo> fixExports = error -> {
|
||||
if (error.context().getTarget().getPackageName().isEmpty()) return null;
|
||||
Module jpsModule = error.context().getCurrent().getJpsModule();
|
||||
PsiJavaModule targetModule = error.context().getTarget().getModule();
|
||||
if (targetModule instanceof PsiCompiledElement && jpsModule != null) {
|
||||
return new AddExportsOptionFix(jpsModule, targetModule.getName(), error.context().getTarget().getPackageName(),
|
||||
error.context().getCurrent().getName());
|
||||
}
|
||||
if (!(targetModule instanceof PsiCompiledElement) && error.context().getCurrent().getModule() != null) {
|
||||
return new AddExportsDirectiveFix(requireNonNull(targetModule), error.context().getTarget().getPackageName(),
|
||||
error.context().getCurrent().getName());
|
||||
}
|
||||
return null;
|
||||
};
|
||||
fix(MODULE_ACCESS_FROM_UNNAMED, fixExports);
|
||||
fix(MODULE_ACCESS_FROM_NAMED, fixExports);
|
||||
JavaFixProvider<PsiElement, JpmsModuleAccessInfo> fixModuleOptions =
|
||||
error -> new AddModulesOptionFix(requireNonNull(error.context().getCurrent().getJpsModule()),
|
||||
requireNonNull(error.context().getTarget().getModule()).getName());
|
||||
fix(MODULE_ACCESS_PACKAGE_NOT_IN_GRAPH, fixModuleOptions);
|
||||
fix(MODULE_ACCESS_NOT_IN_GRAPH, fixModuleOptions);
|
||||
JavaFixProvider<PsiElement, JpmsModuleAccessInfo> fixRequires =
|
||||
error -> new AddRequiresDirectiveFix(requireNonNull(error.context().getCurrent().getModule()),
|
||||
requireNonNull(error.context().getTarget().getModule()).getName());
|
||||
fix(MODULE_ACCESS_PACKAGE_DOES_NOT_READ, fixRequires);
|
||||
fix(MODULE_ACCESS_DOES_NOT_READ, fixRequires);
|
||||
fixes(MODULE_ACCESS_JPS_DEPENDENCY_PROBLEM, (error, sink) -> {
|
||||
if (error.psi() instanceof PsiJavaModuleReferenceElement ref) {
|
||||
PsiJavaModuleReference reference = ref.getReference();
|
||||
if (reference != null) {
|
||||
List<CommonIntentionAction> list = new ArrayList<>();
|
||||
myFactory.registerOrderEntryFixes(reference, list);
|
||||
list.forEach(sink);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createStatementFixes() {
|
||||
|
||||
@@ -42,15 +42,6 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx {
|
||||
return TargetModuleInfo(targetModule, "").accessAt(useFile).checkModuleAccess(place) == null
|
||||
}
|
||||
|
||||
override fun checkAccess(targetModule: PsiJavaModule, place: PsiElement): ErrorWithFixes? {
|
||||
val useFile = place.containingFile?.originalFile ?: return null
|
||||
val moduleAccess = TargetModuleInfo(targetModule, "").accessAt(useFile)
|
||||
|
||||
val access = moduleAccess.checkModuleAccess(place)
|
||||
return if (access == null) null
|
||||
else moduleAccess.toErrorWithFixes(access, place)
|
||||
}
|
||||
|
||||
private fun getProblem(targetPackageName: String, targetFile: PsiFile?, place: PsiElement, quick: Boolean,
|
||||
isAccessible: (JpmsModuleAccessInfo) -> Boolean): ErrorWithFixes? {
|
||||
val originalTargetFile = targetFile?.originalFile
|
||||
@@ -83,7 +74,8 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx {
|
||||
val error = checkAccess(TargetModuleInfo(dirs[0], target.qualifiedName), useFile, quick, isAccessible) ?: return null
|
||||
return when {
|
||||
dirs.size == 1 -> error
|
||||
dirs.asSequence().drop(1).any { checkAccess(TargetModuleInfo(it, target.qualifiedName), useFile, true, isAccessible) == null } -> null
|
||||
dirs.asSequence().drop(1).any { TargetModuleInfo(it, target.qualifiedName)
|
||||
.accessAt(useFile).checkAccess(useFile, isAccessible) == null } -> null
|
||||
else -> error
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user