[java] improves mandatory module path detection; more package accessibility tests

This commit is contained in:
Roman Shevchenko
2018-07-11 13:19:13 +02:00
parent a23b9e5970
commit 378bd98996
7 changed files with 40 additions and 17 deletions
@@ -13,8 +13,9 @@ import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.JdkOrderEntry
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.vfs.jrt.JrtFileSystem
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightJavaModule
import com.intellij.psi.impl.source.PsiJavaModuleReference
@@ -81,14 +82,24 @@ class JavaPlatformModuleSystem : JavaModuleSystemEx {
return null
}
if (useModule == null && targetModule.containingFile?.virtualFile?.fileSystem !is JrtFileSystem) {
return null // a target is not on the mandatory module path
}
val targetName = targetModule.name
val useName = useModule?.name ?: "ALL-UNNAMED"
val module = place.virtualFile?.let { ProjectFileIndex.getInstance(place.project).getModuleForFile(it) }
if (useModule == null) {
val origin = targetModule.containingFile?.virtualFile
if (origin == null || module == null || ModuleRootManager.getInstance(module).fileIndex.getOrderEntryForFile(origin) !is JdkOrderEntry) {
return null // a target is not on the mandatory module path
}
val root = PsiJavaModuleReference.resolve(place, "java.se", false)
if (!(root == null || JavaModuleGraphUtil.reads(root, targetModule) || inAddedModules(module, targetName))) {
return if (quick) ERR else ErrorWithFixes(
JavaErrorMessages.message("module.access.not.in.graph", packageName, targetName),
listOf(AddModulesOptionFix(module, targetName)))
}
}
if (!(targetModule is LightJavaModule ||
JavaModuleGraphUtil.exports(targetModule, packageName, useModule) ||
module != null && inAddedExports(module, targetName, packageName, useName))) {
@@ -105,16 +116,7 @@ class JavaPlatformModuleSystem : JavaModuleSystemEx {
}
}
if (useModule == null) {
if (!targetName.startsWith("java.")) return null
val root = PsiJavaModuleReference.resolve(place, "java.se", false)
if (root == null || JavaModuleGraphUtil.reads(root, targetModule)) return null
if (module != null && inAddedModules(module, targetName)) return null
val fixes = if (quick || module == null) emptyList() else listOf(AddModulesOptionFix(module, targetName))
return if (quick) ERR else ErrorWithFixes(JavaErrorMessages.message("module.access.not.in.graph", packageName, targetName), fixes)
}
if (!(targetName == PsiJavaModule.JAVA_BASE || JavaModuleGraphUtil.reads(useModule, targetModule))) {
if (useModule != null && !(targetName == PsiJavaModule.JAVA_BASE || JavaModuleGraphUtil.reads(useModule, targetModule))) {
return when {
quick -> ERR
PsiNameHelper.isValidModuleName(targetName, useModule) -> ErrorWithFixes(
@@ -32,7 +32,8 @@ class ModuleCompletionTest : LightJava9ModulesCodeInsightFixtureTestCase() {
fun testStatementsUnambiguous() = complete("module M { requires X; ex<caret> }", "module M { requires X; exports <caret> }")
fun testRequiresBare() =
variants("module M { requires <caret>", "transitive", "static", "M2", "java.base", "lib.multi.release", "lib.named", "lib.auto", "lib.claimed")
variants("module M { requires <caret>",
"transitive", "static", "M2", "java.base", "java.se", "javax.doomed", "lib.multi.release", "lib.named", "lib.auto", "lib.claimed")
fun testRequiresTransitive() = complete("module M { requires tr<caret> }", "module M { requires transitive <caret> }")
fun testRequiresSimpleName() = complete("module M { requires M<caret> }", "module M { requires M2;<caret> }")
fun testRequiresQualifiedName() = complete("module M { requires lib.m<caret> }", "module M { requires lib.multi.release;<caret> }")
@@ -42,7 +43,8 @@ class ModuleCompletionTest : LightJava9ModulesCodeInsightFixtureTestCase() {
fun testExportsQualified() = variants("module M { exports pkg.<caret> }", "main", "other", "empty")
fun testExportsQualifiedUnambiguous() = complete("module M { exports pkg.o<caret> }", "module M { exports pkg.other.<caret> }")
fun testExportsTo() = complete("module M { exports pkg.other <caret> }", "module M { exports pkg.other to <caret> }")
fun testExportsToList() = variants("module M { exports pkg.other to <caret> }", "M2", "java.base", "lib.multi.release", "lib.named")
fun testExportsToList() =
variants("module M { exports pkg.other to <caret> }", "M2", "java.base", "java.se", "javax.doomed", "lib.multi.release", "lib.named")
fun testExportsToUnambiguous() = complete("module M { exports pkg.other to M<caret> }", "module M { exports pkg.other to M2<caret> }")
fun testUsesPrefixed() = complete("module M { uses p<caret> }", "module M { uses pkg.<caret> }")
@@ -295,6 +295,25 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
highlight("test.java", checkFileText, checkFileInTests)
}
fun testPrivateJdkPackage() {
addFile("module-info.java", "module M { }")
highlight("test.java", """
import <error descr="Package 'jdk.internal' is declared in module 'java.base', which does not export it to module 'M'">jdk.internal</error>.*;
""".trimIndent())
}
fun testPrivateJdkPackageFromUnnamed() {
highlight("test.java", """
import <error descr="Package 'jdk.internal' is declared in module 'java.base', which does not export it to the unnamed module">jdk.internal</error>.*;
""".trimIndent())
}
fun testNonRootJdkModule() {
highlight("test.java", """
import <error descr="Package 'javax.doomed' is declared in module 'javax.doomed', which is not in the module graph">javax.doomed</error>.*;
""".trimIndent())
}
fun testLinearModuleGraphBug() {
addFile("module-info.java", "module M6 { requires M7; }", M6)
addFile("module-info.java", "module M7 { }", M7)
Binary file not shown.
Binary file not shown.
Binary file not shown.