[java-highlighting] Finish moving module access errors

Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only)

GitOrigin-RevId: 0f89a7cd9609aea2780e132118aae892a6b0bafd
This commit is contained in:
Tagir Valeev
2025-02-24 15:25:03 +01:00
committed by intellij-monorepo-bot
parent f976c0b04c
commit 2250bb64ee
25 changed files with 248 additions and 404 deletions

View File

@@ -3,11 +3,11 @@ package com.intellij.java.codeserver.core
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.psi.JavaModuleSystem
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.PsiJavaModule
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.pom.java.JavaFeature
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightJavaModule
import com.intellij.psi.util.PsiUtil
/**
* Represents a JPMS module and the corresponding module in IntelliJ project model
@@ -55,4 +55,49 @@ sealed interface JpmsModuleInfo {
return JpmsModuleAccessInfo(current, this)
}
}
companion object {
/**
* Find module info structures when accessing a given location.
*
* @param targetPackageName package name which about to be accessed
* @param targetFile concrete target file which is about to be accessed; null if not known (in this case,
* multiple results could be returned, as multiple source roots may define a given package)
* @param place source place from where the access is requested
* @return list of TargetModuleInfo structures that describe the possible target; empty list if the target package is empty
* (which is generally an error), null if not applicable (e.g., modules are not supported at place;
* target does not belong to any module; etc.). In this case, no access problem should be reported.
*/
@JvmStatic
fun findTargetModuleInfos(targetPackageName: String, targetFile: PsiFile?, place: PsiFile): List<TargetModuleInfo>? {
val originalTargetFile = targetFile?.originalFile
if (!PsiUtil.isAvailable(JavaFeature.MODULES, place)) return null
val useVFile = place.virtualFile
val project = place.project
val index = ProjectFileIndex.getInstance(project)
if (useVFile != null && index.isInLibrarySource(useVFile)) return null
if (originalTargetFile != null && originalTargetFile.isPhysical) {
return listOf(TargetModuleInfo(originalTargetFile, targetPackageName))
}
if (useVFile == null) return null
val target = JavaPsiFacade.getInstance(project).findPackage(targetPackageName) ?: return null
val module = index.getModuleForFile(useVFile) ?: return null
val test = index.isInTestSourceContent(useVFile)
val moduleScope = module.getModuleWithDependenciesAndLibrariesScope(test)
val dirs = target.getDirectories(moduleScope)
val packageName = target.qualifiedName
if (dirs.isEmpty()) {
return if (target.getFiles(moduleScope).isEmpty()) {
listOf()
}
else {
null
}
}
return dirs.map { dir -> TargetModuleInfo(dir, packageName) }
}
}
}

View File

@@ -303,6 +303,7 @@ reference.class.in.default.package=Class ''{0}'' is in the default package
reference.non.static.from.static.context=Non-static {0} ''{1}'' cannot be referenced from a static context
reference.outer.type.parameter.from.static.context=''{0}'' cannot be referenced from a static context
reference.select.from.type.parameter=Cannot select from a type parameter
reference.package.not.found=Package not found: {0}
statement.case.outside.switch=Case statement outside switch
statement.invalid=Invalid statement

View File

@@ -923,6 +923,9 @@ final class ExpressionChecker {
if (!result.isStaticsScopeCorrect()) {
myVisitor.report(JavaErrorKinds.REFERENCE_NON_STATIC_FROM_STATIC_CONTEXT.create(ref, resolved));
}
if (resolved instanceof PsiModifierListOwner owner) {
myVisitor.myModuleChecker.checkModuleAccess(owner, ref);
}
}
private void checkUnresolvedReference(@NotNull PsiJavaCodeReferenceElement ref, @NotNull JavaResolveResult result) {

View File

@@ -8,6 +8,7 @@ import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErro
import com.intellij.lang.jvm.JvmModifier;
import com.intellij.psi.*;
import com.intellij.psi.impl.IncompleteModelUtil;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.*;
@@ -389,4 +390,51 @@ final class FunctionChecker {
}
}
}
// 15.13 | 15.27
// It is a compile-time error if any class or interface mentioned by either U or the function type of U
// is not accessible from the class or interface in which the method reference expression appears.
void checkFunctionalInterfaceTypeAccessible(@NotNull PsiFunctionalExpression expression,
@NotNull PsiType functionalInterfaceType) {
checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType, true);
}
private void checkFunctionalInterfaceTypeAccessible(@NotNull PsiFunctionalExpression expression,
@NotNull PsiType functionalInterfaceType,
boolean checkFunctionalTypeSignature) {
PsiClassType.ClassResolveResult resolveResult =
PsiUtil.resolveGenericsClassInType(PsiClassImplUtil.correctType(functionalInterfaceType, expression.getResolveScope()));
PsiClass psiClass = resolveResult.getElement();
if (psiClass == null) return;
if (!PsiUtil.isAccessible(myVisitor.project(), psiClass, expression, null)) {
myVisitor.myModifierChecker.reportAccessProblem(expression, psiClass, resolveResult);
return;
}
for (PsiType type : resolveResult.getSubstitutor().getSubstitutionMap().values()) {
if (type != null) {
checkFunctionalInterfaceTypeAccessible(expression, type, false);
if (myVisitor.hasErrorResults()) return;
}
}
PsiMethod psiMethod = checkFunctionalTypeSignature ? LambdaUtil.getFunctionalInterfaceMethod(resolveResult) : null;
if (psiMethod != null) {
PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(psiMethod, resolveResult);
for (PsiParameter parameter : psiMethod.getParameterList().getParameters()) {
PsiType substitute = substitutor.substitute(parameter.getType());
if (substitute != null) {
checkFunctionalInterfaceTypeAccessible(expression, substitute, false);
if (myVisitor.hasErrorResults()) return;
}
}
PsiType substitute = substitutor.substitute(psiMethod.getReturnType());
if (substitute != null) {
checkFunctionalInterfaceTypeAccessible(expression, substitute, false);
}
return;
}
myVisitor.myModuleChecker.checkModuleAccess(psiClass, expression);
}
}

View File

@@ -60,7 +60,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
final @NotNull ControlFlowChecker myControlFlowChecker = new ControlFlowChecker(this);
private final @NotNull FunctionChecker myFunctionChecker = new FunctionChecker(this);
final @NotNull PatternChecker myPatternChecker = new PatternChecker(this);
private final @NotNull ModuleChecker myModuleChecker = new ModuleChecker(this);
final @NotNull ModuleChecker myModuleChecker = new ModuleChecker(this);
final @NotNull ModifierChecker myModifierChecker = new ModifierChecker(this);
final @NotNull ExpressionChecker myExpressionChecker = new ExpressionChecker(this);
private final @NotNull SwitchChecker mySwitchChecker = new SwitchChecker(this);
@@ -426,6 +426,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
report(JavaErrorKinds.LAMBDA_NOT_FUNCTIONAL_INTERFACE.create(expression, functionalInterfaceType));
}
if (!hasErrorResults()) myFunctionChecker.checkMethodReferenceContext(expression, functionalInterfaceType);
if (!hasErrorResults()) myFunctionChecker.checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType);
}
if (!hasErrorResults()) myFunctionChecker.checkMethodReferenceResolve(expression, results, functionalInterfaceType);
if (!hasErrorResults()) myFunctionChecker.checkMethodReferenceReturnType(expression, result, functionalInterfaceType);
@@ -472,7 +473,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
else if (parent instanceof PsiClass aClass) {
if (!hasErrorResults()) myClassChecker.checkDuplicateNestedClass(aClass);
if (!hasErrorResults() && !(aClass instanceof PsiAnonymousClass)) {
/* anonymous class is highlighted in HighlightClassUtil.checkAbstractInstantiation()*/
/* an anonymous class is highlighted in HighlightClassUtil.checkAbstractInstantiation()*/
myClassChecker.checkClassMustBeAbstract(aClass);
}
if (!hasErrorResults()) {
@@ -933,6 +934,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (functionalInterfaceType != null) {
myFunctionChecker.checkExtendsSealedClass(expression, functionalInterfaceType);
if (!hasErrorResults()) myFunctionChecker.checkInterfaceFunctional(expression, functionalInterfaceType);
if (!hasErrorResults()) myFunctionChecker.checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType);
}
else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) {
report(JavaErrorKinds.LAMBDA_TYPE_INFERENCE_FAILURE.create(expression));

View File

@@ -178,9 +178,7 @@ final class ModifierChecker {
}
}
void reportAccessProblem(@NotNull PsiJavaCodeReferenceElement ref,
@NotNull PsiModifierListOwner resolved,
@NotNull JavaResolveResult result) {
void reportAccessProblem(@NotNull PsiElement ref, @NotNull PsiModifierListOwner resolved, @NotNull JavaResolveResult result) {
result = withElement(result, resolved);
if (resolved.hasModifierProperty(PsiModifier.PRIVATE)) {
myVisitor.report(JavaErrorKinds.ACCESS_PRIVATE.create(ref, result));
@@ -202,15 +200,11 @@ final class ModifierChecker {
return;
}
checkModuleAccess(resolved, ref);
myVisitor.myModuleChecker.checkModuleAccess(resolved, ref);
if (myVisitor.hasErrorResults()) return;
myVisitor.report(JavaErrorKinds.ACCESS_GENERIC_PROBLEM.create(ref, result));
}
private void checkModuleAccess(@NotNull PsiModifierListOwner resolved, @NotNull PsiElement ref) {
// TODO: JPMS
}
private static @NotNull JavaResolveResult withElement(@NotNull JavaResolveResult original, @NotNull PsiElement newElement) {
if (newElement == original.getElement()) return original;
return new JavaResolveResult() {

View File

@@ -4,7 +4,9 @@ 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.JpmsModuleAccessInfo.JpmsModuleAccessProblem;
import com.intellij.java.codeserver.core.JpmsModuleInfo;
import com.intellij.java.codeserver.highlighting.errors.JavaCompilationError;
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKind;
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
import com.intellij.openapi.module.Module;
@@ -24,6 +26,7 @@ import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
@@ -299,7 +302,7 @@ final class ModuleChecker {
myVisitor.report(kind.create(statement));
}
JavaErrorKind.Parameterized<PsiElement, JpmsModuleAccessInfo> accessError(@NotNull JpmsModuleAccessInfo.JpmsModuleAccessProblem problem) {
JavaErrorKind.Parameterized<PsiElement, JpmsModuleAccessInfo> accessError(@NotNull JpmsModuleAccessProblem problem) {
return switch (problem) {
case FROM_NAMED -> JavaErrorKinds.MODULE_ACCESS_FROM_NAMED;
case FROM_UNNAMED -> JavaErrorKinds.MODULE_ACCESS_FROM_UNNAMED;
@@ -325,10 +328,51 @@ final class ModuleChecker {
return;
}
JpmsModuleAccessInfo moduleAccess = new JpmsModuleInfo.TargetModuleInfo(target, "").accessAt(myVisitor.file().getOriginalFile());
JpmsModuleAccessInfo.JpmsModuleAccessProblem problem = moduleAccess.checkModuleAccess(statement);
JpmsModuleAccessProblem problem = moduleAccess.checkModuleAccess(statement);
if (problem != null) {
myVisitor.report(accessError(problem).create(statement, moduleAccess));
}
}
private static @NotNull PsiElement findPackagePrefix(@NotNull PsiJavaCodeReferenceElement ref) {
PsiElement candidate = ref;
while (candidate instanceof PsiJavaCodeReferenceElement element) {
if (element.resolve() instanceof PsiPackage) return candidate;
candidate = element.getQualifier();
}
return ref;
}
void checkModuleAccess(@NotNull PsiModifierListOwner target, @NotNull PsiElement ref) {
if (target instanceof PsiClass targetClass && !(target instanceof PsiTypeParameter)) {
String packageName = PsiUtil.getPackageName(targetClass);
if (packageName != null) {
checkAccess(packageName, target.getContainingFile(), ref);
}
}
else if (target instanceof PsiPackage targetPackage) {
checkAccess(targetPackage.getQualifiedName(), null, ref);
}
}
private void checkAccess(@NotNull String targetPackageName, @Nullable PsiFile targetFile, @NotNull PsiElement place) {
PsiFile file = myVisitor.file().getOriginalFile();
List<JpmsModuleInfo.@NotNull TargetModuleInfo> infos = JpmsModuleInfo.findTargetModuleInfos(targetPackageName, targetFile, file);
if (infos == null) return;
if (infos.isEmpty()) {
myVisitor.report(JavaErrorKinds.REFERENCE_PACKAGE_NOT_FOUND.create(place, targetPackageName));
return;
}
JavaCompilationError<PsiElement, JpmsModuleAccessInfo> error = null;
for (JpmsModuleInfo.TargetModuleInfo info : infos) {
JpmsModuleAccessInfo moduleAccessInfo = info.accessAt(file);
JpmsModuleAccessProblem problem = moduleAccessInfo.checkAccess(file, JpmsModuleAccessInfo.JpmsModuleAccessMode.READ);
if (problem == null) return;
if (error == null) {
PsiElement anchor = place instanceof PsiJavaCodeReferenceElement ref ? findPackagePrefix(ref) : place;
error = accessError(problem).create(anchor, moduleAccessInfo);
}
}
myVisitor.report(error);
}
}

View File

@@ -117,8 +117,8 @@ final class JavaErrorFormatUtil {
return nameElement.getTextRangeInParent();
}
}
if (element instanceof PsiReferenceExpression refExpression) {
PsiElement nameElement = refExpression.getReferenceNameElement();
if (element instanceof PsiJavaCodeReferenceElement ref) {
PsiElement nameElement = ref.getReferenceNameElement();
if (nameElement != null) {
return nameElement.getTextRangeInParent();
}

View File

@@ -1157,6 +1157,9 @@ public final class JavaErrorKinds {
.withRawDescription((ref, refElement) -> message("reference.outer.type.parameter.from.static.context", refElement.getName()));
public static final Simple<PsiJavaCodeReferenceElement> REFERENCE_SELECT_FROM_TYPE_PARAMETER =
error(PsiJavaCodeReferenceElement.class, "reference.select.from.type.parameter");
public static final Parameterized<PsiElement, String> REFERENCE_PACKAGE_NOT_FOUND =
parameterized(PsiElement.class, String.class, "reference.package.not.found")
.withRawDescription((psi, packageName) -> message("reference.package.not.found", packageName));
public static final Simple<PsiSwitchLabelStatementBase> STATEMENT_CASE_OUTSIDE_SWITCH = error("statement.case.outside.switch");
public static final Simple<PsiStatement> STATEMENT_INVALID = error("statement.invalid");
@@ -1307,23 +1310,23 @@ public final class JavaErrorKinds {
parameterized(PsiExpression.class, PsiType.class, "string.template.raw.processor")
.withRawDescription((psi, type) -> message("string.template.raw.processor", type.getPresentableText()));
public static final Parameterized<PsiJavaCodeReferenceElement, JavaResolveResult> ACCESS_PRIVATE =
parameterized(PsiJavaCodeReferenceElement.class, JavaResolveResult.class, "access.private")
.withAnchor(psi -> requireNonNullElse(psi.getReferenceNameElement(), psi))
public static final Parameterized<PsiElement, JavaResolveResult> ACCESS_PRIVATE =
parameterized(PsiElement.class, JavaResolveResult.class, "access.private")
.withRange((psi, cls) -> getRange(psi))
.withRawDescription((psi, result) -> message("access.private", formatResolvedSymbol(result), formatResolvedSymbolContainer(result)));
public static final Parameterized<PsiJavaCodeReferenceElement, JavaResolveResult> ACCESS_PROTECTED =
parameterized(PsiJavaCodeReferenceElement.class, JavaResolveResult.class, "access.protected")
.withAnchor(psi -> requireNonNullElse(psi.getReferenceNameElement(), psi))
public static final Parameterized<PsiElement, JavaResolveResult> ACCESS_PROTECTED =
parameterized(PsiElement.class, JavaResolveResult.class, "access.protected")
.withRange((psi, cls) -> getRange(psi))
.withRawDescription(
(psi, result) -> message("access.protected", formatResolvedSymbol(result), formatResolvedSymbolContainer(result)));
public static final Parameterized<PsiJavaCodeReferenceElement, JavaResolveResult> ACCESS_PACKAGE_LOCAL =
parameterized(PsiJavaCodeReferenceElement.class, JavaResolveResult.class, "access.package.local")
.withAnchor(psi -> requireNonNullElse(psi.getReferenceNameElement(), psi))
public static final Parameterized<PsiElement, JavaResolveResult> ACCESS_PACKAGE_LOCAL =
parameterized(PsiElement.class, JavaResolveResult.class, "access.package.local")
.withRange((psi, cls) -> getRange(psi))
.withRawDescription(
(psi, result) -> message("access.package.local", formatResolvedSymbol(result), formatResolvedSymbolContainer(result)));
public static final Parameterized<PsiJavaCodeReferenceElement, JavaResolveResult> ACCESS_GENERIC_PROBLEM =
parameterized(PsiJavaCodeReferenceElement.class, JavaResolveResult.class, "access.generic.problem")
.withAnchor(psi -> requireNonNullElse(psi.getReferenceNameElement(), psi))
public static final Parameterized<PsiElement, JavaResolveResult> ACCESS_GENERIC_PROBLEM =
parameterized(PsiElement.class, JavaResolveResult.class, "access.generic.problem")
.withRange((psi, cls) -> getRange(psi))
.withRawDescription(
(psi, result) -> message("access.generic.problem", formatResolvedSymbol(result), formatResolvedSymbolContainer(result)));

View File

@@ -14,6 +14,7 @@ import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.editor.colors.TextAttributesScheme;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.packageDependencies.DependencyValidationManager;
@@ -25,6 +26,8 @@ import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.search.scope.packageSet.NamedScope;
import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
import com.intellij.psi.search.scope.packageSet.PackageSet;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiFormatUtilBase;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
@@ -380,4 +383,13 @@ public final class HighlightNamesUtil {
static HighlightInfo highlightClassKeyword(@NotNull PsiKeyword keyword) {
return nameBuilder(JavaHighlightInfoTypes.JAVA_KEYWORD_CLASS_FILE).range(keyword).create();
}
public static @NotNull @NlsSafe String formatClass(@NotNull PsiClass aClass) {
return formatClass(aClass, true);
}
public static @NotNull String formatClass(@NotNull PsiClass aClass, boolean fqn) {
return PsiFormatUtil.formatClass(aClass, PsiFormatUtilBase.SHOW_NAME |
PsiFormatUtilBase.SHOW_ANONYMOUS_CLASS_VERBOSE | (fqn ? PsiFormatUtilBase.SHOW_FQ_NAME : 0));
}
}

View File

@@ -1,158 +1,34 @@
// Copyright 2000-2025 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.ContainerProvider;
import com.intellij.codeInsight.JavaModuleSystemEx;
import com.intellij.codeInsight.JavaModuleSystemEx.ErrorWithFixes;
import com.intellij.codeInsight.daemon.JavaErrorBundle;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.java.codeserver.core.JavaPsiModifierUtil;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.PsiClass;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiFormatUtilBase;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
// generates HighlightInfoType.ERROR-like HighlightInfos
/**
* @deprecated all methods are deprecated
*/
@Deprecated
public final class HighlightUtil {
private HighlightUtil() { }
/**
* @deprecated use {@link HighlightNamesUtil#formatClass(PsiClass)} or
* preferably {@link PsiFormatUtil#formatClass(PsiClass, int)} directly
*/
@Deprecated
public static @NotNull @NlsSafe String formatClass(@NotNull PsiClass aClass) {
return formatClass(aClass, true);
return HighlightNamesUtil.formatClass(aClass);
}
/**
* @deprecated use {@link HighlightNamesUtil#formatClass(PsiClass)} or
* preferably {@link PsiFormatUtil#formatClass(PsiClass, int)} directly
*/
@Deprecated
public static @NotNull String formatClass(@NotNull PsiClass aClass, boolean fqn) {
return PsiFormatUtil.formatClass(aClass, PsiFormatUtilBase.SHOW_NAME |
PsiFormatUtilBase.SHOW_ANONYMOUS_CLASS_VERBOSE | (fqn ? PsiFormatUtilBase.SHOW_FQ_NAME : 0));
}
static @NotNull Pair<@Nls String, List<IntentionAction>> accessProblemDescriptionAndFixes(@NotNull PsiElement ref,
@NotNull PsiElement resolved,
@NotNull JavaResolveResult result) {
assert resolved instanceof PsiModifierListOwner : resolved;
PsiModifierListOwner refElement = (PsiModifierListOwner)resolved;
String symbolName = HighlightMessageUtil.getSymbolName(refElement, result.getSubstitutor());
if (refElement.hasModifierProperty(PsiModifier.PRIVATE)) {
String containerName = getContainerName(refElement, result.getSubstitutor());
return Pair.pair(JavaErrorBundle.message("private.symbol", symbolName, containerName), null);
}
if (refElement.hasModifierProperty(PsiModifier.PROTECTED)) {
String containerName = getContainerName(refElement, result.getSubstitutor());
return Pair.pair(JavaErrorBundle.message("protected.symbol", symbolName, containerName), null);
}
PsiClass packageLocalClass = JavaPsiModifierUtil.getPackageLocalClassInTheMiddle(ref);
if (packageLocalClass != null) {
refElement = packageLocalClass;
symbolName = HighlightMessageUtil.getSymbolName(refElement, result.getSubstitutor());
}
if (refElement.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || packageLocalClass != null) {
String containerName = getContainerName(refElement, result.getSubstitutor());
return Pair.pair(JavaErrorBundle.message("package.local.symbol", symbolName, containerName), null);
}
String containerName = getContainerName(refElement, result.getSubstitutor());
ErrorWithFixes problem = checkModuleAccess(resolved, ref, symbolName, containerName);
if (problem != null) return Pair.pair(problem.message, problem.fixes);
return Pair.pair(JavaErrorBundle.message("visibility.access.problem", symbolName, containerName), null);
}
static @Nullable @Nls ErrorWithFixes checkModuleAccess(@NotNull PsiElement resolved, @NotNull PsiElement ref, @NotNull JavaResolveResult result) {
PsiElement refElement = resolved;
PsiClass packageLocalClass = JavaPsiModifierUtil.getPackageLocalClassInTheMiddle(ref);
if (packageLocalClass != null) {
refElement = packageLocalClass;
}
String symbolName = HighlightMessageUtil.getSymbolName(refElement, result.getSubstitutor());
String containerName = (resolved instanceof PsiModifierListOwner modifierListOwner)
? getContainerName(modifierListOwner, result.getSubstitutor())
: null;
return checkModuleAccess(resolved, ref, symbolName, containerName);
}
private static @Nullable @Nls ErrorWithFixes checkModuleAccess(@NotNull PsiElement target,
@NotNull PsiElement place,
@Nullable String symbolName,
@Nullable String containerName) {
for (JavaModuleSystem moduleSystem : JavaModuleSystem.EP_NAME.getExtensionList()) {
if (moduleSystem instanceof JavaModuleSystemEx system) {
if (target instanceof PsiClass targetClass) {
final ErrorWithFixes problem = system.checkAccess(targetClass, place);
if (problem != null) return problem;
}
if (target instanceof PsiPackage targetPackage) {
final ErrorWithFixes problem = system.checkAccess(targetPackage.getQualifiedName(), null, place);
if (problem != null) return problem;
}
}
else if (!isAccessible(moduleSystem, target, place)) {
return new ErrorWithFixes(JavaErrorBundle.message("visibility.module.access.problem", symbolName, containerName, moduleSystem.getName()));
}
}
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);
return true;
}
private static PsiElement getContainer(@NotNull PsiModifierListOwner refElement) {
for (ContainerProvider provider : ContainerProvider.EP_NAME.getExtensionList()) {
PsiElement container = provider.getContainer(refElement);
if (container != null) return container;
}
return refElement.getParent();
}
private static String getContainerName(@NotNull PsiModifierListOwner refElement, @NotNull PsiSubstitutor substitutor) {
PsiElement container = getContainer(refElement);
return container == null ? "?" : HighlightMessageUtil.getSymbolName(container, substitutor);
}
static HighlightInfo.Builder checkReference(@NotNull PsiJavaCodeReferenceElement ref, @NotNull JavaResolveResult result) {
PsiElement resolved = result.getElement();
boolean skipValidityChecks =
ref.getParent() instanceof PsiMethodCallExpression || resolved == null ||
PsiUtil.isInsideJavadocComment(ref) ||
PsiTreeUtil.getParentOfType(ref, PsiPackageStatement.class, true) != null ||
resolved instanceof PsiPackage && ref.getParent() instanceof PsiJavaCodeReferenceElement;
if (skipValidityChecks) return null;
final ErrorWithFixes moduleProblem = checkModuleAccess(resolved, ref, result);
if (moduleProblem != null) {
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(findPackagePrefix(ref))
.descriptionAndTooltip(moduleProblem.message);
moduleProblem.fixes.forEach(fix -> info.registerFix(fix, List.of(), null, null, null));
return info;
}
return null;
}
private static @NotNull PsiElement findPackagePrefix(@NotNull PsiJavaCodeReferenceElement ref) {
PsiElement candidate = ref;
while (candidate instanceof PsiJavaCodeReferenceElement element) {
if (element.resolve() instanceof PsiPackage) return candidate;
candidate = element.getQualifier();
}
return ref;
return HighlightNamesUtil.formatClass(aClass, fqn);
}
}

View File

@@ -16,15 +16,11 @@ import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.colors.EditorColorsUtil;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.HtmlChunk;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.NewUI;
@@ -40,6 +36,7 @@ import java.util.Map;
import java.util.function.Consumer;
import static com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds.*;
import static com.intellij.util.ObjectUtils.tryCast;
// java highlighting: problems in java code like unresolved/incompatible symbols/methods etc.
public class HighlightVisitorImpl extends JavaElementVisitor implements HighlightVisitor {
@@ -51,8 +48,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
private @NotNull PsiFile myFile;
private JavaErrorCollector myCollector;
private final @NotNull Consumer<? super HighlightInfo.Builder> myErrorSink = builder -> add(builder);
private boolean myHasError; // true if myHolder.add() was called with HighlightInfo of >=ERROR severity. On each .visit(PsiElement) call this flag is reset. Useful to determine whether the error was already reported while visiting this PsiElement.
protected HighlightVisitorImpl() {
@@ -183,7 +178,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
Consumer<@NotNull CommonIntentionAction> consumer = fix -> info.registerFix(fix.asIntention(), null, null, null, null);
errorFixProvider.processFixes(error, consumer);
ErrorFixExtensionPoint.registerFixes(consumer, error.psi(), error.kind().key());
error.psiForKind(EXPRESSION_EXPECTED, REFERENCE_UNRESOLVED, REFERENCE_AMBIGUOUS, ACCESS_PRIVATE, ACCESS_PACKAGE_LOCAL, ACCESS_PROTECTED)
error.psiForKind(EXPRESSION_EXPECTED, REFERENCE_UNRESOLVED, REFERENCE_AMBIGUOUS)
.or(() -> error.psiForKind(ACCESS_PRIVATE, ACCESS_PACKAGE_LOCAL, ACCESS_PROTECTED).map(psi -> tryCast(psi, PsiJavaCodeReferenceElement.class)))
.or(() -> error.psiForKind(TYPE_UNKNOWN_CLASS).map(PsiTypeElement::getInnermostComponentReferenceElement))
.or(() -> error.psiForKind(CALL_AMBIGUOUS_NO_MATCH, CALL_UNRESOLVED).map(PsiMethodCallExpression::getMethodExpression))
.ifPresent(ref -> UnresolvedReferenceQuickFixProvider.registerUnresolvedReferenceLazyQuickFixes(ref, info));
@@ -206,76 +202,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
return false;
}
@Override
public void visitLambdaExpression(@NotNull PsiLambdaExpression expression) {
visitElement(expression);
PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent());
if (hasErrorResults() || toReportFunctionalExpressionProblemOnParent(parent)) return;
if (!hasErrorResults()) {
PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
add(LambdaHighlightingUtil.checkFunctionalInterfaceTypeAccessible(myFile.getProject(), expression, functionalInterfaceType));
}
}
}
@Override
public void visitImportStaticReferenceElement(@NotNull PsiImportStaticReferenceElement ref) {
super.visitImportStaticReferenceElement(ref);
JavaResolveResult[] results = ref.multiResolve(false);
if (!hasErrorResults() && results.length == 1) {
add(HighlightUtil.checkReference(ref, results[0]));
}
}
static @Nullable JavaResolveResult resolveOptimised(@NotNull PsiJavaCodeReferenceElement ref, @NotNull PsiFile containingFile) {
try {
if (ref instanceof PsiReferenceExpressionImpl) {
PsiReferenceExpressionImpl.OurGenericsResolver resolver = PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE;
JavaResolveResult[] results = JavaResolveUtil.resolveWithContainingFile(ref, resolver, true, true, containingFile);
return results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
}
return ref.advancedResolve(true);
}
catch (IndexNotReadyException e) {
return null;
}
}
@Override
public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
JavaResolveResult result = resolveOptimised(expression, myFile);
if (result != null) {
add(HighlightUtil.checkReference(expression, result));
}
if (!hasErrorResults()) {
visitElement(expression);
}
}
@Override
public void visitMethodReferenceExpression(@NotNull PsiMethodReferenceExpression expression) {
// Necessary to call visitElement, as super-implementation is empty
visitElement(expression);
PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent());
if (toReportFunctionalExpressionProblemOnParent(parent)) return;
PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
if (!hasErrorResults() && PsiTypesUtil.allTypeParametersResolved(expression, functionalInterfaceType)) {
add(LambdaHighlightingUtil.checkFunctionalInterfaceTypeAccessible(myFile.getProject(), expression, functionalInterfaceType));
}
}
}
/**
* @return true for {@code functional_expression;} or {@code var l = functional_expression;}
*/
private static boolean toReportFunctionalExpressionProblemOnParent(@Nullable PsiElement parent) {
if (parent instanceof PsiLocalVariable variable) {
return variable.getTypeElement().isInferredType();
}
return parent instanceof PsiExpressionStatement && !(parent.getParent() instanceof PsiSwitchLabeledRuleStatement);
}
@Override
@@ -293,17 +223,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
private void checkSwitchBlock(@NotNull PsiSwitchBlock switchBlock) {
SwitchBlockHighlightingModel model = SwitchBlockHighlightingModel.createInstance(myLanguageLevel, switchBlock, myFile);
if (model == null) return;
if (!hasErrorResults()) model.checkSwitchLabelValues(myErrorSink);
if (!hasErrorResults()) model.checkSwitchLabelValues(builder -> add(builder));
}
@Override
public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) {
if (!(ref instanceof PsiExpression)) {
JavaResolveResult result = resolveOptimised(ref, myFile);
if (result != null) {
add(HighlightUtil.checkReference(ref, result));
}
}
if (!hasErrorResults()) super.visitReferenceElement(ref);
}
}

View File

@@ -737,10 +737,11 @@ final class JavaErrorFixProvider {
}
private void createAccessFixes() {
JavaFixesPusher<PsiJavaCodeReferenceElement, JavaResolveResult> accessFix = (error, sink) -> {
if (error.context().isStaticsScopeCorrect() && error.context().getElement() instanceof PsiJvmMember member) {
HighlightFixUtil.registerAccessQuickFixAction(sink, member, error.psi(), null);
if (error.psi() instanceof PsiReferenceExpression expression) {
JavaFixesPusher<PsiElement, JavaResolveResult> accessFix = (error, sink) -> {
if (error.psi() instanceof PsiJavaCodeReferenceElement ref &&
error.context().isStaticsScopeCorrect() && error.context().getElement() instanceof PsiJvmMember member) {
HighlightFixUtil.registerAccessQuickFixAction(sink, member, ref, null);
if (ref instanceof PsiReferenceExpression expression) {
sink.accept(myFactory.createRenameWrongRefFix(expression));
}
}
@@ -865,7 +866,7 @@ final class JavaErrorFixProvider {
}
});
fix(CLASS_REFERENCE_LIST_DUPLICATE,
error -> myFactory.createRemoveDuplicateExtendsAction(HighlightUtil.formatClass(error.context())));
error -> myFactory.createRemoveDuplicateExtendsAction(HighlightNamesUtil.formatClass(error.context())));
multi(CLASS_REFERENCE_LIST_INNER_PRIVATE, error -> List.of(
addModifierFix(error.context(), PsiModifier.PUBLIC),
addModifierFix(error.context(), PsiModifier.PROTECTED)));

View File

@@ -2,6 +2,7 @@
package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.codeInsight.daemon.impl.HighlightVisitor;
import com.intellij.java.codeserver.highlighting.JavaErrorCollector;
import com.intellij.openapi.editor.colors.TextAttributesScheme;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbService;
@@ -23,7 +24,7 @@ import java.util.function.Supplier;
* - color names, like "reassigned variables"/fields/statics etc.
* - soft keywords
* NO COMPILATION ERRORS
* for other highlighting errors see {@link HighlightVisitorImpl}
* for other highlighting errors see {@link JavaErrorCollector}
*/
final class JavaNamesHighlightVisitor extends JavaElementVisitor implements HighlightVisitor, DumbAware {
private HighlightInfoHolder myHolder;
@@ -178,7 +179,7 @@ final class JavaNamesHighlightVisitor extends JavaElementVisitor implements High
}
private void doVisitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) {
JavaResolveResult result = HighlightVisitorImpl.resolveOptimised(ref, myFile);
JavaResolveResult result = LocalRefUseInfo.resolveOptimised(ref, myFile);
PsiElement resolved = result != null ? result.getElement() : null;
if (resolved instanceof PsiVariable variable) {

View File

@@ -1,88 +0,0 @@
// 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.JavaModuleSystemEx.ErrorWithFixes;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public final class LambdaHighlightingUtil {
// 15.13 | 15.27
// It is a compile-time error if any class or interface mentioned by either U or the function type of U
// is not accessible from the class or interface in which the method reference expression appears.
static HighlightInfo.Builder checkFunctionalInterfaceTypeAccessible(@NotNull Project project,
@NotNull PsiFunctionalExpression expression,
@NotNull PsiType functionalInterfaceType) {
return checkFunctionalInterfaceTypeAccessible(project, expression, functionalInterfaceType, true);
}
private static HighlightInfo.Builder checkFunctionalInterfaceTypeAccessible(@NotNull Project project, @NotNull PsiFunctionalExpression expression,
@NotNull PsiType functionalInterfaceType,
boolean checkFunctionalTypeSignature) {
PsiClassType.ClassResolveResult resolveResult =
PsiUtil.resolveGenericsClassInType(PsiClassImplUtil.correctType(functionalInterfaceType, expression.getResolveScope()));
PsiClass psiClass = resolveResult.getElement();
if (psiClass == null) {
return null;
}
if (PsiUtil.isAccessible(project, psiClass, expression, null)) {
for (PsiType type : resolveResult.getSubstitutor().getSubstitutionMap().values()) {
if (type != null) {
HighlightInfo.Builder info = checkFunctionalInterfaceTypeAccessible(project, expression, type, false);
if (info != null) {
return info;
}
}
}
PsiMethod psiMethod = checkFunctionalTypeSignature ? LambdaUtil.getFunctionalInterfaceMethod(resolveResult) : null;
if (psiMethod != null) {
PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(psiMethod, resolveResult);
for (PsiParameter parameter : psiMethod.getParameterList().getParameters()) {
PsiType substitute = substitutor.substitute(parameter.getType());
if (substitute != null) {
HighlightInfo.Builder info = checkFunctionalInterfaceTypeAccessible(project, expression, substitute, false);
if (info != null) {
return info;
}
}
}
PsiType substitute = substitutor.substitute(psiMethod.getReturnType());
if (substitute != null) {
return checkFunctionalInterfaceTypeAccessible(project, expression, substitute, false);
}
return null;
}
}
else {
Pair<@Nls String, List<IntentionAction>> problem =
HighlightUtil.accessProblemDescriptionAndFixes(expression, psiClass, resolveResult);
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(problem.first);
if (problem.second != null) {
problem.second.forEach(fix -> info.registerFix(fix, List.of(), null, null, null));
}
return info;
}
final ErrorWithFixes moduleProblem = HighlightUtil.checkModuleAccess(psiClass, expression, resolveResult);
if (moduleProblem != null) {
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(moduleProblem.message);
moduleProblem.fixes.forEach(fix -> info.registerFix(fix, List.of(), null, null, null));
return info;
}
return null;
}
}

View File

@@ -15,6 +15,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.IncompleteModelUtil;
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.*;
import com.intellij.util.ArrayUtilRt;
@@ -246,6 +247,20 @@ public final class LocalRefUseInfo {
return false;
}
static @Nullable JavaResolveResult resolveOptimised(@NotNull PsiJavaCodeReferenceElement ref, @NotNull PsiFile containingFile) {
try {
if (ref instanceof PsiReferenceExpressionImpl) {
PsiReferenceExpressionImpl.OurGenericsResolver resolver = PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE;
JavaResolveResult[] results = JavaResolveUtil.resolveWithContainingFile(ref, resolver, true, true, containingFile);
return results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
}
return ref.advancedResolve(true);
}
catch (IndexNotReadyException e) {
return null;
}
}
private static class Builder extends JavaRecursiveElementWalkingVisitor {
private final @NotNull PsiFile myFile;
private final @NotNull Set<PsiAnchor> myDclsUsedMap;
@@ -399,7 +414,7 @@ public final class LocalRefUseInfo {
public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) {
super.visitReferenceElement(ref);
if (!(ref instanceof PsiImportStaticReferenceElement)) {
JavaResolveResult result = HighlightVisitorImpl.resolveOptimised(ref, myFile);
JavaResolveResult result = resolveOptimised(ref, myFile);
if (result != null) {
registerReference(ref, result);
}
@@ -409,7 +424,7 @@ public final class LocalRefUseInfo {
@Override
public void visitReferenceExpression(@NotNull PsiReferenceExpression ref) {
super.visitReferenceExpression(ref);
JavaResolveResult result = HighlightVisitorImpl.resolveOptimised(ref, myFile);
JavaResolveResult result = resolveOptimised(ref, myFile);
if (result != null) {
registerReference(ref, result);
}

View File

@@ -4,7 +4,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.BlockUtils;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightNamesUtil;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.java.JavaBundle;
import com.intellij.modcommand.ActionContext;
@@ -75,7 +75,7 @@ public class AccessStaticViaInstanceFix extends PsiBasedModCommandAction<PsiRefe
? "access.static.method.via.class.reference.text"
: "access.static.field.via.class.reference.text",
HighlightMessageUtil.getSymbolName(member, substitutor, PsiFormatUtilBase.SHOW_TYPE),
HighlightUtil.formatClass(aClass, false));
HighlightNamesUtil.formatClass(aClass, false));
}
@Override

View File

@@ -2,7 +2,7 @@
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightNamesUtil;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.modcommand.ActionContext;
import com.intellij.modcommand.ModPsiUpdater;
@@ -22,8 +22,8 @@ public class MoveBoundClassToFrontFix extends PsiUpdateModCommandAction<PsiTypeP
PsiClass psiClass = classToExtendFrom.resolve();
myName = QuickFixBundle.message("move.bound.class.to.front.fix.text",
psiClass == null ? "<null>" : HighlightUtil.formatClass(psiClass),
HighlightUtil.formatClass(aClass));
psiClass == null ? "<null>" : HighlightNamesUtil.formatClass(psiClass),
HighlightNamesUtil.formatClass(aClass));
}
@Override

View File

@@ -14,11 +14,9 @@ import com.intellij.java.JavaBundle
import com.intellij.java.codeserver.core.JpmsModuleAccessInfo
import com.intellij.java.codeserver.core.JpmsModuleAccessInfo.JpmsModuleAccessMode
import com.intellij.java.codeserver.core.JpmsModuleAccessInfo.JpmsModuleAccessProblem
import com.intellij.java.codeserver.core.JpmsModuleInfo
import com.intellij.java.codeserver.core.JpmsModuleInfo.TargetModuleInfo
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.pom.java.JavaFeature
import com.intellij.psi.*
import com.intellij.psi.util.PsiUtil
import org.jetbrains.annotations.Nls
/**
@@ -32,13 +30,13 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx {
override fun isAccessible(targetPackageName: String, targetFile: PsiFile?, place: PsiElement): Boolean {
val useFile = place.containingFile?.originalFile ?: return true
val infos = findTargetModuleInfos(targetPackageName, targetFile, useFile) ?: return true
val infos = JpmsModuleInfo.findTargetModuleInfos(targetPackageName, targetFile, useFile) ?: return true
return infos.isNotEmpty() && infos.any { info -> info.accessAt(useFile).checkAccess(useFile, JpmsModuleAccessMode.EXPORT) == null }
}
override fun checkAccess(targetPackageName: String, targetFile: PsiFile?, place: PsiElement): ErrorWithFixes? {
val useFile = place.containingFile?.originalFile ?: return null
val infos = findTargetModuleInfos(targetPackageName, targetFile, useFile) ?: return null
val infos = JpmsModuleInfo.findTargetModuleInfos(targetPackageName, targetFile, useFile) ?: return null
if (infos.isEmpty()) {
return ErrorWithFixes(JavaErrorBundle.message("package.not.found", targetPackageName))
}
@@ -59,36 +57,6 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx {
return TargetModuleInfo(targetModule, "").accessAt(useFile).checkModuleAccess(place) == null
}
private fun findTargetModuleInfos(targetPackageName: String, targetFile: PsiFile?, useFile: PsiFile): List<TargetModuleInfo>? {
val originalTargetFile = targetFile?.originalFile
if (!PsiUtil.isAvailable(JavaFeature.MODULES, useFile)) return null
val useVFile = useFile.virtualFile
val index = ProjectFileIndex.getInstance(useFile.project)
if (useVFile != null && index.isInLibrarySource(useVFile)) return null
if (originalTargetFile != null && originalTargetFile.isPhysical) {
return listOf(TargetModuleInfo(originalTargetFile, targetPackageName))
}
if (useVFile == null) return null
val target = JavaPsiFacade.getInstance(useFile.project).findPackage(targetPackageName) ?: return null
val module = index.getModuleForFile(useVFile) ?: return null
val test = index.isInTestSourceContent(useVFile)
val moduleScope = module.getModuleWithDependenciesAndLibrariesScope(test)
val dirs = target.getDirectories(moduleScope)
val packageName = target.qualifiedName
if (dirs.isEmpty()) {
return if (target.getFiles(moduleScope).isEmpty()) {
listOf()
}
else {
null
}
}
return dirs.map { dir -> TargetModuleInfo(dir, packageName) }
}
fun JpmsModuleAccessInfo.toErrorWithFixes(problem: JpmsModuleAccessProblem, place: PsiElement): ErrorWithFixes {
return ErrorWithFixes(getMessage(problem), getFixes(problem, place))
}

View File

@@ -3,7 +3,7 @@ import test.*;
class Test {
{
I i = <error descr="'test.A' is not public in 'test'. Cannot be accessed from outside package">(a) -> {}</error>;
J j = <error descr="'test.A' is not public in 'test'. Cannot be accessed from outside package">() -> null</error>;
I i = <error descr="'test.A' is not public in 'test'. Cannot be accessed from outside package">(a) -> {};</error>
J j = <error descr="'test.A' is not public in 'test'. Cannot be accessed from outside package">() -> null;</error>
}
}

View File

@@ -10,7 +10,7 @@ class Outer {
class Usage {
void test(Outer outer) {
outer.m(<error descr="'Outer.Inner' has private access in 'Outer'">() -> {}</error>);
outer.m(<error descr="'Outer.Inner' has private access in 'Outer'">this::foo</error>);
outer.m(this::<error descr="'Outer.Inner' has private access in 'Outer'">foo</error>);
}
void foo() {}

View File

@@ -1,4 +1,4 @@
import static <error descr="Static method may only be called on its containing interface">p.Foo.FooEx.foo;</error>
import static p.Foo.FooEx.<error descr="Static method may only be called on its containing interface">foo</error>;
class FooImpl {
public void baz() {

View File

@@ -4,7 +4,7 @@ import java.util.function.Consumer;
class Test {
{
consume(<error descr="'Outer.A' has private access in 'Outer'">o -> {}</error>, new Outer.B(), new Outer.C());
consume(<error descr="'Outer.A' has private access in 'Outer'">Test::foo</error>, new Outer.B(), new Outer.C());
consume(Test::<error descr="'Outer.A' has private access in 'Outer'">foo</error>, new Outer.B(), new Outer.C());
}
private static void foo(Object o) {}

View File

@@ -3,7 +3,7 @@ package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.daemon.Validator;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightNamesUtil;
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.codeInspection.util.InspectionMessage;
import com.intellij.ide.highlighter.JavaFileType;
@@ -611,7 +611,7 @@ public final class JavaFxPsiUtil {
private static boolean unableToCoerceError(@NotNull PsiType targetType, @NotNull PsiClass fromClass,
@NotNull BiConsumer<? super String, ? super Validator.ValidationHost.ErrorType> messageConsumer) {
messageConsumer.accept(
JavaFXBundle.message("unable.to.coerce.error", HighlightUtil.formatClass(fromClass), targetType.getCanonicalText()),
JavaFXBundle.message("unable.to.coerce.error", HighlightNamesUtil.formatClass(fromClass), targetType.getCanonicalText()),
Validator.ValidationHost.ErrorType.ERROR);
return false;
}
@@ -619,7 +619,7 @@ public final class JavaFxPsiUtil {
private static boolean unrelatedTypesWarning(@NotNull PsiType targetType, @NotNull PsiClass fromClass,
@NotNull BiConsumer<? super @InspectionMessage String, ? super Validator.ValidationHost.ErrorType> messageConsumer) {
messageConsumer.accept(
JavaFXBundle.message("conversion.between.unrelated.types.error", HighlightUtil.formatClass(fromClass), targetType.getCanonicalText()),
JavaFXBundle.message("conversion.between.unrelated.types.error", HighlightNamesUtil.formatClass(fromClass), targetType.getCanonicalText()),
Validator.ValidationHost.ErrorType.WARNING);
return true;
}

View File

@@ -5,7 +5,6 @@ package org.jetbrains.kotlin.idea.java
import com.intellij.codeInsight.ClassUtil.getAnyMethodToImplement
import com.intellij.codeInsight.daemon.JavaErrorBundle
import com.intellij.codeInsight.daemon.impl.analysis.HighlightNamesUtil
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil
import com.intellij.codeInsight.intention.QuickFixFactory
import com.intellij.lang.annotation.AnnotationHolder
@@ -77,8 +76,8 @@ class UnimplementedKotlinInterfaceMemberAnnotator : Annotator {
private fun report(method: KtLightMethod, holder: AnnotationHolder, psiClass: PsiClass) {
val key = if (psiClass is PsiEnumConstantInitializer) "enum.constant.should.implement.method" else "class.must.be.abstract"
val message = JavaErrorBundle.message(
key, HighlightUtil.formatClass(psiClass, false), JavaHighlightUtil.formatMethod(method),
HighlightUtil.formatClass(method.containingClass, false)
key, HighlightNamesUtil.formatClass(psiClass, false), JavaHighlightUtil.formatMethod(method),
HighlightNamesUtil.formatClass(method.containingClass, false)
)
val quickFixFactory = QuickFixFactory.getInstance()
var error = holder.newAnnotation(HighlightSeverity.ERROR, message)