[java-highlighting] WIP IDEA-372969 Support JEP 512: Compact Source Files and Instance Main Methods

- update language levels partially
- fix tests

(cherry picked from commit 8d7b599772eda8dfd999bee9f816ec2609be4adb)


(cherry picked from commit 98a507ba78b8fc496651b5800fc3936c9c87b689)

IJ-MR-169535

GitOrigin-RevId: 898e8b4dfc303eb60da6cfff5d756304c461c424
This commit is contained in:
Mikhail Pyltsin
2025-06-20 22:02:29 +02:00
committed by intellij-monorepo-bot
parent 2111b032dc
commit 26de6fc1df
41 changed files with 121 additions and 67 deletions

View File

@@ -95,8 +95,26 @@ enum class JavaFeature {
}
},
//jep 463,477
IMPLICIT_CLASSES(LanguageLevel.JDK_21_PREVIEW, "feature.implicit.classes"),
INSTANCE_MAIN_METHOD(LanguageLevel.JDK_21_PREVIEW, "feature.instance.main.method"),
//todo change everything related to implicit_classes
IMPLICIT_CLASSES(LanguageLevel.JDK_25, "feature.implicit.classes") {
override fun isSufficient(useSiteLevel: LanguageLevel): Boolean {
return super.isSufficient(useSiteLevel) ||
LanguageLevel.JDK_21_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_22_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_23_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_24_PREVIEW == useSiteLevel
}
},
//todo change everything related to implicit_classes
INSTANCE_MAIN_METHOD(LanguageLevel.JDK_25, "feature.instance.main.method") {
override fun isSufficient(useSiteLevel: LanguageLevel): Boolean {
return super.isSufficient(useSiteLevel) ||
LanguageLevel.JDK_21_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_22_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_23_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_24_PREVIEW == useSiteLevel
}
},
SCOPED_VALUES(LanguageLevel.JDK_21_PREVIEW, "feature.scoped.values"),
STRUCTURED_CONCURRENCY(LanguageLevel.JDK_21_PREVIEW, "feature.structured.concurrency"),
@@ -108,7 +126,16 @@ enum class JavaFeature {
STRUCTURED_CONCURRENCY_TASK_SCOPE_STATIC_FACTORY_METHODS(LanguageLevel.JDK_25_PREVIEW, "feature.structured.concurrency.static.factory.methods"),
IMPLICIT_CLASS_NAME_OUT_OF_SCOPE(LanguageLevel.JDK_22_PREVIEW, "feature.implicit.class.name.out.of.scope"),
//todo change everything related to implicit_classes
IMPLICIT_CLASS_NAME_OUT_OF_SCOPE(LanguageLevel.JDK_25, "feature.implicit.class.name.out.of.scope"){
override fun isSufficient(useSiteLevel: LanguageLevel): Boolean {
return super.isSufficient(useSiteLevel) ||
LanguageLevel.JDK_22_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_23_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_24_PREVIEW == useSiteLevel
}
},
CLASSFILE_API(LanguageLevel.JDK_22_PREVIEW, "feature.classfile.api"),
STREAM_GATHERERS(LanguageLevel.JDK_22_PREVIEW, "feature.stream.gatherers"),
STATEMENTS_BEFORE_SUPER(LanguageLevel.JDK_22_PREVIEW, "feature.statements.before.super") {
@@ -125,7 +152,14 @@ enum class JavaFeature {
//jep 463,477
INHERITED_STATIC_MAIN_METHOD(LanguageLevel.JDK_22_PREVIEW, "feature.inherited.static.main.method"),
IMPLICIT_IMPORT_IN_IMPLICIT_CLASSES(LanguageLevel.JDK_23_PREVIEW, "feature.implicit.import.in.implicit.classes"),
//todo change everything related to implicit_classes
IMPLICIT_IMPORT_IN_IMPLICIT_CLASSES(LanguageLevel.JDK_25, "feature.implicit.import.in.implicit.classes"){
override fun isSufficient(useSiteLevel: LanguageLevel): Boolean {
return super.isSufficient(useSiteLevel) ||
LanguageLevel.JDK_23_PREVIEW == useSiteLevel ||
LanguageLevel.JDK_24_PREVIEW == useSiteLevel
}
},
//JEP 507
PRIMITIVE_TYPES_IN_PATTERNS(LanguageLevel.JDK_23_PREVIEW, "feature.primitive.types.in.patterns"),

View File

@@ -1,5 +1,5 @@
class Devk1 {
public void main(String args[]) {
public void main() {
foo();
}

View File

@@ -1,5 +1,5 @@
class Devk1 {
public void main(String args[]) {
public void main() {
foo();
}

View File

@@ -5,7 +5,7 @@ interface Func<TIn, TOut>{
class Main {
public static void main(final String[] args) {
public static void main() {
Func<Integer, String> func = Integer::<error descr="Reference to 'toString' is ambiguous, both 'toString()' and 'toString(int)' match">toString</error>;
System.out.println(func.run(6));
}

View File

@@ -28,7 +28,7 @@ class MyTest {
System.out.println(i);
}
public static void main(String[] args) {
public static void main() {
foo<error descr="Ambiguous method call: both 'MyTest.foo(I1)' and 'MyTest.foo(I2)' match">(Foo::m)</error>;
}
}
@@ -66,7 +66,7 @@ class MyTest1 {
System.out.println(i);
}
public static void main(String[] args) {
public static void main() {
m<error descr="Ambiguous method call: both 'MyTest1.m(I1)' and 'MyTest1.m(I2)' match">(Foo::new)</error>;
}
}
@@ -103,7 +103,7 @@ class MyTest2 {
System.out.println(i);
}
public static void main(String[] args) {
public static void main() {
m<error descr="Ambiguous method call: both 'MyTest2.m(I1)' and 'MyTest2.m(I2)' match">(Foo::new)</error>;
}
}

View File

@@ -1,6 +1,6 @@
class App {
public static void main(String[] args) {
public static void main() {
test(App::getLength);
}

View File

@@ -11,7 +11,7 @@ class Main {
public static void caller(MyCallRet c) {
c.call(3);
}
public static void main(String[] args) {
public static void main() {
caller( (int n) -> { System.out.println(" " + n); } );
}
}

View File

@@ -10,7 +10,7 @@ class Test {
System.out.println(i);
}
public static void main(String[] args) {
public static void main() {
call(()-> null);
}
}

View File

@@ -12,7 +12,7 @@ class Test {
System.out.println(callable);
}
public static void main(String[] args) {
public static void main() {
final Collection<Void> collection = new ArrayList<>();
final Iterable<Void> iterable = collection;
foo(iterable::iterator);

View File

@@ -1,7 +1,7 @@
import java.util.function.Consumer;
class Test {
public static void main(String[] args) {
public static void main() {
Consumer<String> ref = Test::method;
System.out.println(ref);
}

View File

@@ -15,7 +15,7 @@ class BBB {
return null;
}
public static void main(String[] args) {
public static void main() {
f();
}
}

View File

@@ -11,7 +11,7 @@ class TestIntelliJ<T, S extends List<T>> extends SubInterface<T, S> {
return t;
}
public static void main(String... args) {
public static void main() {
TestIntelliJ<String, List<String>> testIntelliJ = new TestIntelliJ<>();
testIntelliJ.test(testIntelliJ);
}

View File

@@ -20,7 +20,7 @@ class Test {
private <T> void process(handler<T> <warning descr="Parameter 'h' is never used">h</warning>) {}
public static void main(String[] args) {
public static void main() {
Test t = new Test();
t.<Message<Result<String>>>process(m -> {
if (m.data.isSuccessful());

View File

@@ -9,7 +9,7 @@ class Test {
System.out.println(objs);
}
public static void main(String[] args) {
public static void main() {
test(String.class, new Runnable[1]);
}
}

View File

@@ -38,7 +38,7 @@ class GenericsError {
}
public static void main(final String[] args) {
public static void main() {
final ListHolder<? extends B> aListHolder = new ListHolder<B>();
final DeletingLooper<? super B> bLooper = new MyDeletingLooper();

View File

@@ -12,7 +12,7 @@ class Main {
System.out.println("Integer... x");
}
public static void main(String[] args) {
public static void main() {
int i = 0;
Integer i2 = 127;
var<error descr="Ambiguous method call: both 'Main.var(int...)' and 'Main.var(Integer...)' match">(i, i2)</error>;

View File

@@ -10,7 +10,7 @@ class Test {
static class IJ implements I, J {}
static class JI implements J, I {}
public static void main(String[] args) {
public static void main() {
new IJ(). f();
new JI(). f();

View File

@@ -4,7 +4,7 @@ class Test {
public void test(int... <warning descr="Parameter 'a' is never used">a</warning>){}
public static void main(String[] args) {
public static void main() {
new Test().test<error descr="Ambiguous method call: both 'Test.test(String...)' and 'Test.test(int...)' match">()</error>;
}
}

View File

@@ -11,7 +11,7 @@ class Foo {
return super.toString();
}
public static void main(String[] args) {
public static void main() {
System.out.println(new Foo().go());
}
}

View File

@@ -34,7 +34,7 @@ class Test {
System.out.println(s);
}
public static void main(String[] args) {
public static void main() {
method(() -> {
voids("-> B");

View File

@@ -1,3 +1,3 @@
<warning descr="Modifier 'public' is redundant for 'main' method on Java 23-preview">public</warning> <warning descr="Modifier 'static' is redundant for 'main' method on Java 23-preview">static</warning> void main(String[] args) {
<warning descr="Modifier 'public' is redundant for 'main' method on Java 25">public</warning> <warning descr="Modifier 'static' is redundant for 'main' method on Java 25">static</warning> void main(String[] args) {
System.out.println("Hello World!");
}

View File

@@ -1,7 +1,7 @@
package test;
public class NormalClassWithModifiers {
<warning descr="Modifier 'public' is redundant for 'main' method on Java 23-preview">public</warning> static void main(String[] args) {
<warning descr="Modifier 'public' is redundant for 'main' method on Java 25">public</warning> static void main(String[] args) {
System.out.println("Hello World!");
}

View File

@@ -3,10 +3,16 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
import com.intellij.pom.java.LanguageLevel;
public class RemoveUnusedParameterTest extends LightQuickFixParameterizedTestCase {
@Override
protected LanguageLevel getLanguageLevel() {
return LanguageLevel.JDK_24;
}
@Override
protected void setUp() throws Exception {
super.setUp();

View File

@@ -37,10 +37,12 @@ import com.intellij.openapi.options.advanced.AdvancedSettingsImpl;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.statistics.StatisticsManager;
import com.intellij.psi.statistics.impl.StatisticsManagerImpl;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.NeedsIndex;
import com.intellij.testFramework.common.ThreadUtil;
import com.intellij.testFramework.fixtures.CodeInsightTestUtil;
@@ -1515,11 +1517,13 @@ public class JavaAutoPopupTest extends JavaCompletionAutoPopupTestCase {
}
public void testQuickBackspaceEnter() {
myFixture.configureByText("a.java", "<caret>");
type("cl");
assertEquals(myFixture.getLookupElementStrings(), List.of("class"));
myFixture.type("\b\n");
myFixture.checkResult("class <caret>");
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, () -> {
myFixture.configureByText("a.java", "<caret>");
type("cl");
assertEquals(myFixture.getLookupElementStrings(), List.of("class"));
myFixture.type("\b\n");
myFixture.checkResult("class <caret>");
});
}
public void test_new_primitive_array_in_Object_variable() {

View File

@@ -13,7 +13,7 @@ import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
import org.jetbrains.plugins.groovy.intentions.style.inference.resolve
class ImplicitClassHighlightingTest : LightJavaCodeInsightFixtureTestCase() {
override fun getProjectDescriptor() = JAVA_23
override fun getProjectDescriptor() = JAVA_LATEST_WITH_LATEST_JDK
override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/implicitClass"
fun testHighlightInsufficientLevel() {
@@ -108,7 +108,7 @@ class ImplicitClassHighlightingTest : LightJavaCodeInsightFixtureTestCase() {
}
fun testImplicitWithPackages() {
IdeaTestUtil.withLevel(module, JavaFeature.IMPLICIT_IMPORT_IN_IMPLICIT_CLASSES.minimumLevel, Runnable {
IdeaTestUtil.withLevel(module, LanguageLevel.JDK_23_PREVIEW, Runnable {
myFixture.addClass("""
package a.b;

View File

@@ -29,11 +29,13 @@ import com.intellij.openapi.util.RecursionManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.testFramework.DumbModeTestUtils;
import com.intellij.testFramework.EdtTestUtil;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
import com.intellij.testFramework.fixtures.CodeInsightTestUtil;
import com.intellij.util.DocumentUtil;
@@ -356,17 +358,20 @@ public class LiveTemplateTest extends LiveTemplateTestCase {
}
public void testOtherContext() {
configureFromFileText("a.java", "class Foo { <caret>xxx }");
Set<TemplateContextType> types =
TemplateManagerImpl.getApplicableContextTypes(TemplateActionContext.expanding(myFixture.getFile(), getEditor()));
assertEquals(2, types.size());
assertTrue(types.contains(TemplateContextTypes.getByClass(JavaCodeContextType.Declaration.class)));
assertTrue(types.contains(TemplateContextTypes.getByClass(JavaCodeContextType.NormalClassDeclarationBeforeShortMainMethod.class)));
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, () -> {
configureFromFileText("a.txt", "class Foo { <caret>xxx }");
assertInstanceOf(assertOneElement(
TemplateManagerImpl.getApplicableContextTypes(TemplateActionContext.expanding(myFixture.getFile(), getEditor()))),
EverywhereContextType.class);
configureFromFileText("a.java", "class Foo { <caret>xxx }");
Set<TemplateContextType> types =
TemplateManagerImpl.getApplicableContextTypes(TemplateActionContext.expanding(myFixture.getFile(), getEditor()));
assertEquals(2, types.size());
assertTrue(types.contains(TemplateContextTypes.getByClass(JavaCodeContextType.Declaration.class)));
assertTrue(types.contains(TemplateContextTypes.getByClass(JavaCodeContextType.NormalClassDeclarationBeforeShortMainMethod.class)));
configureFromFileText("a.txt", "class Foo { <caret>xxx }");
assertInstanceOf(assertOneElement(
TemplateManagerImpl.getApplicableContextTypes(TemplateActionContext.expanding(myFixture.getFile(), getEditor()))),
EverywhereContextType.class);
});
}
public void testJavaOtherContext() {
@@ -464,10 +469,12 @@ public class LiveTemplateTest extends LiveTemplateTestCase {
}
public void testListTemplatesSearchesPrefixInDescription() {
myFixture.configureByText("a.java", "class A { main<caret> }");
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, () -> {
myFixture.configureByText("a.java", "class A { main<caret> }");
new ListTemplatesHandler().invoke(getProject(), getEditor(), myFixture.getFile());
assertEquals(List.of("main", "psvm"), myFixture.getLookupElementStrings());
new ListTemplatesHandler().invoke(getProject(), getEditor(), myFixture.getFile());
assertEquals(List.of("main", "psvm"), myFixture.getLookupElementStrings());
});
}
public void testListTemplatesAction() {

View File

@@ -231,7 +231,7 @@ public class TemplatesCompletionTest extends JavaCompletionAutoPopupTestCase {
myFixture.configureByText("a.java", "class Foo { ps<caret> } class psvClass {}");
type("v");
myFixture.assertPreferredCompletionItems(0, "psvm", "psvClass");
myFixture.assertPreferredCompletionItems(0, "psvm", "psvma", "psvClass");
myFixture.configureByText("a.xml", "CARBON C<caret>");
myFixture.completeBasic();

View File

@@ -70,7 +70,7 @@ class UnusedDeclarationClassPatternsTest : LightJavaCodeInsightFixtureTestCase()
val patterns = EntryPointsManagerBase.getInstance(project).patterns
try {
patterns.add(classPattern)
myFixture.configureByText("C.java", "public abstract class C { void fooBar() {} public static void main(String[] args) {}}")
myFixture.configureByText("C.java", "public abstract class C { void fooBar() {} public static void main() {}}")
myFixture.checkHighlighting()
}
finally {

View File

@@ -13,6 +13,7 @@ import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.pom.java.JavaFeature;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
@@ -376,7 +377,7 @@ public class ResolveModuleImportTest extends LightJava9ModulesCodeInsightFixture
}
public void testAmbiguousModuleImportWithPackageImport() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.MODULE_IMPORT_DECLARATIONS.getMinimumLevel(), ()->{
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_23_PREVIEW, ()->{
prepareAmbiguousModuleTests();
myFixture.configureByFile(getTestName(false) + ".java");
myFixture.checkHighlighting();

View File

@@ -18,11 +18,13 @@ public class ConfusingMainMethodInspectionTest extends LightJavaInspectionTestCa
}
public void testConfusingMainMethod() {
doTest();
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, () -> {
doTest();
});
}
public void testConfusingMainMethodInImplicitClass() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21_PREVIEW, () -> {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_25, () -> {
doTest();
});
}

View File

@@ -3,7 +3,7 @@ import com.intellij.util.xml.DomElementVisitor;
public class ImplicitUsagesDomElementVisitor implements DomElementVisitor {
public static void main(String[] args) {} // suppress class unused
public static void main() {} // suppress class unused
interface MyDom extends DomElement {}
@@ -21,7 +21,7 @@ public class ImplicitUsagesDomElementVisitor implements DomElementVisitor {
public static class NonDomElementVisitorClass {
public static void main(String[] args) {} // suppress class unused
public static void main() {} // suppress class unused
public void <warning descr="Method 'visitMyDom(ImplicitUsagesDomElementVisitor.MyDom)' is never used">visitMyDom</warning>(MyDom myDom) { myDom = null; }

View File

@@ -32,7 +32,7 @@ class KtPropertyKeyFoldingTest : JavaCodeInsightFixtureTestCase() {
private const val BUNDLE_NAME = "i18n";
private val BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
fun main(args: Array<String>) {
fun main() {
System.out.print(getMessage("com.example.localization.welcomeMessage"));
}
@@ -66,7 +66,7 @@ class KtPropertyKeyFoldingTest : JavaCodeInsightFixtureTestCase() {
private const val BUNDLE_NAME = "i18n";
private val BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
fun main(args: Array<String>) {
fun main() {
System.out.print(getMessage("com.example.localization.welcomeMessage", "My Friend"));
}

View File

@@ -123,7 +123,7 @@ class JavaJunit5ImplicitUsageProviderTest : JUnit5ImplicitUsageProviderTestBase(
import java.util.stream.Stream;
public class MyTest {
public static void main(String[] args){
public static void main(){
new MyTest();
}
public static Stream<Arguments> <warning descr="Method 'allJdks()' is never used">allJdks</warning>() {

View File

@@ -6,7 +6,7 @@ public class BuilderWithDefaultRedundantInitializer {
private String filed2 = <warning descr="Variable 'filed2' initializer '\" some value\"' is redundant">" some value"</warning>;
public static void main(String[] args) {
public static void main() {
System.out.println(BuilderWithDefaultRedundantInitializer.builder().field1("xyz").build());
}
}

View File

@@ -28,7 +28,7 @@ class Foo {
}
public class BuilderWithDefaultReinitializeInConstructor {
public static void main(String[] args) {
public static void main() {
new Bar("FooBar", "Foo");
new Foo("FooBar", "Foo");
}

View File

@@ -9,7 +9,7 @@ import java.util.ArrayList;
import java.util.Map;
public class BuilderWithPredefinedBuilderClassMethods {
public static void main(String[] args) {
public static void main() {
new BuilderWithPredefinedBuilderClassMethods().test();
System.out.println(new MathContext(1).getSomeInt());
}

View File

@@ -27,7 +27,7 @@ public class FieldNameConstantsExample {
}
}
public static void main(String[] args) {
public static void main() {
new FieldNameConstantsExample().logFieldValue(new Foo("a", "b"), "foo");
}
}

View File

@@ -15,7 +15,7 @@ public final class LombokBasics {
if (this <warning descr="Object values are compared using '==', not 'equals()'">==</warning> other) {} // equals is implicitly defined
}
public static void main(String[] args) {
public static void main() {
new LombokBasics(10).test(new LombokBasics(12));
}
}

View File

@@ -19,7 +19,7 @@ public class LombokEqualsAndHashCode {
private float f;
}
public static void main(String[] args) {
public static void main() {
System.out.println(new Parent());
System.out.println(new Child1());
System.out.println(new Child2());

View File

@@ -12,7 +12,7 @@ public class LombokNullable {
@Nonnull
private String value;
public static void main(String[] args) {
public static void main() {
String value = Math.random() > 0.5 ? null : "xx";
LombokNullable test = LombokNullable.builder()
@@ -33,7 +33,7 @@ class LombokNullableConstructor {
this.value = value;
}
public static void main(String[] args) {
public static void main() {
String value = Math.random() > 0.5 ? null : "xx";
LombokNullableConstructor test = LombokNullableConstructor.builder()
@@ -52,7 +52,7 @@ record LombokNullableRecord(@Nonnull String foo) {
.build();
}
public static void main(String[] args) {
public static void main() {
final LombokNullableRecord myNullableRecord = LombokNullableRecord.of(null);
System.out.println(myNullableRecord);
}

View File

@@ -10,7 +10,7 @@ public class LombokStaticVars {
log.info("This should not produce error: Variable 'log' might not have been initialized");
};
public static void main(String[] args) {
public static void main() {
LAMDA.run();
}
}