mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java, inspection] generate necessary requires for empty module-info.java file. IDEA-341665
GitOrigin-RevId: 47bce7db3bc4429cdfd78bbb3518e8fea1cc80b8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f31f3f2c58
commit
1714ca86b3
+13
-5
@@ -99,7 +99,7 @@ public final class JavaModuleGraphUtil {
|
||||
return CachedValuesManager.getCachedValue(rootPsi, () -> {
|
||||
VirtualFile _root = rootPsi.getVirtualFile();
|
||||
LightJavaModule result = LightJavaModule.create(rootPsi.getManager(), _root, LightJavaModule.moduleName(_root));
|
||||
return Result.create(result, _root, ProjectRootModificationTracker.getInstance(rootPsi.getProject()));
|
||||
return Result.create(result, _root, ProjectRootModificationTracker.getInstance(rootPsi.getProject()));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -169,7 +169,7 @@ public final class JavaModuleGraphUtil {
|
||||
List<VirtualFile> roots = new ArrayList<>(rootManager.getSourceRoots(resourceRootType));
|
||||
roots.addAll(sourceRoots);
|
||||
files = ContainerUtil.mapNotNull(roots, root -> root.findFileByRelativePath(JarFile.MANIFEST_NAME));
|
||||
if (files.size() == 1) {
|
||||
if (files.size() == 1 || new HashSet<>(files).size() == 1) {
|
||||
VirtualFile manifest = files.get(0);
|
||||
PsiFile manifestPsi = PsiManager.getInstance(project).findFile(manifest);
|
||||
assert manifestPsi != null : manifest;
|
||||
@@ -184,7 +184,8 @@ public final class JavaModuleGraphUtil {
|
||||
if (virtualAutoModuleName != null && !sourceSourceRoots.isEmpty()) {
|
||||
return LightJavaModule.create(PsiManager.getInstance(project), sourceSourceRoots.get(0), virtualAutoModuleName);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
final VirtualFile file = files.get(0);
|
||||
if (ContainerUtil.and(files, f -> f.equals(file))) {
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
|
||||
@@ -257,7 +258,7 @@ public final class JavaModuleGraphUtil {
|
||||
}
|
||||
|
||||
private static boolean isExported(@NotNull PsiJavaModule from, @NotNull PsiJavaModule to) {
|
||||
VirtualFile toFile = to.getContainingFile().getVirtualFile();
|
||||
VirtualFile toFile = getVirtualFile(to);
|
||||
if (toFile == null) return false;
|
||||
|
||||
Module fromModule = ModuleUtilCore.findModuleForPsiElement(from);
|
||||
@@ -276,6 +277,13 @@ public final class JavaModuleGraphUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile getVirtualFile(@NotNull PsiJavaModule module) {
|
||||
if (module instanceof LightJavaModule light) {
|
||||
return light.getRootVirtualFile();
|
||||
}
|
||||
return PsiUtilCore.getVirtualFile(module);
|
||||
}
|
||||
|
||||
private static boolean alreadyContainsRequires(@NotNull PsiJavaModule module, @NotNull String dependency) {
|
||||
for (PsiRequiresStatement requiresStatement : module.getRequires()) {
|
||||
@@ -306,7 +314,7 @@ public final class JavaModuleGraphUtil {
|
||||
|
||||
if (descriptors.size() == 2) {
|
||||
if (descriptors.stream()
|
||||
.map(d -> PsiUtilCore.getVirtualFile(d))
|
||||
.map(d -> getVirtualFile(d))
|
||||
.filter(Objects::nonNull)
|
||||
.map(moduleRootManager.getFileIndex()::isInTestSourceContent).count() < 2) {
|
||||
return Collections.emptyList();
|
||||
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
// 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.codeInspection.java19api;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.roots.DependencyScope;
|
||||
import com.intellij.openapi.roots.ModuleFileIndex;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.psi.JavaTokenType.LBRACE;
|
||||
import static com.intellij.psi.JavaTokenType.RBRACE;
|
||||
import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
|
||||
|
||||
public class JavaEmptyModuleInfoFileInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
private static final Set<String> JVM_LANGUAGES = Set.of("java", "kt", "kts", "groovy");
|
||||
|
||||
@Override
|
||||
public ProblemDescriptor @Nullable [] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
if (!PsiUtil.isAvailable(JavaFeature.MODULES, file)) return ProblemDescriptor.EMPTY_ARRAY;
|
||||
if (!file.getName().equals(MODULE_INFO_FILE)) return ProblemDescriptor.EMPTY_ARRAY;
|
||||
if (!(file instanceof PsiJavaFile javaFile)) return ProblemDescriptor.EMPTY_ARRAY;
|
||||
|
||||
PsiJavaModule descriptor = javaFile.getModuleDeclaration();
|
||||
if (descriptor == null) return ProblemDescriptor.EMPTY_ARRAY;
|
||||
|
||||
if (!isEmptyModule(descriptor)) return ProblemDescriptor.EMPTY_ARRAY;
|
||||
if (!needRequires(descriptor)) return ProblemDescriptor.EMPTY_ARRAY;
|
||||
|
||||
ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
|
||||
file,
|
||||
JavaBundle.message("inspection.unresolved.module.dependencies.problem.descriptor"),
|
||||
isOnTheFly,
|
||||
LocalQuickFix.notNullElements(new GenerateModuleInfoRequiresFix()),
|
||||
ProblemHighlightType.WARNING
|
||||
);
|
||||
return new ProblemDescriptor[]{problemDescriptor};
|
||||
}
|
||||
|
||||
private static class GenerateModuleInfoRequiresFix extends PsiUpdateModCommandQuickFix {
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return JavaBundle.message("inspection.auto.add.module.requirements.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
|
||||
if (!(element instanceof PsiJavaFile psiJavaFile)) return;
|
||||
PsiJavaModule descriptor = psiJavaFile.getModuleDeclaration();
|
||||
if (descriptor == null) return;
|
||||
Set<PsiJavaModule> modules = walk(descriptor, stmt -> true);
|
||||
|
||||
if (modules.isEmpty()) {
|
||||
PsiElement content = getStartContentElement(descriptor);
|
||||
PsiElement newLine = PsiParserFacade.getInstance(element.getProject())
|
||||
.createWhiteSpaceFromText("\n");
|
||||
PsiComment comment = JavaPsiFacade.getElementFactory(element.getProject())
|
||||
.createCommentFromText("// no dependencies", null);
|
||||
descriptor.addAfter(comment, content);
|
||||
descriptor.addAfter(newLine, content);
|
||||
}
|
||||
else {
|
||||
DependencyScope scope = getScope(descriptor);
|
||||
for (PsiJavaModule target : modules) {
|
||||
JavaModuleGraphUtil.addDependency(descriptor, target, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isEmptyModule(@NotNull PsiJavaModule module) {
|
||||
PsiElement element = getStartContentElement(module);
|
||||
if (element == null) return false;
|
||||
while ((element = element.getNextSibling()) != null) {
|
||||
if (element.getNode().getElementType() == RBRACE) return true;
|
||||
if (!(element instanceof PsiWhiteSpace)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean needRequires(@NotNull PsiJavaModule descriptor) {
|
||||
Set<PsiJavaModule> modules = walk(descriptor, psiJavaModule -> psiJavaModule.getName().equals(descriptor.getName()));
|
||||
return !modules.isEmpty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement getStartContentElement(@NotNull PsiJavaModule module) {
|
||||
PsiElement[] children = module.getChildren();
|
||||
for (PsiElement child : children) {
|
||||
if (child.getNode().getElementType() == LBRACE) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Set<PsiJavaModule> walk(@NotNull PsiJavaModule descriptor,
|
||||
@NotNull Function<@NotNull PsiJavaModule, @NotNull Boolean> function) {
|
||||
PsiFile descriptorFile = descriptor.getContainingFile().getOriginalFile();
|
||||
Module module = ModuleUtilCore.findModuleForFile(descriptorFile);
|
||||
if (module == null) return Set.of();
|
||||
|
||||
PsiManager psiManager = PsiManager.getInstance(module.getProject());
|
||||
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
|
||||
ModuleFileIndex fileIndex = rootManager.getFileIndex();
|
||||
|
||||
// collect descriptors
|
||||
Map<PsiImportStatement, PsiJavaModule> imports = new ConcurrentHashMap<>();
|
||||
ImportsCollector collector = new ImportsCollector(psiManager, statement -> {
|
||||
PsiJavaModule result = imports.computeIfAbsent(statement, stmt -> findDescriptor(stmt.resolve()));
|
||||
return result == null || function.apply(result);
|
||||
});
|
||||
DependencyScope scope = getScope(descriptor);
|
||||
for (VirtualFile root : rootManager.getSourceRoots()) {
|
||||
DependencyScope currentScope = fileIndex.isInTestSourceContent(root) ? DependencyScope.TEST : DependencyScope.COMPILE;
|
||||
if (currentScope == scope) {
|
||||
VfsUtilCore.iterateChildrenRecursively(root, file -> file.isDirectory() ||
|
||||
(file.getExtension() != null && JVM_LANGUAGES.contains(file.getExtension())),
|
||||
collector);
|
||||
}
|
||||
}
|
||||
|
||||
// clean descriptors
|
||||
return imports.values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(m -> !m.getName().equals(descriptor.getName()))
|
||||
.collect(Collectors.toCollection(() -> new TreeSet<>((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()))));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static DependencyScope getScope(@NotNull PsiJavaModule descriptor) {
|
||||
PsiFile file = descriptor.getContainingFile().getOriginalFile();
|
||||
Module module = ModuleUtilCore.findModuleForFile(file);
|
||||
if (module == null) return DependencyScope.COMPILE;
|
||||
|
||||
return ModuleRootManager.getInstance(module).getFileIndex()
|
||||
.isInTestSourceContent(file.getVirtualFile())
|
||||
? DependencyScope.TEST
|
||||
: DependencyScope.COMPILE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiJavaModule findDescriptor(@Nullable PsiElement psiElement) {
|
||||
if (psiElement == null) return null;
|
||||
if (psiElement instanceof PsiPackage psiPackage) {
|
||||
PsiDirectory[] directories = psiPackage.getDirectories(psiPackage.getResolveScope());
|
||||
for (PsiDirectory directory : directories) {
|
||||
PsiJavaModule descriptor = JavaModuleGraphUtil.findDescriptorByElement(directory);
|
||||
if (descriptor != null) return descriptor;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return JavaModuleGraphUtil.findDescriptorByElement(psiElement);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ImportsCollector implements ContentIterator {
|
||||
@NotNull
|
||||
private final PsiManager myPsiManager;
|
||||
@NotNull
|
||||
private final Function<PsiImportStatement, Boolean> myFunction;
|
||||
|
||||
private ImportsCollector(@NotNull PsiManager manager, @NotNull Function<PsiImportStatement, Boolean> function) {
|
||||
myPsiManager = manager;
|
||||
myFunction = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processFile(@NotNull VirtualFile fileOrDir) {
|
||||
PsiFile file = myPsiManager.findFile(fileOrDir);
|
||||
if (file == null) return true;
|
||||
if (file instanceof PsiJavaFile javaFile) {
|
||||
PsiImportList imports = javaFile.getImportList();
|
||||
if (imports == null) return true;
|
||||
for (PsiImportStatement importStatement : imports.getImportStatements()) {
|
||||
if (!myFunction.apply(importStatement)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1907,6 +1907,11 @@
|
||||
enabledByDefault="true" level="WARNING"
|
||||
key="inspection.undeclared.service.usage.name" bundle="messages.JavaBundle"
|
||||
implementationClass="com.intellij.codeInspection.java19api.Java9UndeclaredServiceUsageInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="JavaEmptyModuleInfoFile"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.visibility.issues"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
key="inspection.empty.module.info.file" bundle="messages.JavaBundle"
|
||||
implementationClass="com.intellij.codeInspection.java19api.JavaEmptyModuleInfoFileInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="RedundantComparatorComparing"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.verbose.or.redundant.code.constructs"
|
||||
enabledByDefault="true" level="WARNING" editorAttributes="NOT_USED_ELEMENT_ATTRIBUTES"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<body>
|
||||
Reports an empty <code>module-info.java</code> file, indicating unresolved module dependencies. Automatically adds necessary <code>requires</code> statements by inspecting imports.
|
||||
To suppress this warning, include the following in <code>module-info.java</code>:
|
||||
<pre><code>
|
||||
module module.name {
|
||||
// no dependencies
|
||||
}
|
||||
</code></pre>
|
||||
<b>Quick Fix:</b> <i>Auto-add module requirements</i> fills in missing <code>requires</code> based on source code imports.
|
||||
<small>New in 2024.1</small>
|
||||
</body>
|
||||
Binary file not shown.
Binary file not shown.
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/main/main.iml" filepath="$PROJECT_DIR$/main/main.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/b/b.iml" filepath="$PROJECT_DIR$/b/b.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/c/c.iml" filepath="$PROJECT_DIR$/c/c.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/d/d.iml" filepath="$PROJECT_DIR$/d/d.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../../lib/lib.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package b;
|
||||
|
||||
public class UtilB {
|
||||
public static String name() {
|
||||
return "B";
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module module.b {
|
||||
exports b;
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
Automatic-Module-Name: module.c
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package c;
|
||||
|
||||
public class UtilC {
|
||||
public static String name() {
|
||||
return "C";
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
module module.c {
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package d;
|
||||
|
||||
public class UtilD {
|
||||
public static String name() {
|
||||
return "D";
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package a;
|
||||
|
||||
import b.*;
|
||||
import c.*;
|
||||
import d.*;
|
||||
import l.*;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
module module.a {
|
||||
requires lib;
|
||||
requires module.b;
|
||||
requires module.c;
|
||||
}
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/main/main.iml" filepath="$PROJECT_DIR$/main/main.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/b/b.iml" filepath="$PROJECT_DIR$/b/b.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/c/c.iml" filepath="$PROJECT_DIR$/c/c.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/d/d.iml" filepath="$PROJECT_DIR$/d/d.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../../lib/lib.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package b;
|
||||
|
||||
public class UtilB {
|
||||
public static String name() {
|
||||
return "B";
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module module.b {
|
||||
exports b;
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
Automatic-Module-Name: module.c
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package c;
|
||||
|
||||
public class UtilC {
|
||||
public static String name() {
|
||||
return "C";
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package d;
|
||||
|
||||
public class UtilD {
|
||||
public static String name() {
|
||||
return "D";
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package a;
|
||||
|
||||
import b.*;
|
||||
import c.*;
|
||||
import d.*;
|
||||
import l.*;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
<warning descr="Unresolved module dependencies">module module.a {
|
||||
}</warning>
|
||||
java/java-tests/testData/inspection/emptyModuleInfoFile/singleLibraryDependency/after/.idea/misc.xml
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/main.iml" filepath="$PROJECT_DIR$/main.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../lib/lib.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" scope="TEST">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../lib/test.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import l.InLib;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(InLib.class);
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module main {
|
||||
requires lib;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import org.jetbrains.org.jetbrains.intellij.java.test.library.*;
|
||||
|
||||
public class MainTest {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Util.name());
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module main {
|
||||
requires intellij.java.test.library;
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/main.iml" filepath="$PROJECT_DIR$/main.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../lib/lib.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" scope="TEST">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../lib/test.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import l.InLib;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(InLib.class);
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
<warning descr="Unresolved module dependencies">module main {
|
||||
}</warning>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import org.jetbrains.org.jetbrains.intellij.java.test.library.*;
|
||||
|
||||
public class MainTest {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Util.name());
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
<warning descr="Unresolved module dependencies">module main {
|
||||
}</warning>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/main.iml" filepath="$PROJECT_DIR$/main.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("test");
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
module main {
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("test");
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
module main {
|
||||
}
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/main.iml" filepath="$PROJECT_DIR$/main.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("test");
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
module main {
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("test");
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
module main {
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// 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.java.codeInspection.java19api;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInspection.java19api.JavaEmptyModuleInfoFileInspection;
|
||||
import com.intellij.java.testFramework.fixtures.MultiModuleProjectDescriptor;
|
||||
import com.intellij.openapi.application.impl.NonBlockingReadActionImpl;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.refactoring.LightMultiFileTestCase;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.util.LazyInitializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class JavaEmptyModuleInfoFileInspectionTest extends LightMultiFileTestCase {
|
||||
private final LazyInitializer.LazyValue<MultiModuleProjectDescriptor> myDescriptor = new LazyInitializer.LazyValue<>(() -> {
|
||||
MultiModuleProjectDescriptor value =
|
||||
new MultiModuleProjectDescriptor(Paths.get(getTestDataPath() + "/" + getTestName(true)), "main", null);
|
||||
Path lib = value.getProjectPath().getParent().getParent().resolve("lib");
|
||||
Path beforeLib = value.getBeforePath().getParent().getParent().resolve("lib");
|
||||
try {
|
||||
FileUtilRt.deleteRecursively(lib);
|
||||
FileUtil.copyDir(beforeLib.toFile(), lib.toFile());
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
Assert.fail("Failed to copy lib files");
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
@Override
|
||||
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
|
||||
return myDescriptor.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/inspection/emptyModuleInfoFile";
|
||||
}
|
||||
|
||||
public void testSingleLibraryDependency() {
|
||||
doTest("src/module-info.java");
|
||||
doTest("test/module-info.java");
|
||||
}
|
||||
|
||||
public void testSingleModule() {
|
||||
doTest("src/module-info.java");
|
||||
doTest("test/module-info.java");
|
||||
}
|
||||
|
||||
public void testMultiModuleProject() {
|
||||
doTest("src/module-info.java", "main/");
|
||||
}
|
||||
|
||||
private void doTest(@NotNull String path) {
|
||||
doTest(path, "");
|
||||
}
|
||||
|
||||
private void doTest(@NotNull String path, @NotNull String dir) {
|
||||
VirtualFile file = getModule().getModuleFile().getParent().findFileByRelativePath(path);
|
||||
myFixture.configureFromExistingVirtualFile(file);
|
||||
|
||||
JavaEmptyModuleInfoFileInspection inspection = new JavaEmptyModuleInfoFileInspection();
|
||||
myFixture.enableInspections(inspection);
|
||||
myFixture.testHighlighting(true, false, false, file);
|
||||
|
||||
IntentionAction intention = myFixture.getAvailableIntention("Auto-add module requirements");
|
||||
if (intention != null) {
|
||||
myFixture.launchAction(intention);
|
||||
NonBlockingReadActionImpl.waitForAsyncTaskCompletion();
|
||||
}
|
||||
myFixture.checkResultByFile(getTestName(false) + "/after/" + dir + path);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -59,7 +59,7 @@ public class MultiModuleProjectDescriptor extends DefaultLightProjectDescriptor
|
||||
myPath = path;
|
||||
myMainModuleName = mainModuleName;
|
||||
myProcess = process;
|
||||
myProjectPath = TemporaryDirectory.generateTemporaryPath(ProjectImpl.LIGHT_PROJECT_NAME);
|
||||
myProjectPath = TemporaryDirectory.generateTemporaryPath("project/before/" + ProjectImpl.LIGHT_PROJECT_NAME);
|
||||
}
|
||||
|
||||
public Path getBeforePath() {
|
||||
|
||||
@@ -798,6 +798,9 @@ inspection.unused.symbol.check.localvars=Local variables
|
||||
inspection.unused.symbol.check.methods=Methods:
|
||||
inspection.unused.symbol.check.parameters=Parameters in
|
||||
inspection.unused.symbol.check.parameters.excluding.hierarchy=Excluding hierarchy
|
||||
inspection.empty.module.info.file=Empty 'module-info.java' file
|
||||
inspection.unresolved.module.dependencies.problem.descriptor=Unresolved module dependencies
|
||||
inspection.auto.add.module.requirements.quickfix=Auto-add module requirements
|
||||
inspection.value.based.warnings=Value-based warnings
|
||||
inspection.preview.feature=Preview Feature warning
|
||||
inspection.value.based.warnings.synchronization=Attempt to synchronize on an instance of a value-based class
|
||||
|
||||
Reference in New Issue
Block a user