From 383836cb40ca774d4f297bfe46f591493d3bf401 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Fri, 23 Jun 2023 10:11:08 +0300 Subject: [PATCH 001/226] [kotlin] restore cooperative development in the 'kt-master' branch GitOrigin-RevId: 10518176da8acd1fe44a03ea9ef32b72f0a5dcf1 --- .../kotlinc_allopen_compiler_plugin.xml | 7 +++--- .../kotlinc_analysis_api_providers.xml | 7 +++--- .../kotlinc_analysis_project_structure.xml | 7 +++--- ...inc_android_extensions_compiler_plugin.xml | 7 +++--- .../kotlinc_assignment_compiler_plugin.xml | 7 +++--- .idea/libraries/kotlinc_high_level_api.xml | 7 +++--- .../libraries/kotlinc_high_level_api_fe10.xml | 7 +++--- .../libraries/kotlinc_high_level_api_fir.xml | 7 +++--- .../kotlinc_high_level_api_fir_tests.xml | 7 +++--- .../kotlinc_high_level_api_impl_base.xml | 7 +++--- ...kotlinc_high_level_api_impl_base_tests.xml | 7 +++--- ...inc_incremental_compilation_impl_tests.xml | 7 +++--- .../kotlinc_kotlin_build_common_tests.xml | 7 +++--- .../libraries/kotlinc_kotlin_compiler_cli.xml | 7 +++--- .../kotlinc_kotlin_compiler_common.xml | 7 +++--- .../kotlinc_kotlin_compiler_fe10.xml | 7 +++--- .../libraries/kotlinc_kotlin_compiler_fir.xml | 7 +++--- .../libraries/kotlinc_kotlin_compiler_ir.xml | 7 +++--- .../kotlinc_kotlin_compiler_tests.xml | 7 +++--- .../kotlinc_kotlin_gradle_statistics.xml | 7 +++--- .idea/libraries/kotlinc_kotlin_jps_common.xml | 7 +++--- .../kotlinc_kotlin_script_runtime.xml | 7 +++--- .../kotlinc_kotlin_scripting_common.xml | 7 +++--- ...kotlinc_kotlin_scripting_compiler_impl.xml | 7 +++--- .../kotlinc_kotlin_scripting_jvm.xml | 7 +++--- .idea/libraries/kotlinc_kotlin_stdlib.xml | 23 ++++++++----------- ...kotlinc_kotlin_stdlib_minimal_for_test.xml | 7 +++--- ..._kotlinx_serialization_compiler_plugin.xml | 7 +++--- .../kotlinc_lombok_compiler_plugin.xml | 7 +++--- .idea/libraries/kotlinc_low_level_api_fir.xml | 7 +++--- .../kotlinc_noarg_compiler_plugin.xml | 7 +++--- .../kotlinc_parcelize_compiler_plugin.xml | 7 +++--- ...linc_sam_with_receiver_compiler_plugin.xml | 7 +++--- .../kotlinc_scripting_compiler_plugin.xml | 7 +++--- .../kotlinc_symbol_light_classes.xml | 7 +++--- .../resources/model.properties | 2 +- 36 files changed, 112 insertions(+), 151 deletions(-) diff --git a/.idea/libraries/kotlinc_allopen_compiler_plugin.xml b/.idea/libraries/kotlinc_allopen_compiler_plugin.xml index 7aa23c481922..b4241b099d2d 100644 --- a/.idea/libraries/kotlinc_allopen_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_allopen_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_analysis_api_providers.xml b/.idea/libraries/kotlinc_analysis_api_providers.xml index 80f327dc7f19..4b9e306e97fd 100644 --- a/.idea/libraries/kotlinc_analysis_api_providers.xml +++ b/.idea/libraries/kotlinc_analysis_api_providers.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_analysis_project_structure.xml b/.idea/libraries/kotlinc_analysis_project_structure.xml index 13ed5dd73907..0f08ef95bf7c 100644 --- a/.idea/libraries/kotlinc_analysis_project_structure.xml +++ b/.idea/libraries/kotlinc_analysis_project_structure.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_android_extensions_compiler_plugin.xml b/.idea/libraries/kotlinc_android_extensions_compiler_plugin.xml index 204449116884..32f17ac3b24a 100644 --- a/.idea/libraries/kotlinc_android_extensions_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_android_extensions_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_assignment_compiler_plugin.xml b/.idea/libraries/kotlinc_assignment_compiler_plugin.xml index 09bb1f00ce59..71295b39ea41 100644 --- a/.idea/libraries/kotlinc_assignment_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_assignment_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api.xml b/.idea/libraries/kotlinc_high_level_api.xml index aa74b92eac0f..ec4c32cc75f4 100644 --- a/.idea/libraries/kotlinc_high_level_api.xml +++ b/.idea/libraries/kotlinc_high_level_api.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_fe10.xml b/.idea/libraries/kotlinc_high_level_api_fe10.xml index 854c3f382a25..0c93b8382ad6 100644 --- a/.idea/libraries/kotlinc_high_level_api_fe10.xml +++ b/.idea/libraries/kotlinc_high_level_api_fe10.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_fir.xml b/.idea/libraries/kotlinc_high_level_api_fir.xml index 33cc21ac4fd1..6330f8778c6f 100644 --- a/.idea/libraries/kotlinc_high_level_api_fir.xml +++ b/.idea/libraries/kotlinc_high_level_api_fir.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_fir_tests.xml b/.idea/libraries/kotlinc_high_level_api_fir_tests.xml index a74cb6316fb5..c18c2e60efcb 100644 --- a/.idea/libraries/kotlinc_high_level_api_fir_tests.xml +++ b/.idea/libraries/kotlinc_high_level_api_fir_tests.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_impl_base.xml b/.idea/libraries/kotlinc_high_level_api_impl_base.xml index 936b2649f0a6..fd6dc0b987fd 100644 --- a/.idea/libraries/kotlinc_high_level_api_impl_base.xml +++ b/.idea/libraries/kotlinc_high_level_api_impl_base.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_impl_base_tests.xml b/.idea/libraries/kotlinc_high_level_api_impl_base_tests.xml index 3ee2c1f93a6a..32d2114f18b3 100644 --- a/.idea/libraries/kotlinc_high_level_api_impl_base_tests.xml +++ b/.idea/libraries/kotlinc_high_level_api_impl_base_tests.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_incremental_compilation_impl_tests.xml b/.idea/libraries/kotlinc_incremental_compilation_impl_tests.xml index 7f636a1c2f7d..f88f6ca3f728 100644 --- a/.idea/libraries/kotlinc_incremental_compilation_impl_tests.xml +++ b/.idea/libraries/kotlinc_incremental_compilation_impl_tests.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_build_common_tests.xml b/.idea/libraries/kotlinc_kotlin_build_common_tests.xml index 85604bf3a2f2..78568afb8097 100644 --- a/.idea/libraries/kotlinc_kotlin_build_common_tests.xml +++ b/.idea/libraries/kotlinc_kotlin_build_common_tests.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_cli.xml b/.idea/libraries/kotlinc_kotlin_compiler_cli.xml index 577d368c21ae..70a6aad2489a 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_cli.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_cli.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_common.xml b/.idea/libraries/kotlinc_kotlin_compiler_common.xml index cc3b0dcb5584..9d889e08ce49 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_common.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_common.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_fe10.xml b/.idea/libraries/kotlinc_kotlin_compiler_fe10.xml index 2d016a9019d4..e94371825c15 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_fe10.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_fe10.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_fir.xml b/.idea/libraries/kotlinc_kotlin_compiler_fir.xml index 4c22a671bbb3..1d70088b3672 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_fir.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_fir.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_ir.xml b/.idea/libraries/kotlinc_kotlin_compiler_ir.xml index bf2badc4fd62..72526fa5a4a1 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_ir.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_ir.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_tests.xml b/.idea/libraries/kotlinc_kotlin_compiler_tests.xml index 02bbf51dabed..1bd77f9f07bb 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_tests.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_tests.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_gradle_statistics.xml b/.idea/libraries/kotlinc_kotlin_gradle_statistics.xml index e317550b04c7..35c4996d44f0 100644 --- a/.idea/libraries/kotlinc_kotlin_gradle_statistics.xml +++ b/.idea/libraries/kotlinc_kotlin_gradle_statistics.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_jps_common.xml b/.idea/libraries/kotlinc_kotlin_jps_common.xml index 6a5cfb013dc2..8ec96bc94777 100644 --- a/.idea/libraries/kotlinc_kotlin_jps_common.xml +++ b/.idea/libraries/kotlinc_kotlin_jps_common.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_script_runtime.xml b/.idea/libraries/kotlinc_kotlin_script_runtime.xml index a9456b3cbaae..e17c173d563b 100644 --- a/.idea/libraries/kotlinc_kotlin_script_runtime.xml +++ b/.idea/libraries/kotlinc_kotlin_script_runtime.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_scripting_common.xml b/.idea/libraries/kotlinc_kotlin_scripting_common.xml index a43c9d8a0785..53b4457b3acd 100644 --- a/.idea/libraries/kotlinc_kotlin_scripting_common.xml +++ b/.idea/libraries/kotlinc_kotlin_scripting_common.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_scripting_compiler_impl.xml b/.idea/libraries/kotlinc_kotlin_scripting_compiler_impl.xml index ebc7ae7f1530..269c2b7bd351 100644 --- a/.idea/libraries/kotlinc_kotlin_scripting_compiler_impl.xml +++ b/.idea/libraries/kotlinc_kotlin_scripting_compiler_impl.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_scripting_jvm.xml b/.idea/libraries/kotlinc_kotlin_scripting_jvm.xml index 632009d36428..b68719d24f8f 100644 --- a/.idea/libraries/kotlinc_kotlin_scripting_jvm.xml +++ b/.idea/libraries/kotlinc_kotlin_scripting_jvm.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_stdlib.xml b/.idea/libraries/kotlinc_kotlin_stdlib.xml index cd57486e8d27..2534610ad395 100644 --- a/.idea/libraries/kotlinc_kotlin_stdlib.xml +++ b/.idea/libraries/kotlinc_kotlin_stdlib.xml @@ -1,25 +1,20 @@ - - - - - - + - - - - + + + + - - - - + + + + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_stdlib_minimal_for_test.xml b/.idea/libraries/kotlinc_kotlin_stdlib_minimal_for_test.xml index 73ecca995b36..093ed9623c63 100644 --- a/.idea/libraries/kotlinc_kotlin_stdlib_minimal_for_test.xml +++ b/.idea/libraries/kotlinc_kotlin_stdlib_minimal_for_test.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlinx_serialization_compiler_plugin.xml b/.idea/libraries/kotlinc_kotlinx_serialization_compiler_plugin.xml index e70b7e91bb2c..69dc43051f7c 100644 --- a/.idea/libraries/kotlinc_kotlinx_serialization_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_kotlinx_serialization_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_lombok_compiler_plugin.xml b/.idea/libraries/kotlinc_lombok_compiler_plugin.xml index 5015783151e7..53e0d754b3da 100644 --- a/.idea/libraries/kotlinc_lombok_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_lombok_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_low_level_api_fir.xml b/.idea/libraries/kotlinc_low_level_api_fir.xml index d4ba528fa926..9a640dd8d49e 100644 --- a/.idea/libraries/kotlinc_low_level_api_fir.xml +++ b/.idea/libraries/kotlinc_low_level_api_fir.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_noarg_compiler_plugin.xml b/.idea/libraries/kotlinc_noarg_compiler_plugin.xml index f293be5c3df4..2c1a292400eb 100644 --- a/.idea/libraries/kotlinc_noarg_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_noarg_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_parcelize_compiler_plugin.xml b/.idea/libraries/kotlinc_parcelize_compiler_plugin.xml index 9aa15c304e29..d302a3eaa5a0 100644 --- a/.idea/libraries/kotlinc_parcelize_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_parcelize_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_sam_with_receiver_compiler_plugin.xml b/.idea/libraries/kotlinc_sam_with_receiver_compiler_plugin.xml index 346ba70a74ec..a098b3ac0a4e 100644 --- a/.idea/libraries/kotlinc_sam_with_receiver_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_sam_with_receiver_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_scripting_compiler_plugin.xml b/.idea/libraries/kotlinc_scripting_compiler_plugin.xml index 2f254fc4e874..ac1898242d85 100644 --- a/.idea/libraries/kotlinc_scripting_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_scripting_compiler_plugin.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_symbol_light_classes.xml b/.idea/libraries/kotlinc_symbol_light_classes.xml index 6870481c8f55..ee35f2b3f987 100644 --- a/.idea/libraries/kotlinc_symbol_light_classes.xml +++ b/.idea/libraries/kotlinc_symbol_light_classes.xml @@ -1,12 +1,11 @@ - - + - + - + \ No newline at end of file diff --git a/plugins/kotlin/util/project-model-updater/resources/model.properties b/plugins/kotlin/util/project-model-updater/resources/model.properties index 70b135cc7ce3..6e076351efe6 100644 --- a/plugins/kotlin/util/project-model-updater/resources/model.properties +++ b/plugins/kotlin/util/project-model-updater/resources/model.properties @@ -1,5 +1,5 @@ kotlincVersion=1.9.20-dev-4794 -kotlincArtifactsMode=MAVEN +kotlincArtifactsMode=BOOTSTRAP jpsPluginVersion=1.8.21-release-380 jpsPluginArtifactsMode=MAVEN From 67ef81fb0bd4dd63ef94444e83f61d9d602377ba Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 1 Jun 2023 16:29:53 +0200 Subject: [PATCH 002/226] [kotlin] KT-57489 Use correct source for implicit this receiver GitOrigin-RevId: 21234f5a237f0b2f4d2d38e5cc4f09b6900ac0f7 --- .../test/testData/stepping/stepInto/accessors.kt | 4 +--- .../stepOver/coroutines/sequenceNested.k2.out | 12 ------------ 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 plugins/kotlin/jvm-debugger/test/testData/stepping/stepOver/coroutines/sequenceNested.k2.out diff --git a/plugins/kotlin/jvm-debugger/test/testData/stepping/stepInto/accessors.kt b/plugins/kotlin/jvm-debugger/test/testData/stepping/stepInto/accessors.kt index 35ec74dcb467..3764c1b763e5 100644 --- a/plugins/kotlin/jvm-debugger/test/testData/stepping/stepInto/accessors.kt +++ b/plugins/kotlin/jvm-debugger/test/testData/stepping/stepInto/accessors.kt @@ -28,6 +28,4 @@ class A { } // STEP_INTO: 17 -// SKIP_SYNTHETIC_METHODS: false -// IGNORE_FOR_K2_CODE -// Remove ignore after KT-57489 fix \ No newline at end of file +// SKIP_SYNTHETIC_METHODS: false \ No newline at end of file diff --git a/plugins/kotlin/jvm-debugger/test/testData/stepping/stepOver/coroutines/sequenceNested.k2.out b/plugins/kotlin/jvm-debugger/test/testData/stepping/stepOver/coroutines/sequenceNested.k2.out deleted file mode 100644 index 46f7187fdae3..000000000000 --- a/plugins/kotlin/jvm-debugger/test/testData/stepping/stepOver/coroutines/sequenceNested.k2.out +++ /dev/null @@ -1,12 +0,0 @@ -LineBreakpoint created at sequenceNested.kt:6 -Run Java -Connected to the target VM -sequenceNested.kt:6 -sequenceNested.kt:15 -sequenceNested.kt:14 -sequenceNested.kt:21 -sequenceNested.kt:23 -sequenceNested.kt:24 -Disconnected from the target VM - -Process finished with exit code 0 From 54035a3f1c4a1774e7aa31538b2414acc1ec5c2f Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Thu, 1 Jun 2023 14:21:57 +0200 Subject: [PATCH 003/226] [kotlin] KTIJ-25335 Add UAST test for properties with missing names - The test data includes examples from KTIJ-25335, KTIJ-24121, and KTIJ-23584. GitOrigin-RevId: 8d87d99119472fad9cd40bb9a759f4c9df721a21 --- .../test/FirUastDeclarationTestGenerated.java | 5 ++++ .../testData/declaration/missingNames.kt | 19 ++++++++++++ .../declaration/missingNames.log.fe10.txt | 30 +++++++++++++++++++ .../declaration/missingNames.log.fir.txt | 30 +++++++++++++++++++ .../declaration/missingNames.render.fe10.txt | 21 +++++++++++++ .../declaration/missingNames.render.fir.txt | 21 +++++++++++++ .../FE1UastDeclarationTestGenerated.java | 5 ++++ 7 files changed, 131 insertions(+) create mode 100644 plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.kt create mode 100644 plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.log.fe10.txt create mode 100644 plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.log.fir.txt create mode 100644 plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.render.fe10.txt create mode 100644 plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.render.fir.txt diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/test/org/jetbrains/fir/uast/test/FirUastDeclarationTestGenerated.java b/plugins/kotlin/uast/uast-kotlin-fir/tests/test/org/jetbrains/fir/uast/test/FirUastDeclarationTestGenerated.java index 5393391b8b3e..1c33fadaaf4b 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/test/org/jetbrains/fir/uast/test/FirUastDeclarationTestGenerated.java +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/test/org/jetbrains/fir/uast/test/FirUastDeclarationTestGenerated.java @@ -98,6 +98,11 @@ public class FirUastDeclarationTestGenerated extends AbstractFirUastDeclarationT runTest("testData/declaration/mangling.kt"); } + @TestMetadata("missingNames.kt") + public void testMissingNames() throws Exception { + runTest("testData/declaration/missingNames.kt"); + } + @TestMetadata("nullabilityOfTypeParameter.kt") public void testNullabilityOfTypeParameter() throws Exception { runTest("testData/declaration/nullabilityOfTypeParameter.kt"); diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.kt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.kt new file mode 100644 index 000000000000..3e0acce27a07 --- /dev/null +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.kt @@ -0,0 +1,19 @@ +// KTIJ-25335 +class SimpleClass(valOne: String, valTwo: Int) { + val +} + +class Foo(val name: String, val) + +// KTIJ-23584 +interface Foo { + val +} + +// KTIJ-24121 +class MyClass(val value: T) { + fun getValAsString(): T { + return value.toString() + } + val +} diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.log.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.log.fe10.txt new file mode 100644 index 000000000000..960460867048 --- /dev/null +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.log.fe10.txt @@ -0,0 +1,30 @@ +UFile (package = ) + UClass (name = SimpleClass) + UMethod (name = SimpleClass) + UParameter (name = valOne) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UParameter (name = valTwo) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UClass (name = Foo) + UField (name = name) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = getName) + UMethod (name = Foo) + UParameter (name = name) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UParameter (name = ) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UClass (name = Foo) + UClass (name = MyClass) + UField (name = value) + UMethod (name = getValAsString) + UBlockExpression + UReturnExpression + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = value) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UMethod (name = getValue) + UMethod (name = MyClass) + UParameter (name = value) diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.log.fir.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.log.fir.txt new file mode 100644 index 000000000000..4982f4679ef9 --- /dev/null +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.log.fir.txt @@ -0,0 +1,30 @@ +UFile (package = ) + UClass (name = SimpleClass) + UMethod (name = SimpleClass) + UParameter (name = valOne) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UParameter (name = valTwo) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UClass (name = Foo) + UField (name = name) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = getName) + UMethod (name = Foo) + UParameter (name = name) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UParameter (name = ) + UAnnotation (fqName = null) + UClass (name = Foo) + UClass (name = MyClass) + UField (name = value) + UMethod (name = getValAsString) + UBlockExpression + UReturnExpression + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = value) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UMethod (name = getValue) + UMethod (name = MyClass) + UParameter (name = value) diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.render.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.render.fe10.txt new file mode 100644 index 000000000000..4185ad8852d9 --- /dev/null +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.render.fe10.txt @@ -0,0 +1,21 @@ +public final class SimpleClass { + public fun SimpleClass(@org.jetbrains.annotations.NotNull valOne: java.lang.String, @org.jetbrains.annotations.NotNull valTwo: int) = UastEmptyExpression +} + +public final class Foo { + @org.jetbrains.annotations.NotNull private final var name: java.lang.String + public final fun getName() : java.lang.String = UastEmptyExpression + public fun Foo(@org.jetbrains.annotations.NotNull name: java.lang.String, @org.jetbrains.annotations.NotNull : error.NonExistentClass) = UastEmptyExpression +} + +public abstract interface Foo { +} + +public final class MyClass { + private final var value: T + public final fun getValAsString() : T { + return value.toString() + } + public final fun getValue() : T = UastEmptyExpression + public fun MyClass(value: T) = UastEmptyExpression +} diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.render.fir.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.render.fir.txt new file mode 100644 index 000000000000..16b420239bad --- /dev/null +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/declaration/missingNames.render.fir.txt @@ -0,0 +1,21 @@ +public final class SimpleClass { + public fun SimpleClass(@org.jetbrains.annotations.NotNull valOne: java.lang.String, @org.jetbrains.annotations.NotNull valTwo: int) = UastEmptyExpression +} + +public final class Foo { + @org.jetbrains.annotations.NotNull private final var name: java.lang.String + public final fun getName() : java.lang.String = UastEmptyExpression + public fun Foo(@org.jetbrains.annotations.NotNull name: java.lang.String, @null : error.NonExistentClass) = UastEmptyExpression +} + +public abstract interface Foo { +} + +public final class MyClass { + private final var value: T + public final fun getValAsString() : T { + return value.toString() + } + public final fun getValue() : T = UastEmptyExpression + public fun MyClass(value: T) = UastEmptyExpression +} diff --git a/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/comparison/FE1UastDeclarationTestGenerated.java b/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/comparison/FE1UastDeclarationTestGenerated.java index 71b0690e6703..56f92fa799bd 100644 --- a/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/comparison/FE1UastDeclarationTestGenerated.java +++ b/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/comparison/FE1UastDeclarationTestGenerated.java @@ -98,6 +98,11 @@ public class FE1UastDeclarationTestGenerated extends AbstractFE1UastDeclarationT runTest("../../uast-kotlin-fir/tests/testData/declaration/mangling.kt"); } + @TestMetadata("missingNames.kt") + public void testMissingNames() throws Exception { + runTest("../../uast-kotlin-fir/tests/testData/declaration/missingNames.kt"); + } + @TestMetadata("nullabilityOfTypeParameter.kt") public void testNullabilityOfTypeParameter() throws Exception { runTest("../../uast-kotlin-fir/tests/testData/declaration/nullabilityOfTypeParameter.kt"); From afd70efab211b1e187d0fa7ed941b0b1e03a8531 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Wed, 21 Jun 2023 15:00:55 +0200 Subject: [PATCH 004/226] [kotlin] KTIJ-25335 Generate light classes tests for fields with missing names GitOrigin-RevId: 163029f19b843312638b7fdd78717c8d288232d1 --- .../IdeLightClassesByFqNameTestGenerated.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/asJava/classes/IdeLightClassesByFqNameTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/asJava/classes/IdeLightClassesByFqNameTestGenerated.java index b885f526a23d..db2365c970d8 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/asJava/classes/IdeLightClassesByFqNameTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/asJava/classes/IdeLightClassesByFqNameTestGenerated.java @@ -83,6 +83,21 @@ public abstract class IdeLightClassesByFqNameTestGenerated extends AbstractIdeLi runTest(compilerTestData("compiler/testData/asJava/lightClasses/lightClassByFqName/compilationErrors/ExpectedNestedClassInObject.kt")); } + @TestMetadata("FieldWithoutName.kt") + public void testFieldWithoutName() throws Exception { + runTest(compilerTestData("compiler/testData/asJava/lightClasses/lightClassByFqName/compilationErrors/FieldWithoutName.kt")); + } + + @TestMetadata("FieldWithoutName2.kt") + public void testFieldWithoutName2() throws Exception { + runTest(compilerTestData("compiler/testData/asJava/lightClasses/lightClassByFqName/compilationErrors/FieldWithoutName2.kt")); + } + + @TestMetadata("FieldWithoutName3.kt") + public void testFieldWithoutName3() throws Exception { + runTest(compilerTestData("compiler/testData/asJava/lightClasses/lightClassByFqName/compilationErrors/FieldWithoutName3.kt")); + } + @TestMetadata("FunctionWithoutName.kt") public void testFunctionWithoutName() throws Exception { runTest(compilerTestData("compiler/testData/asJava/lightClasses/lightClassByFqName/compilationErrors/FunctionWithoutName.kt")); From fbd35fd51f3ff6e674888989543b2837d54ba29a Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 23 Jun 2023 10:06:05 +0000 Subject: [PATCH 005/226] [kotlin] k2: icons provider for SymbolLightClasses (KTIJ-25171) Merge-request: KT-MR-10790 Merged-by: Anna Kozlova GitOrigin-RevId: 4028f9062929351e4f71f1d0e2a9ce11370fb3c6 --- .../kotlin/idea/KotlinIconProvider.kt | 9 +++-- .../codeInsight/FirKotlinIconProviderTest.kt | 40 +++++++++++++++++++ .../kotlin/idea/KotlinIconProviderTest.kt | 10 +++++ 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/codeInsight/FirKotlinIconProviderTest.kt diff --git a/plugins/kotlin/base/resources/src/org/jetbrains/kotlin/idea/KotlinIconProvider.kt b/plugins/kotlin/base/resources/src/org/jetbrains/kotlin/idea/KotlinIconProvider.kt index b0dbd091d136..1f9026f3c207 100644 --- a/plugins/kotlin/base/resources/src/org/jetbrains/kotlin/idea/KotlinIconProvider.kt +++ b/plugins/kotlin/base/resources/src/org/jetbrains/kotlin/idea/KotlinIconProvider.kt @@ -11,7 +11,6 @@ import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile -import com.intellij.psi.util.parentOfType import com.intellij.ui.IconManager import com.intellij.ui.RowIcon import com.intellij.util.PlatformIcons @@ -174,7 +173,7 @@ abstract class KotlinIconProvider : IconProvider(), DumbAware { (shortName?.asString() == JvmFileClassUtil.JVM_NAME_SHORT).ifTrue { val grandParent = parent.parent if (grandParent is KtPropertyAccessor) { - grandParent.parentOfType()?.getBaseIcon() + grandParent.property.getBaseIcon() } else { grandParent.getBaseIcon() } @@ -184,8 +183,10 @@ abstract class KotlinIconProvider : IconProvider(), DumbAware { val origin = (this as? KtLightClass)?.kotlinOrigin //TODO (light classes for decompiled files): correct presentation if (origin != null) origin.getBaseIcon() else CLASS - } - else -> unwrapped?.takeIf { it != this }?.getBaseIcon() + } ?: getBaseIconUnwrapped() + else -> getBaseIconUnwrapped() } + + private fun PsiElement.getBaseIconUnwrapped(): Icon? = unwrapped?.takeIf { it != this }?.getBaseIcon() } } diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/codeInsight/FirKotlinIconProviderTest.kt b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/codeInsight/FirKotlinIconProviderTest.kt new file mode 100644 index 000000000000..e7fe40f37c20 --- /dev/null +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/codeInsight/FirKotlinIconProviderTest.kt @@ -0,0 +1,40 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.fir.codeInsight +import com.intellij.openapi.util.Iconable +import com.intellij.psi.search.searches.ClassInheritorsSearch +import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.ui.icons.RowIcon +import com.intellij.util.PsiIconUtil +import com.intellij.util.ThrowableRunnable +import org.jetbrains.kotlin.idea.fir.invalidateCaches +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.runAll +import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import javax.swing.Icon + +class FirKotlinIconProviderTest : KotlinLightCodeInsightFixtureTestCase() { + override fun isFirPlugin(): Boolean { + return true + } + + override fun getProjectDescriptor(): LightProjectDescriptor { + return KotlinWithJdkAndRuntimeLightProjectDescriptor.getInstance() + } + + override fun tearDown() { + runAll( + ThrowableRunnable { project.invalidateCaches() }, + ThrowableRunnable { super.tearDown() } + ) + } + + fun testJavaBase() { + val aClass = myFixture.addClass("public class BaseJavaClass {}") + myFixture.addFileToProject("foo.kt", "class Foo : BaseJavaClass() {}") + val psiClass = ClassInheritorsSearch.search(aClass).findFirst()!! + val icon = PsiIconUtil.getProvidersIcon(psiClass, Iconable.ICON_FLAG_VISIBILITY or Iconable.ICON_FLAG_READ_STATUS) + val iconString = (icon.safeAs()?.allIcons?.joinToString(transform = Icon::toString) ?: icon)?.toString() + assertEquals("org/jetbrains/kotlin/idea/icons/classKotlin.svg", iconString) + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/KotlinIconProviderTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/KotlinIconProviderTest.kt index cc330428faa9..ee17058d5ace 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/KotlinIconProviderTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/KotlinIconProviderTest.kt @@ -2,6 +2,7 @@ package org.jetbrains.kotlin.idea import com.intellij.openapi.util.Iconable +import com.intellij.psi.search.searches.ClassInheritorsSearch import com.intellij.ui.icons.RowIcon import com.intellij.util.PsiIconUtil import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase @@ -41,6 +42,15 @@ class KotlinIconProviderTest: KotlinLightCodeInsightFixtureTestCase() { createFileAndCheckIcon("Foo.kt", fileBody, "org/jetbrains/kotlin/idea/icons/kotlin_file.svg") } + fun testJavaBase() { + val aClass = myFixture.addClass("public class BaseJavaClass {}") + myFixture.addFileToProject("foo.kt", "class Foo : BaseJavaClass() {}") + val psiClass = ClassInheritorsSearch.search(aClass).findFirst()!! + val icon = PsiIconUtil.getProvidersIcon(psiClass, Iconable.ICON_FLAG_VISIBILITY or Iconable.ICON_FLAG_READ_STATUS) + val iconString = (icon.safeAs()?.allIcons?.joinToString(transform = Icon::toString) ?: icon)?.toString() + assertEquals("org/jetbrains/kotlin/idea/icons/classKotlin.svg", iconString) + } + private fun createFileAndCheckIcon(fileName: String, fileBody: String, vararg icons: String) { val psiFile = myFixture.configureByText(fileName, fileBody) val icon = PsiIconUtil.getProvidersIcon(psiFile, Iconable.ICON_FLAG_VISIBILITY or Iconable.ICON_FLAG_READ_STATUS) From 54b7354233679ccbd11bd5ac81e2ecd5fd5bce04 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 20 Jun 2023 22:35:13 -0700 Subject: [PATCH 006/226] LC: regenerate tests for KT-59537 GitOrigin-RevId: d383b343c1a01ce1339f749a014e957ad56c6b6a --- .../asJava/classes/IdeLightClassesByPsiTestGenerated.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/asJava/classes/IdeLightClassesByPsiTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/asJava/classes/IdeLightClassesByPsiTestGenerated.java index 7a85192a2644..b69c7c8521a3 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/asJava/classes/IdeLightClassesByPsiTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/asJava/classes/IdeLightClassesByPsiTestGenerated.java @@ -83,6 +83,11 @@ public abstract class IdeLightClassesByPsiTestGenerated extends AbstractIdeLight runTest(compilerTestData("compiler/testData/asJava/lightClasses/lightClassByPsi/facades/properties.kt")); } + @TestMetadata("reifiedInlineReturnsObject.kt") + public void testReifiedInlineReturnsObject() throws Exception { + runTest(compilerTestData("compiler/testData/asJava/lightClasses/lightClassByPsi/facades/reifiedInlineReturnsObject.kt")); + } + @TestMetadata("simpleFunctions.kt") public void testSimpleFunctions() throws Exception { runTest(compilerTestData("compiler/testData/asJava/lightClasses/lightClassByPsi/facades/simpleFunctions.kt")); From 5dd46f9ba5cab195d50e8ade0b8e626fcde37903 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 22 Jun 2023 22:52:01 +0200 Subject: [PATCH 007/226] [kotlin] update test data after decompiler changes Escaped names GitOrigin-RevId: 529d6351edb44f59ecd7b2dc7ecc2ad5ba4d71b5 --- .../testData/intentions/specifyTypeExplicitly/backticked.kt | 1 - .../intentions/specifyTypeExplicitly/backticked.kt.after | 3 +-- .../parameters/misc/idWithRequiredBackticks.kt | 2 +- .../parameters/misc/idWithRequiredBackticks.kt.after | 4 ++-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/plugins/kotlin/idea/tests/testData/intentions/specifyTypeExplicitly/backticked.kt b/plugins/kotlin/idea/tests/testData/intentions/specifyTypeExplicitly/backticked.kt index e5ca237bf273..66be7b9ab5f2 100644 --- a/plugins/kotlin/idea/tests/testData/intentions/specifyTypeExplicitly/backticked.kt +++ b/plugins/kotlin/idea/tests/testData/intentions/specifyTypeExplicitly/backticked.kt @@ -1,3 +1,2 @@ -// IGNORE_FIR class `1` val x = `1`() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/intentions/specifyTypeExplicitly/backticked.kt.after b/plugins/kotlin/idea/tests/testData/intentions/specifyTypeExplicitly/backticked.kt.after index f817cb01821a..500593f51973 100644 --- a/plugins/kotlin/idea/tests/testData/intentions/specifyTypeExplicitly/backticked.kt.after +++ b/plugins/kotlin/idea/tests/testData/intentions/specifyTypeExplicitly/backticked.kt.after @@ -1,3 +1,2 @@ -// IGNORE_FIR class `1` -val x: `1` = `1`() \ No newline at end of file +val x: `1` = `1`() diff --git a/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/idWithRequiredBackticks.kt b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/idWithRequiredBackticks.kt index d3a9827f62d2..c9dc3e7bf311 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/idWithRequiredBackticks.kt +++ b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/idWithRequiredBackticks.kt @@ -1,5 +1,5 @@ // PARAM_TYPES: kotlin.Int -// PARAM_DESCRIPTOR: val 0: kotlin.Int defined in test +// PARAM_DESCRIPTOR: val `0`: kotlin.Int defined in test fun test() { val `0` = 0 `0`plus 1 diff --git a/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/idWithRequiredBackticks.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/idWithRequiredBackticks.kt.after index 51c1f596f9cc..2e165057f829 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/idWithRequiredBackticks.kt.after +++ b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/idWithRequiredBackticks.kt.after @@ -1,5 +1,5 @@ // PARAM_TYPES: kotlin.Int -// PARAM_DESCRIPTOR: val 0: kotlin.Int defined in test +// PARAM_DESCRIPTOR: val `0`: kotlin.Int defined in test fun test() { val `0` = 0 __dummyTestFun__(`0`) @@ -7,4 +7,4 @@ fun test() { private fun __dummyTestFun__(`0`: Int) { `0` plus 1 -} \ No newline at end of file +} From 8e1db9888bd154a81ddac724bded1bef93325b13 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 5 Jun 2023 12:25:16 +0200 Subject: [PATCH 008/226] [kotlin] k2: invalidate builtin tracker and the world on stdlib update GitOrigin-RevId: b993aad8029859911ec86b69d1e1445c276270b5 --- .../KotlinModuleStateTrackerProvider.kt | 19 ++++++++++++++----- ...otlin.base.fe10.analysis-api-providers.xml | 2 ++ ...kotlin.base.fir.analysis-api-providers.xml | 3 +++ .../FirIdeKotlinModuleStateTrackerProvider.kt | 19 +++++++++++++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 plugins/kotlin/base/fir/analysis-api-providers/src/org/jetbrains/kotlin/idea/base/fir/analysisApiProviders/FirIdeKotlinModuleStateTrackerProvider.kt diff --git a/plugins/kotlin/base/analysis-api-providers/src/org/jetbrains/kotlin/idea/base/analysisApiProviders/KotlinModuleStateTrackerProvider.kt b/plugins/kotlin/base/analysis-api-providers/src/org/jetbrains/kotlin/idea/base/analysisApiProviders/KotlinModuleStateTrackerProvider.kt index 91a79248c877..61f5b83d818f 100644 --- a/plugins/kotlin/base/analysis-api-providers/src/org/jetbrains/kotlin/idea/base/analysisApiProviders/KotlinModuleStateTrackerProvider.kt +++ b/plugins/kotlin/base/analysis-api-providers/src/org/jetbrains/kotlin/idea/base/analysisApiProviders/KotlinModuleStateTrackerProvider.kt @@ -3,7 +3,6 @@ package org.jetbrains.kotlin.idea.base.analysisApiProviders import com.intellij.java.workspace.entities.JavaSourceRootPropertiesEntity import com.intellij.openapi.Disposable -import com.intellij.openapi.components.Service import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.ProjectJdkTable @@ -44,9 +43,8 @@ import org.jetbrains.kotlin.parsing.KotlinParserDefinition import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicLong -@Service(Service.Level.PROJECT) @OptIn(Frontend10ApiUsage::class) -class KotlinModuleStateTrackerProvider(val project: Project) : Disposable { +open class KotlinModuleStateTrackerProvider(val project: Project) : Disposable { init { val busConnection = project.messageBus.connect(this) busConnection.subscribe(WorkspaceModelTopics.CHANGED, ModelChangeListener()) @@ -55,11 +53,14 @@ class KotlinModuleStateTrackerProvider(val project: Project) : Disposable { busConnection.subscribe(VirtualFileManager.VFS_CHANGES, LibraryUpdatesListener()) } + private val builtinTracker = ModuleStateTrackerImpl() private val libraryCache = ConcurrentHashMap() private val sourceModuleCache = ConcurrentHashMap() private val sdkCache = ConcurrentHashMap() private val scriptCache = ConcurrentHashMap() + protected open fun shouldInvalidateBuiltinSession(events: List): Boolean { return false } + fun getModuleStateTrackerFor(module: KtModule): KtModuleStateTracker { return when (module) { is KtScriptDependencyModule -> ModuleStateTrackerImpl() @@ -85,7 +86,7 @@ class KotlinModuleStateTrackerProvider(val project: Project) : Disposable { is KtLibrarySourceModule -> getModuleStateTrackerFor(module.binaryLibrary) - is KtBuiltinsModule -> ModuleStateTrackerImpl() + is KtBuiltinsModule -> builtinTracker is KtScriptModule -> { val virtualFile = module.file.virtualFile ?: error("Script ${module.file} does not have a backing 'VirtualFile'") @@ -115,6 +116,14 @@ class KotlinModuleStateTrackerProvider(val project: Project) : Disposable { private inner class LibraryUpdatesListener : BulkFileListener { val index = ProjectRootManager.getInstance(project).fileIndex override fun after(events: List) { + if (shouldInvalidateBuiltinSession(events)) { + builtinTracker.incModificationCount() + libraryCache.values.forEach { it.incModificationCount() } + sourceModuleCache.values.forEach { it.incModificationCount() } + sdkCache.values.forEach { it.incModificationCount() } + scriptCache.values.forEach { it.incModificationCount() } + return + } events.mapNotNull { event -> val file = when (event) { //for all other events workspace model should do the job @@ -246,7 +255,7 @@ class KotlinModuleStateTrackerProvider(val project: Project) : Disposable { } -private class ModuleStateTrackerImpl : KtModuleStateTracker { +class ModuleStateTrackerImpl : KtModuleStateTracker { private val modificationCount = AtomicLong() @Volatile diff --git a/plugins/kotlin/base/fe10/analysis-api-providers/resources/kotlin.base.fe10.analysis-api-providers.xml b/plugins/kotlin/base/fe10/analysis-api-providers/resources/kotlin.base.fe10.analysis-api-providers.xml index acdbc7be190a..8e5d7f8e1137 100644 --- a/plugins/kotlin/base/fe10/analysis-api-providers/resources/kotlin.base.fe10.analysis-api-providers.xml +++ b/plugins/kotlin/base/fe10/analysis-api-providers/resources/kotlin.base.fe10.analysis-api-providers.xml @@ -4,6 +4,8 @@ + diff --git a/plugins/kotlin/base/fir/analysis-api-providers/resources/kotlin.base.fir.analysis-api-providers.xml b/plugins/kotlin/base/fir/analysis-api-providers/resources/kotlin.base.fir.analysis-api-providers.xml index a57ef258ad02..f9c2b4012ee2 100644 --- a/plugins/kotlin/base/fir/analysis-api-providers/resources/kotlin.base.fir.analysis-api-providers.xml +++ b/plugins/kotlin/base/fir/analysis-api-providers/resources/kotlin.base.fir.analysis-api-providers.xml @@ -5,6 +5,9 @@ serviceInterface="org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory" serviceImplementation="org.jetbrains.kotlin.idea.base.fir.analysisApiProviders.FirIdeKotlinModificationTrackerFactory"/> + diff --git a/plugins/kotlin/base/fir/analysis-api-providers/src/org/jetbrains/kotlin/idea/base/fir/analysisApiProviders/FirIdeKotlinModuleStateTrackerProvider.kt b/plugins/kotlin/base/fir/analysis-api-providers/src/org/jetbrains/kotlin/idea/base/fir/analysisApiProviders/FirIdeKotlinModuleStateTrackerProvider.kt new file mode 100644 index 000000000000..c8269ee0f08a --- /dev/null +++ b/plugins/kotlin/base/fir/analysis-api-providers/src/org/jetbrains/kotlin/idea/base/fir/analysisApiProviders/FirIdeKotlinModuleStateTrackerProvider.kt @@ -0,0 +1,19 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.base.fir.analysisApiProviders + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent +import com.intellij.openapi.vfs.newvfs.events.VFileEvent +import java.util.regex.Pattern +import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirBuiltinsSessionFactory +import org.jetbrains.kotlin.idea.base.analysisApiProviders.KotlinModuleStateTrackerProvider + +private val STDLIB_PATTERN = Pattern.compile("kotlin-stdlib-(\\d*)\\.(\\d*)\\.(\\d*)\\.jar") + +class FirIdeKotlinModuleStateTrackerProvider(project: Project) : KotlinModuleStateTrackerProvider(project) { + override fun shouldInvalidateBuiltinSession(events: List): Boolean { + return events.find { event -> + event is VFileContentChangeEvent && STDLIB_PATTERN.matcher(event.file.name).matches() + } != null + } +} \ No newline at end of file From b51f259df53ca8e34c7e19e031cfd03b6466bd83 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Thu, 15 Jun 2023 19:24:47 -0700 Subject: [PATCH 009/226] FIR/UAST: update test data (enum modality) ^KT-57567 GitOrigin-RevId: 1afe5c25844636648a28b1d7ca01c556fc06ecda --- .../testData/legacyRenderLog/CommentOwners.render.fe10.txt | 2 +- .../testData/legacyRenderLog/EnumValueMembers.render.fe10.txt | 2 +- .../testData/legacyRenderLog/EnumValueMembers.render.fir.txt | 2 +- .../legacyRenderLog/EnumValuesConstructors.render.fe10.txt | 2 +- .../tests/testData/legacyTypes/CommentOwners.types.fe10.txt | 2 +- .../testData/legacyTypes/EnumValueMembers.types.fe10.txt | 4 ++-- .../tests/testData/legacyTypes/EnumValueMembers.types.fir.txt | 4 ++-- .../legacyTypes/EnumValuesConstructors.types.fe10.txt | 4 ++-- .../tests/testData/legacyValues/CommentOwners.values.fe10.txt | 2 +- .../testData/legacyValues/EnumValueMembers.values.fe10.txt | 4 ++-- .../testData/legacyValues/EnumValueMembers.values.fir.txt | 4 ++-- .../legacyValues/EnumValuesConstructors.values.fe10.txt | 4 ++-- .../tests/testData/EnumValueMembers.render-ide.txt | 2 +- .../uast-kotlin/tests/testData/EnumValueMembers.render.txt | 2 +- .../tests/testData/EnumValuesConstructors.render-ide.txt | 2 +- .../tests/testData/EnumValuesConstructors.render.txt | 2 +- 16 files changed, 22 insertions(+), 22 deletions(-) diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/CommentOwners.render.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/CommentOwners.render.fe10.txt index 57e7629244bf..76989f296fa5 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/CommentOwners.render.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/CommentOwners.render.fe10.txt @@ -37,7 +37,7 @@ public final class TopLevelClass { } } -public enum MyBooleanEnum { +public final enum MyBooleanEnum { @null TRUE @null FALSE private fun MyBooleanEnum() = UastEmptyExpression diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValueMembers.render.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValueMembers.render.fe10.txt index 4fc1f29e9be0..63a94f43a397 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValueMembers.render.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValueMembers.render.fe10.txt @@ -1,4 +1,4 @@ -public enum Style { +public abstract enum Style { @org.jetbrains.annotations.NotNull private final var value: java.lang.String @null SHEET("foo") { public fun getExitAnimation() : java.lang.String { diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValueMembers.render.fir.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValueMembers.render.fir.txt index ea24a0ec7d04..e35846764f59 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValueMembers.render.fir.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValueMembers.render.fir.txt @@ -1,4 +1,4 @@ -public final enum Style { +public abstract enum Style { @org.jetbrains.annotations.NotNull private final var value: java.lang.String @null SHEET("foo") { public fun getExitAnimation() : java.lang.String { diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValuesConstructors.render.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValuesConstructors.render.fe10.txt index ed5ab4620e13..99584c7dc177 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValuesConstructors.render.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/EnumValuesConstructors.render.fe10.txt @@ -1,4 +1,4 @@ -public enum Style { +public final enum Style { @org.jetbrains.annotations.Nullable private final var value: java.lang.String @null SYSTEM("system") @null USER("user") diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/CommentOwners.types.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/CommentOwners.types.fe10.txt index d7891bb72266..78978b0cc293 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/CommentOwners.types.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/CommentOwners.types.fe10.txt @@ -69,7 +69,7 @@ UFile (package = ) [public final class CommentOwnersKt {...] USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: Object) [] UClass (name = NestedClass) [public static final class NestedClass {...}] UMethod (name = NestedClass) [public fun NestedClass() = UastEmptyExpression] - UClass (name = MyBooleanEnum) [public enum MyBooleanEnum {...}] + UClass (name = MyBooleanEnum) [public final enum MyBooleanEnum {...}] UEnumConstant (name = TRUE) [@null TRUE] UAnnotation (fqName = null) [@null] USimpleNameReferenceExpression (identifier = MyBooleanEnum) [MyBooleanEnum] diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValueMembers.types.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValueMembers.types.fe10.txt index 900012075231..5e214dabb9c1 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValueMembers.types.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValueMembers.types.fe10.txt @@ -1,5 +1,5 @@ -UFile (package = ) [public enum Style {...] - UClass (name = Style) [public enum Style {...}] +UFile (package = ) [public abstract enum Style {...] + UClass (name = Style) [public abstract enum Style {...}] UField (name = value) [@org.jetbrains.annotations.NotNull private final var value: java.lang.String] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UEnumConstant (name = SHEET) [@null SHEET("foo") {...}] diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValueMembers.types.fir.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValueMembers.types.fir.txt index 0a38b56040e5..704a61c29a2f 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValueMembers.types.fir.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValueMembers.types.fir.txt @@ -1,5 +1,5 @@ -UFile (package = ) [public final enum Style {...] - UClass (name = Style) [public final enum Style {...}] +UFile (package = ) [public abstract enum Style {...] + UClass (name = Style) [public abstract enum Style {...}] UField (name = value) [@org.jetbrains.annotations.NotNull private final var value: java.lang.String] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UEnumConstant (name = SHEET) [@null SHEET("foo") {...}] diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValuesConstructors.types.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValuesConstructors.types.fe10.txt index b9b7912d5d32..fab88267ba24 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValuesConstructors.types.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/EnumValuesConstructors.types.fe10.txt @@ -1,5 +1,5 @@ -UFile (package = ) [public enum Style {...] - UClass (name = Style) [public enum Style {...}] +UFile (package = ) [public final enum Style {...] + UClass (name = Style) [public final enum Style {...}] UField (name = value) [@org.jetbrains.annotations.Nullable private final var value: java.lang.String] UAnnotation (fqName = org.jetbrains.annotations.Nullable) [@org.jetbrains.annotations.Nullable] UEnumConstant (name = SYSTEM) [@null SYSTEM("system")] diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/CommentOwners.values.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/CommentOwners.values.fe10.txt index 09a788a2c9d3..f09bf4f4cd5b 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/CommentOwners.values.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/CommentOwners.values.fe10.txt @@ -69,7 +69,7 @@ UFile (package = ) [public final class CommentOwnersKt {...] USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: Object) [] = external ()() UClass (name = NestedClass) [public static final class NestedClass {...}] UMethod (name = NestedClass) [public fun NestedClass() = UastEmptyExpression] - UClass (name = MyBooleanEnum) [public enum MyBooleanEnum {...}] + UClass (name = MyBooleanEnum) [public final enum MyBooleanEnum {...}] UEnumConstant (name = TRUE) [@null TRUE] = Undetermined UAnnotation (fqName = null) [@null] USimpleNameReferenceExpression (identifier = MyBooleanEnum) [MyBooleanEnum] = external MyBooleanEnum() diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValueMembers.values.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValueMembers.values.fe10.txt index 510f3862af68..54959b3f0435 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValueMembers.values.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValueMembers.values.fe10.txt @@ -1,5 +1,5 @@ -UFile (package = ) [public enum Style {...] - UClass (name = Style) [public enum Style {...}] +UFile (package = ) [public abstract enum Style {...] + UClass (name = Style) [public abstract enum Style {...}] UField (name = value) [@org.jetbrains.annotations.NotNull private final var value: java.lang.String] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UEnumConstant (name = SHEET) [@null SHEET("foo") {...}] = Undetermined diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValueMembers.values.fir.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValueMembers.values.fir.txt index 04cc79af6fae..935c75544c3e 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValueMembers.values.fir.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValueMembers.values.fir.txt @@ -1,5 +1,5 @@ -UFile (package = ) [public final enum Style {...] - UClass (name = Style) [public final enum Style {...}] +UFile (package = ) [public abstract enum Style {...] + UClass (name = Style) [public abstract enum Style {...}] UField (name = value) [@org.jetbrains.annotations.NotNull private final var value: java.lang.String] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UEnumConstant (name = SHEET) [@null SHEET("foo") {...}] = Undetermined diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValuesConstructors.values.fe10.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValuesConstructors.values.fe10.txt index 0f3eae3c21e6..ef21789529d1 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValuesConstructors.values.fe10.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/EnumValuesConstructors.values.fe10.txt @@ -1,5 +1,5 @@ -UFile (package = ) [public enum Style {...] - UClass (name = Style) [public enum Style {...}] +UFile (package = ) [public final enum Style {...] + UClass (name = Style) [public final enum Style {...}] UField (name = value) [@org.jetbrains.annotations.Nullable private final var value: java.lang.String] UAnnotation (fqName = org.jetbrains.annotations.Nullable) [@org.jetbrains.annotations.Nullable] UEnumConstant (name = SYSTEM) [@null SYSTEM("system")] = Undetermined diff --git a/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValueMembers.render-ide.txt b/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValueMembers.render-ide.txt index e1124ee6d106..462ed6a7147c 100644 --- a/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValueMembers.render-ide.txt +++ b/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValueMembers.render-ide.txt @@ -1,4 +1,4 @@ -public enum Style { +public abstract enum Style { @org.jetbrains.annotations.NotNull private final var value: java.lang.String @null SHEET("foo") { public fun getExitAnimation() : java.lang.String { diff --git a/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValueMembers.render.txt b/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValueMembers.render.txt index 4fc1f29e9be0..63a94f43a397 100644 --- a/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValueMembers.render.txt +++ b/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValueMembers.render.txt @@ -1,4 +1,4 @@ -public enum Style { +public abstract enum Style { @org.jetbrains.annotations.NotNull private final var value: java.lang.String @null SHEET("foo") { public fun getExitAnimation() : java.lang.String { diff --git a/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValuesConstructors.render-ide.txt b/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValuesConstructors.render-ide.txt index 637249179cc5..f8c0d81ca907 100644 --- a/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValuesConstructors.render-ide.txt +++ b/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValuesConstructors.render-ide.txt @@ -1,4 +1,4 @@ -public enum Style { +public final enum Style { @org.jetbrains.annotations.Nullable private final var value: java.lang.String @null SYSTEM("system") @null USER("user") diff --git a/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValuesConstructors.render.txt b/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValuesConstructors.render.txt index ed5ab4620e13..99584c7dc177 100644 --- a/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValuesConstructors.render.txt +++ b/plugins/kotlin/uast/uast-kotlin/tests/testData/EnumValuesConstructors.render.txt @@ -1,4 +1,4 @@ -public enum Style { +public final enum Style { @org.jetbrains.annotations.Nullable private final var value: java.lang.String @null SYSTEM("system") @null USER("user") From 36cf0aedfd3cbefad0a365eb832c855cd4a778c2 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Thu, 15 Jun 2023 19:25:12 -0700 Subject: [PATCH 010/226] Ensure enum class from LC is final ^KT-57567 Fixed GitOrigin-RevId: 992f97218bf56d8160f32baea65ccaab2b1f74dd --- .../uast/test/common/kotlin/LightClassBehaviorTestBase.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/kotlin/uast/uast-kotlin-base/tests/test/org/jetbrains/uast/test/common/kotlin/LightClassBehaviorTestBase.kt b/plugins/kotlin/uast/uast-kotlin-base/tests/test/org/jetbrains/uast/test/common/kotlin/LightClassBehaviorTestBase.kt index a25d5c5f0ac3..ec5ee9e67455 100644 --- a/plugins/kotlin/uast/uast-kotlin-base/tests/test/org/jetbrains/uast/test/common/kotlin/LightClassBehaviorTestBase.kt +++ b/plugins/kotlin/uast/uast-kotlin-base/tests/test/org/jetbrains/uast/test/common/kotlin/LightClassBehaviorTestBase.kt @@ -170,20 +170,24 @@ interface LightClassBehaviorTestBase : UastPluginSelection { val upTo = uFile.findElementByTextFromPsi("upTo", strict = false) .orFail("can't find fun upTo") TestCase.assertTrue(upTo.javaPsi.hasModifier(JvmModifier.FINAL)) + TestCase.assertTrue(upTo.javaPsi.containingClass!!.hasModifier(JvmModifier.FINAL)) TestCase.assertTrue(upTo.javaPsi.parameterList.parameters[0].annotations.any { it.isNotNull }) val isFinished = uFile.findElementByTextFromPsi("isFinished", strict = false) .orFail("can't find accessor isFinished") TestCase.assertTrue(isFinished.javaPsi.hasModifier(JvmModifier.FINAL)) + TestCase.assertTrue(isFinished.javaPsi.containingClass!!.hasModifier(JvmModifier.FINAL)) val isAtLeast = uFile.findElementByTextFromPsi("isAtLeast", strict = false) .orFail("can't find fun isAtLeast") TestCase.assertTrue(isAtLeast.javaPsi.hasModifier(JvmModifier.FINAL)) + TestCase.assertTrue(isAtLeast.javaPsi.containingClass!!.hasModifier(JvmModifier.FINAL)) TestCase.assertTrue(isAtLeast.javaPsi.parameterList.parameters[0].annotations.any { it.isNotNull }) val done = uFile.findElementByTextFromPsi("done", strict = false) .orFail("can't find fun done") TestCase.assertTrue(done.javaPsi.hasModifier(JvmModifier.FINAL)) + TestCase.assertTrue(done.javaPsi.containingClass!!.hasModifier(JvmModifier.FINAL)) TestCase.assertTrue(done.javaPsi.parameterList.parameters[0].annotations.any { it.isNotNull }) } From 98abe914e53712a2cbbe5f659db03c29bd4e1177 Mon Sep 17 00:00:00 2001 From: Jaebaek Seo Date: Tue, 6 Jun 2023 14:29:06 -0700 Subject: [PATCH 011/226] Match K2 optional parameter rendering for completion with K1 K1 renders " = ..." for optional parameter completion, which is missing in the current K2 implementation. This commit fixes it. GitOrigin-RevId: f1aeddfd0bbe497e762eb36c78d4118963cfc636 --- .../k2/lookups/CompletionShortNamesRenderer.kt | 2 +- .../common/parameterNameAndType/FunctionCall.kt | 17 +++++++++++++++++ .../test/JSBasicCompletionTestGenerated.java | 5 +++++ .../test/JvmBasicCompletionTestGenerated.java | 5 +++++ ...ighLevelJvmBasicCompletionTestGenerated.java | 5 +++++ 5 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 plugins/kotlin/completion/testData/basic/common/parameterNameAndType/FunctionCall.kt diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/CompletionShortNamesRenderer.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/CompletionShortNamesRenderer.kt index fe1b7d771fc3..f130e775e116 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/CompletionShortNamesRenderer.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/CompletionShortNamesRenderer.kt @@ -30,7 +30,7 @@ internal object CompletionShortNamesRenderer { private fun KtAnalysisSession.renderFunctionParameter(parameter: KtVariableLikeSignature): String = "${if (parameter.symbol.isVararg) "vararg " else ""}${parameter.name.asString()}: ${ parameter.returnType.renderNonErrorOrUnsubstituted(parameter.symbol.returnType) - }" + }${if (parameter.symbol.hasDefaultValue) " = ..." else ""}" val renderer = KtTypeRendererForSource.WITH_SHORT_NAMES val rendererVerbose = renderer.with { diff --git a/plugins/kotlin/completion/testData/basic/common/parameterNameAndType/FunctionCall.kt b/plugins/kotlin/completion/testData/basic/common/parameterNameAndType/FunctionCall.kt new file mode 100644 index 000000000000..c2df0b875cb6 --- /dev/null +++ b/plugins/kotlin/completion/testData/basic/common/parameterNameAndType/FunctionCall.kt @@ -0,0 +1,17 @@ +// FIR_COMPARISON +// FIR_IDENTICAL +package pack + +fun foobarOne(required: Int): Int = required + +fun foobarTwo(required: Int, optional: Int = 3): Int = required + optional + +fun test(foobarArg: Int) {} + +fun runTest() { + test(foobar) +} + +// EXIST: { lookupString: "foobarOne", itemText: "foobarOne", tailText:"(required: Int) (pack)", icon: "Function"} +// EXIST: { lookupString: "foobarTwo", itemText: "foobarTwo", tailText: "(required: Int, optional: Int = ...) (pack)", icon:"Function"} +// EXIST: { lookupString: "foobarArg =", itemText: "foobarArg =", tailText: " Int", icon: "Parameter"} \ No newline at end of file diff --git a/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index 7c97c24e7ca7..3649e3ef390a 100644 --- a/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -1623,6 +1623,11 @@ public abstract class JSBasicCompletionTestGenerated extends AbstractJSBasicComp runTest("../testData/basic/common/parameterNameAndType/ByAbbreviation.kt"); } + @TestMetadata("FunctionCall.kt") + public void testFunctionCall() throws Exception { + runTest("../testData/basic/common/parameterNameAndType/FunctionCall.kt"); + } + @TestMetadata("InSecondaryConstructor.kt") public void testInSecondaryConstructor() throws Exception { runTest("../testData/basic/common/parameterNameAndType/InSecondaryConstructor.kt"); diff --git a/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index c5cca6532862..43828278323c 100644 --- a/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -1623,6 +1623,11 @@ public abstract class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCo runTest("../testData/basic/common/parameterNameAndType/ByAbbreviation.kt"); } + @TestMetadata("FunctionCall.kt") + public void testFunctionCall() throws Exception { + runTest("../testData/basic/common/parameterNameAndType/FunctionCall.kt"); + } + @TestMetadata("InSecondaryConstructor.kt") public void testInSecondaryConstructor() throws Exception { runTest("../testData/basic/common/parameterNameAndType/InSecondaryConstructor.kt"); diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/completion/HighLevelJvmBasicCompletionTestGenerated.java b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/completion/HighLevelJvmBasicCompletionTestGenerated.java index 23acfcebbbcc..08a6df6f6cc2 100644 --- a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/completion/HighLevelJvmBasicCompletionTestGenerated.java +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/completion/HighLevelJvmBasicCompletionTestGenerated.java @@ -1623,6 +1623,11 @@ public abstract class HighLevelJvmBasicCompletionTestGenerated extends AbstractH runTest("../completion/testData/basic/common/parameterNameAndType/ByAbbreviation.kt"); } + @TestMetadata("FunctionCall.kt") + public void testFunctionCall() throws Exception { + runTest("../completion/testData/basic/common/parameterNameAndType/FunctionCall.kt"); + } + @TestMetadata("InSecondaryConstructor.kt") public void testInSecondaryConstructor() throws Exception { runTest("../completion/testData/basic/common/parameterNameAndType/InSecondaryConstructor.kt"); From 2114b5158cf439d961a33bc860abfd273517734f Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 20 Jun 2023 13:16:43 +0200 Subject: [PATCH 012/226] [kotlin] k2 completion: avoid requesting fir for fake elements from completion (KTIJ-25929) notUnderContentRootModuleInfo recognizes exactly one file. If it is a copy, then a consequence resolve won't work because it will take `originalDeclaration` first and then moduleKind won't match. GitOrigin-RevId: 9bf0ea13430f283f283239fbec38113ab975659c --- .../keywords/OverrideKeywordHandler.kt | 17 +++++++------ .../FirCompletionOutsideSourceRootTest.kt | 25 +++++++++++++++---- .../common/ComponentFunction.kt | 1 + .../common/ComponentFunction.kt.after | 1 + 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/keywords/OverrideKeywordHandler.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/keywords/OverrideKeywordHandler.kt index 0eaeefdedb72..0ad2df6d47b8 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/keywords/OverrideKeywordHandler.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/keywords/OverrideKeywordHandler.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.idea.completion.contributors.keywords import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.lookup.LookupElement import com.intellij.icons.AllIcons -import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.project.Project import com.intellij.ui.RowIcon import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt @@ -15,18 +14,21 @@ import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererModifierFilter -import org.jetbrains.kotlin.analysis.api.symbols.* +import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtVariableSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.idea.KtIconProvider.getBaseIcon -import org.jetbrains.kotlin.idea.base.analysis.api.utils.invokeShortening -import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferences import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferencesInRange -import org.jetbrains.kotlin.idea.completion.* +import org.jetbrains.kotlin.idea.completion.OverridesCompletionLookupElementDecorator import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.keywords.CompletionKeywordHandler -import org.jetbrains.kotlin.idea.core.overrideImplement.* +import org.jetbrains.kotlin.idea.core.overrideImplement.BodyType +import org.jetbrains.kotlin.idea.core.overrideImplement.KtClassMember +import org.jetbrains.kotlin.idea.core.overrideImplement.KtOverrideMembersHandler +import org.jetbrains.kotlin.idea.core.overrideImplement.MemberGenerateMode import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -52,7 +54,8 @@ internal class OverrideKeywordHandler( val result = mutableListOf() val position = parameters.position val isConstructorParameter = position.getNonStrictParentOfType() != null - val classOrObject = position.getNonStrictParentOfType() ?: return result + val parent = position.getNonStrictParentOfType() ?: return result + val classOrObject = parent.getOriginalDeclaration() as? KtClassOrObject ?: parent val members = collectMembers(classOrObject, isConstructorParameter) for (member in members) { diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/completion/FirCompletionOutsideSourceRootTest.kt b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/completion/FirCompletionOutsideSourceRootTest.kt index adee6bd0d665..51806881e206 100644 --- a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/completion/FirCompletionOutsideSourceRootTest.kt +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/completion/FirCompletionOutsideSourceRootTest.kt @@ -1,17 +1,25 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.fir.completion +import com.intellij.testFramework.common.runAll import com.intellij.testFramework.LightProjectDescriptor import java.nio.charset.Charset +import org.jetbrains.kotlin.idea.fir.invalidateCaches import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor class FirCompletionOutsideSourceRootTest : KotlinLightCodeInsightFixtureTestCase() { - fun testFunctionName() { - val tempFile = createTempFile("kt", null, "fun ", Charset.defaultCharset()) - myFixture.configureFromExistingVirtualFile(tempFile) - myFixture.completeBasic() - } + fun testFunctionName() { + val tempFile = createTempFile("kt", null, "fun ", Charset.defaultCharset()) + myFixture.configureFromExistingVirtualFile(tempFile) + myFixture.completeBasic() + } + + fun testOverrideHandler() { + val tempFile = createTempFile("kt", null, "interface A {fu}", Charset.defaultCharset()) + myFixture.configureFromExistingVirtualFile(tempFile) + myFixture.completeBasic() + } override fun isFirPlugin(): Boolean { return true @@ -20,4 +28,11 @@ class FirCompletionOutsideSourceRootTest : KotlinLightCodeInsightFixtureTestCase override fun getProjectDescriptor(): LightProjectDescriptor { return KotlinWithJdkAndRuntimeLightProjectDescriptor.getInstance() } + + override fun tearDown() { + runAll( + { project.invalidateCaches() }, + { super.tearDown() } + ) + } } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/ComponentFunction.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/ComponentFunction.kt index bae53998698b..dd5a4dbadbd6 100644 --- a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/ComponentFunction.kt +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/ComponentFunction.kt @@ -6,3 +6,4 @@ import test1.component2 fun foo() { val (a, b) = MyClass() } +// FIR_COMPARISON \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/ComponentFunction.kt.after b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/ComponentFunction.kt.after index bae53998698b..374a3e18116e 100644 --- a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/ComponentFunction.kt.after +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/ComponentFunction.kt.after @@ -6,3 +6,4 @@ import test1.component2 fun foo() { val (a, b) = MyClass() } +// FIR_COMPARISON From 3fd6010bbb31d01f45c9b7ad7e7ab9504be6215b Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 21 Jun 2023 13:30:15 +0200 Subject: [PATCH 013/226] [kotlin] k2: update file structure renderers GitOrigin-RevId: 0b5fa3a9f65ba3f615c43cb80c70bc20f3447693 --- .../KotlinFirStructureElementPresentation.kt | 13 +++ .../AnonymousObjectMembers.after | 14 ++-- .../CheckLocationForKotlin.after | 40 ++++----- .../CheckMemberLocationForJava.after | 24 +++--- .../DoNotShowParentsInLocationJava.after | 10 +-- .../InheritedDelegationMethods.after | 12 +-- .../fileStructure/InheritedInnerClasses.after | 10 +-- .../fileStructure/InheritedJavaMembers.after | 14 ++-- .../fileStructure/InheritedLocalKotlin.after | 20 ++--- .../fileStructure/InheritedMembers.after | 12 +-- ...InheritedMembersWithSubstitutedTypes.after | 12 +-- .../InheritedSAMConversion.after | 10 +-- .../fileStructure/LocalElements.after | 10 +-- .../structureView/fileStructure/Render.after | 82 +++++++++---------- .../fileStructure/SeveralClasses.after | 8 +- .../structureView/fileStructure/Simple.after | 12 +-- 16 files changed, 158 insertions(+), 145 deletions(-) diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/structureView/KotlinFirStructureElementPresentation.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/structureView/KotlinFirStructureElementPresentation.kt index 644d23a17a33..79861fd0ac9d 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/structureView/KotlinFirStructureElementPresentation.kt +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/structureView/KotlinFirStructureElementPresentation.kt @@ -12,11 +12,16 @@ import com.intellij.psi.PsiNamedElement import com.intellij.util.PsiIconUtil import com.intellij.util.ui.StartupUiUtil import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.analysis.api.renderer.base.KtKeywordRenderer import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtCallableReturnTypeFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.bodies.KtParameterDefaultValueRenderer import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererModifierFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.KtTypeParametersRenderer +import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.callables.KtConstructorSymbolRenderer +import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.callables.KtFunctionSymbolRenderer +import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.classifiers.KtNamedClassOrObjectSymbolRenderer import org.jetbrains.kotlin.analysis.api.renderer.declarations.superTypes.KtSuperTypesFilter import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol @@ -25,6 +30,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.idea.base.codeInsight.KotlinIconProvider.getIconFor import org.jetbrains.kotlin.idea.codeInsight.KotlinCodeInsightBundle +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import javax.swing.Icon @@ -49,6 +55,13 @@ internal class KotlinFirStructureElementPresentation( superTypesFilter = KtSuperTypesFilter.NONE parameterDefaultValueRenderer = KtParameterDefaultValueRenderer.THREE_DOTS typeParametersRenderer = KtTypeParametersRenderer.NO_TYPE_PARAMETERS + keywordRender = + KtKeywordRenderer.AsWordWithFilter { keyword -> keyword == KtTokens.CONSTRUCTOR_KEYWORD || keyword == KtTokens.OBJECT_KEYWORD || keyword == KtTokens.COMPANION_KEYWORD } + returnTypeFilter = KtCallableReturnTypeFilter.ALWAYS + classOrObjectRenderer = KtNamedClassOrObjectSymbolRenderer.AS_SOURCE_WITHOUT_PRIMARY_CONSTRUCTOR + parameterDefaultValueRenderer = KtParameterDefaultValueRenderer.NO_DEFAULT_VALUE + constructorRenderer = KtConstructorSymbolRenderer.AS_RAW_SIGNATURE + functionSymbolRenderer = KtFunctionSymbolRenderer.AS_RAW_SIGNATURE } } diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.after index 9a213410a292..6b9b514371ec 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.after @@ -1,10 +1,10 @@ -AnonymousObjectMembers.kt - -class C - -fun bar() + -C + -bar(): Unit -object : Runnable - fun run() - fun xyzzy() - -val f: Runnable + run(): Unit + xyzzy(): Unit + -f: Runnable -object : Runnable - fun run() - fun xyzzy() \ No newline at end of file + run(): Unit + xyzzy(): Unit \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.after index de88c8bbba76..ad83439ef609 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.after @@ -1,21 +1,21 @@ -CheckLocationForKotlin.kt - -class Third - fun equals(other: Any?): Boolean location=→Any - fun foo123() location=→A3 - fun foo12_() location=→A2 - fun foo1_3() location=→A3 - fun foo1__() location=→A1 - fun foo_23() location=→A3 - fun foo_2_() location=→A2 - fun foo__3() location=→A3 - fun foo___() location=→First - fun hashCode(): Int location=→Any - fun toString(): String location=→Any - val bar123: String location=→A3 - val bar12_: String location=→A2 - val bar1_3: String location=→A3 - val bar1__: String location=→A1 - val bar_23: String location=→A3 - val bar_2_: String location=→A2 - val bar__3: String location=→A3 - val bar___: String location=→First \ No newline at end of file + -Third + bar123: String location=→A3 + bar12_: String location=→A2 + bar1_3: String location=→A3 + bar1__: String location=→A1 + bar_23: String location=→A3 + bar_2_: String location=→A2 + bar__3: String location=→A3 + bar___: String location=→First + equals(Any?): Boolean location=→Any + foo123(): Unit location=→A3 + foo12_(): Unit location=→A2 + foo1_3(): Unit location=→A3 + foo1__(): Unit location=→A1 + foo_23(): Unit location=→A3 + foo_2_(): Unit location=→A2 + foo__3(): Unit location=→A3 + foo___(): Unit location=→First + hashCode(): Int location=→Any + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.after index e4835ccfe906..2df957421e3d 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.after @@ -1,13 +1,13 @@ -CheckMemberLocationForJava.kt - -class Some - fun equals(other: Any?): Boolean location=→Any - fun foo123() location=→A3 - fun foo12_() location=→A2 - fun foo1_3() location=→A3 - fun foo1__() location=→A1 - fun foo_23() location=→A3 - fun foo_2_() location=→A2 - fun foo__3() location=→A3 - fun foo___() location=→First - fun hashCode(): Int location=→Any - fun toString(): String location=→Any \ No newline at end of file + -Some + equals(Any?): Boolean location=→Any + foo123(): Unit location=→A3 + foo12_(): Unit location=→A2 + foo1_3(): Unit location=→A3 + foo1__(): Unit location=→A1 + foo_23(): Unit location=→A3 + foo_2_(): Unit location=→A2 + foo__3(): Unit location=→A3 + foo___(): Unit location=→First + hashCode(): Int location=→Any + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.after index 13323459860a..1843706c6b84 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.after @@ -1,6 +1,6 @@ -DoNotShowParentsInLocationJava.kt - -interface Third - fun equals(other: Any?): Boolean location=→Any - fun foo() location=→Second - fun hashCode(): Int location=→Any - fun toString(): String location=→Any \ No newline at end of file + -Third + equals(Any?): Boolean location=→Any + foo(): Unit location=→Second + hashCode(): Int location=→Any + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.after index 46de6e82572e..5df556ccda0e 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.after @@ -1,7 +1,7 @@ -InheritedDelegationMethods.kt - -class Test - fun equals(other: Any?): Boolean location=→Any - fun first() location=→Some - fun hashCode(): Int location=→Any - fun second() location=→Some - fun toString(): String location=→Any \ No newline at end of file + -Test + equals(Any?): Boolean location=→Any + first(): Unit location=→Some + hashCode(): Int location=→Any + second(): Unit location=→Some + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.after index 5b411cec4d5a..5acfd464532e 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.after @@ -1,6 +1,6 @@ -InheritedInnerClasses.kt - -class B - fun equals(other: Any?): Boolean location=→Any - fun foo() location=→A - fun hashCode(): Int location=→Any - fun toString(): String location=→Any \ No newline at end of file + -B + equals(Any?): Boolean location=→Any + foo(): Unit location=→A + hashCode(): Int location=→Any + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.after index 37115c31f57e..8a913667ac07 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.after @@ -1,8 +1,8 @@ -InheritedJavaMembers.kt - -class InheritedJavaMembers - constructor() - fun call(): String? location=→Callable - fun equals(other: Any?): Boolean location=→Any - fun hashCode(): Int location=→Any - fun test() - fun toString(): String location=→Any \ No newline at end of file + -InheritedJavaMembers + call(): String? location=→Callable + constructor InheritedJavaMembers() + equals(Any?): Boolean location=→Any + hashCode(): Int location=→Any + test(): Unit + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.after index 32742480e3f0..1102ca5642bc 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.after @@ -1,11 +1,11 @@ -InheritedLocalKotlin.kt - -class A - fun equals(other: Any?): Boolean location=→Any - fun hashCode(): Int location=→Any - fun some() - fun toString(): String location=→Any - val a: Int - -class B - fun some() location=→TA - val a: Int location=→TA - interface TA \ No newline at end of file + -A + a: Int + equals(Any?): Boolean location=→Any + hashCode(): Int location=→Any + some(): Unit + toString(): String location=→Any + -B + a: Int location=→TA + some(): Unit location=→TA + TA \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.after index aa55072ab2bc..50d4a74adb89 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.after @@ -1,7 +1,7 @@ -InheritedMembers.kt - -class Test - fun equals(other: Any?): Boolean location=→Any - fun hashCode(): Int location=→Any - fun run() location=→Runnable - fun test() - fun toString(): String location=→Any \ No newline at end of file + -Test + equals(Any?): Boolean location=→Any + hashCode(): Int location=→Any + run(): Unit location=→Runnable + test(): Unit + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.after index 6de1524e7bd5..89d7c03c944e 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.after @@ -1,7 +1,7 @@ -InheritedMembersWithSubstitutedTypes.kt - -interface Third - fun equals(other: Any?): Boolean location=→Any - fun foo(a: T) location=→First - fun hashCode(): Int location=→Any - fun toString(): String location=→Any - val a: U location=→Second \ No newline at end of file + -Third + a: U location=→Second + equals(Any?): Boolean location=→Any + foo(T): Unit location=→First + hashCode(): Int location=→Any + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.after index 96448f6c64cf..976211c15c70 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.after @@ -1,6 +1,6 @@ -InheritedSAMConversion.kt - -class KotlinTest - fun equals(other: Any?): Boolean location=→Any - fun foo(samClass: TestSAM.SamClass?) location=→TestSAM - fun hashCode(): Int location=→Any - fun toString(): String location=→Any \ No newline at end of file + -KotlinTest + equals(Any?): Boolean location=→Any + foo(TestSAM.SamClass!): Unit location=→TestSAM + hashCode(): Int location=→Any + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.after index 20375f521993..429f32a67a70 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.after @@ -1,7 +1,7 @@ -LocalElements.kt - -fun foo() - -class X + -foo(): Unit + bar(): Unit + -X - - fun quux() - fun xyzzy() - fun bar() \ No newline at end of file + quux(): Unit + xyzzy(): Unit \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.after index 301b3e209871..f7a27220ce93 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.after @@ -1,45 +1,45 @@ -Render.kt - class A1 - -class A2(a: Int, b: String = ...) - a: Int - b: String = ... - constructor(a: Int, b: String = ...) - -class A3(a: Int) - a: Int - constructor(a: Int) - var b: String - -class A4(t: T?) - constructor(t: T?) - t: T? - -class A5 - class Inner1 - class Inner2 - -class A6 - -companion object - fun test() - -class A7 - - val a: Int - class TestWithWhere - -class WithDefaultArgs(a: Int = ..., b: String = ...) - a: Int = ... - constructor(a: Int = ..., b: String = ...) - -enum class Enum1 + - Enum1 FIRST SECOND - fun Comparable.extension2() - fun String.extension1() - fun test1() - fun test2(a: String?) - fun test3(t: T, u: U) - fun test4(t: T) - fun test5(): String - fun test6(): Comparable - fun testWithWhere() - fun withDefaulArgs(a: Int = ..., b: String = ...) - interface Trait - interface Trait1 - val a: Int - -val b: Any + A1 + -A2 + a: Int + b: String + constructor A2(Int, String) + -A3 + a: Int + b: String + constructor A3(Int) + -A4 + constructor A4(T?) + t: T? + -A5 + Inner1 + Inner2 + -A6 + -companion object + test(): Unit + -A7 + + a: Int + a: Int + -b: Any object - val Comparable.a: String \ No newline at end of file + Comparable.a: String + Comparable.extension2(): Unit + String.extension1(): Unit + test1(): Unit + test2(String?): Unit + test3(T, U): Unit + test4(T): Unit + test5(): String + test6(): Comparable + TestWithWhere + testWithWhere(): Unit + Trait + Trait1 + withDefaulArgs(Int, String): Unit + -WithDefaultArgs + a: Int + constructor WithDefaultArgs(Int, String) \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.after index ab742c21552d..618c426eddd7 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.after @@ -1,5 +1,5 @@ -SeveralClasses.kt - class B - class Other - class Some - interface A \ No newline at end of file + A + B + Other + Some \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.after index 794fc5583500..f6d13367b2bb 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.after +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.after @@ -1,7 +1,7 @@ -Simple.kt - -class Test(str: String) - constructor(str: String) - fun foo(): Int - fun other() - str: String - val some: Int \ No newline at end of file + -Test + constructor Test(String) + foo(): Int + other(): Unit + some: Int + str: String \ No newline at end of file From da0868389d54c5d3ccf8cc0c07b871d5f636bcc0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 21 Jun 2023 20:47:09 +0200 Subject: [PATCH 014/226] [kotlin] k2: file structure: reuse common test data GitOrigin-RevId: 656d9faeeb4c2564162b838d7f61ca55249e2c6a --- .../AbstractKotlinFirFileStructureTest.kt | 9 +++ .../KotlinFirFileStructureTestGenerated.java | 43 +++++++------ .../AnonymousObjectMembers.after | 10 --- .../fileStructure/AnonymousObjectMembers.kt | 15 ----- .../CheckLocationForKotlin.Data.kt | 62 ------------------- .../CheckLocationForKotlin.after | 21 ------- .../fileStructure/CheckLocationForKotlin.kt | 5 -- .../CheckMemberLocationForJava.Data.java | 40 ------------ .../CheckMemberLocationForJava.after | 13 ---- .../CheckMemberLocationForJava.kt | 3 - .../DoNotShowParentsInLocationJava.Data.kt | 5 -- .../DoNotShowParentsInLocationJava.after | 6 -- .../DoNotShowParentsInLocationJava.kt | 3 - .../fileStructure/EmptyFile.after | 1 - .../structureView/fileStructure/EmptyFile.kt | 0 .../InheritedDelegationMethods.Data.kt | 9 --- .../InheritedDelegationMethods.after | 7 --- .../InheritedDelegationMethods.kt | 3 - .../InheritedInnerClasses.Data.kt | 6 -- .../fileStructure/InheritedInnerClasses.after | 6 -- .../fileStructure/InheritedInnerClasses.kt | 5 -- .../fileStructure/InheritedJavaMembers.kt | 8 --- .../fileStructure/InheritedLocalKotlin.after | 11 ---- .../fileStructure/InheritedLocalKotlin.kt | 15 ----- .../fileStructure/InheritedMembers.after | 7 --- .../fileStructure/InheritedMembers.kt | 7 --- .../fileStructure/InheritedMembersOfEnum.kt | 6 -- ...heritedMembersWithSubstitutedTypes.Data.kt | 7 --- ...InheritedMembersWithSubstitutedTypes.after | 7 --- .../InheritedMembersWithSubstitutedTypes.kt | 5 -- .../InheritedSAMConversion.Data.java | 9 --- .../InheritedSAMConversion.after | 6 -- .../fileStructure/InheritedSAMConversion.kt | 6 -- .../InheritedSynthesizedFromDataClass.after | 5 -- .../InheritedSynthesizedFromDataClass.kt | 5 -- .../fileStructure/LocalElements.after | 7 --- .../fileStructure/LocalElements.kt | 13 ---- .../structureView/fileStructure/Render.kt | 54 ---------------- .../fileStructure/SeveralClasses.after | 5 -- .../fileStructure/SeveralClasses.kt | 4 -- .../structureView/fileStructure/Simple.after | 7 --- .../structureView/fileStructure/Simple.kt | 5 -- .../KotlinFileStructureTestBase.kt | 2 +- .../InheritedJavaMembers.fir.after} | 0 .../fileStructure/InheritedMembers.after | 3 +- .../fileStructure/InheritedMembers.kt | 2 +- .../InheritedMembersOfEnum.fir.after} | 0 ...nheritedSynthesizedFromDataClass.fir.after | 7 +++ .../fileStructure/Render.fir.after} | 4 +- .../GenerateK2StructureViewTests.kt | 2 +- 50 files changed, 47 insertions(+), 444 deletions(-) delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.Data.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.Data.java delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.Data.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/EmptyFile.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/EmptyFile.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.Data.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.Data.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersOfEnum.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.Data.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.Data.java delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.kt delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.after delete mode 100644 plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.kt rename plugins/kotlin/{code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.after => idea/tests/testData/structureView/fileStructure/InheritedJavaMembers.fir.after} (100%) rename plugins/kotlin/{code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersOfEnum.after => idea/tests/testData/structureView/fileStructure/InheritedMembersOfEnum.fir.after} (100%) create mode 100644 plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.fir.after rename plugins/kotlin/{code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.after => idea/tests/testData/structureView/fileStructure/Render.fir.after} (96%) diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/test/org/jetbrains/kotlin/idea/k2/structureView/AbstractKotlinFirFileStructureTest.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/test/org/jetbrains/kotlin/idea/k2/structureView/AbstractKotlinFirFileStructureTest.kt index be4bfc4cc063..0fbc40b89f32 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/test/org/jetbrains/kotlin/idea/k2/structureView/AbstractKotlinFirFileStructureTest.kt +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/test/org/jetbrains/kotlin/idea/k2/structureView/AbstractKotlinFirFileStructureTest.kt @@ -7,6 +7,7 @@ import org.jetbrains.kotlin.idea.fir.invalidateCaches import org.jetbrains.kotlin.idea.k2.codeinsight.structureView.KotlinFirInheritedMembersNodeProvider import org.jetbrains.kotlin.idea.structureView.AbstractKotlinFileStructureTest import org.jetbrains.kotlin.idea.test.runAll +import java.io.File abstract class AbstractKotlinFirFileStructureTest : AbstractKotlinFileStructureTest() { override fun isFirPlugin(): Boolean { @@ -23,4 +24,12 @@ abstract class AbstractKotlinFirFileStructureTest : AbstractKotlinFileStructureT ThrowableRunnable { super.tearDown() } ) } + + override fun getFileName(ext: String): String { + val firSpecificName = getTestName(false) + ".fir" + ( if (ext.isEmpty()) "" else ".$ext") + if (File(testDataDirectory, firSpecificName).exists()) { + return firSpecificName + } + return super.getFileName(ext) + } } \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/test/org/jetbrains/kotlin/idea/k2/structureView/KotlinFirFileStructureTestGenerated.java b/plugins/kotlin/code-insight/kotlin.code-insight.k2/test/org/jetbrains/kotlin/idea/k2/structureView/KotlinFirFileStructureTestGenerated.java index abd0c4936c72..58a953b08b89 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/test/org/jetbrains/kotlin/idea/k2/structureView/KotlinFirFileStructureTestGenerated.java +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/test/org/jetbrains/kotlin/idea/k2/structureView/KotlinFirFileStructureTestGenerated.java @@ -17,7 +17,7 @@ import org.junit.runner.RunWith; @TestRoot("code-insight/kotlin.code-insight.k2") @TestDataPath("$CONTENT_ROOT") @RunWith(JUnit3RunnerWithInners.class) -@TestMetadata("testData/structureView/fileStructure") +@TestMetadata("../../idea/tests/testData/structureView/fileStructure") public class KotlinFirFileStructureTestGenerated extends AbstractKotlinFirFileStructureTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); @@ -25,91 +25,96 @@ public class KotlinFirFileStructureTestGenerated extends AbstractKotlinFirFileSt @TestMetadata("AnonymousObjectMembers.kt") public void testAnonymousObjectMembers() throws Exception { - runTest("testData/structureView/fileStructure/AnonymousObjectMembers.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/AnonymousObjectMembers.kt"); } @TestMetadata("CheckLocationForKotlin.kt") public void testCheckLocationForKotlin() throws Exception { - runTest("testData/structureView/fileStructure/CheckLocationForKotlin.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/CheckLocationForKotlin.kt"); } @TestMetadata("CheckMemberLocationForJava.kt") public void testCheckMemberLocationForJava() throws Exception { - runTest("testData/structureView/fileStructure/CheckMemberLocationForJava.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/CheckMemberLocationForJava.kt"); } @TestMetadata("DoNotShowParentsInLocationJava.kt") public void testDoNotShowParentsInLocationJava() throws Exception { - runTest("testData/structureView/fileStructure/DoNotShowParentsInLocationJava.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.kt"); } @TestMetadata("EmptyFile.kt") public void testEmptyFile() throws Exception { - runTest("testData/structureView/fileStructure/EmptyFile.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/EmptyFile.kt"); } @TestMetadata("InheritedDelegationMethods.kt") public void testInheritedDelegationMethods() throws Exception { - runTest("testData/structureView/fileStructure/InheritedDelegationMethods.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedDelegationMethods.kt"); } @TestMetadata("InheritedInnerClasses.kt") public void testInheritedInnerClasses() throws Exception { - runTest("testData/structureView/fileStructure/InheritedInnerClasses.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedInnerClasses.kt"); } @TestMetadata("InheritedJavaMembers.kt") public void testInheritedJavaMembers() throws Exception { - runTest("testData/structureView/fileStructure/InheritedJavaMembers.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedJavaMembers.kt"); } @TestMetadata("InheritedLocalKotlin.kt") public void testInheritedLocalKotlin() throws Exception { - runTest("testData/structureView/fileStructure/InheritedLocalKotlin.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedLocalKotlin.kt"); } @TestMetadata("InheritedMembers.kt") public void testInheritedMembers() throws Exception { - runTest("testData/structureView/fileStructure/InheritedMembers.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedMembers.kt"); } @TestMetadata("InheritedMembersOfEnum.kt") public void testInheritedMembersOfEnum() throws Exception { - runTest("testData/structureView/fileStructure/InheritedMembersOfEnum.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedMembersOfEnum.kt"); } @TestMetadata("InheritedMembersWithSubstitutedTypes.kt") public void testInheritedMembersWithSubstitutedTypes() throws Exception { - runTest("testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.kt"); } @TestMetadata("InheritedSAMConversion.kt") public void testInheritedSAMConversion() throws Exception { - runTest("testData/structureView/fileStructure/InheritedSAMConversion.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedSAMConversion.kt"); } @TestMetadata("InheritedSynthesizedFromDataClass.kt") public void testInheritedSynthesizedFromDataClass() throws Exception { - runTest("testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.kt"); } @TestMetadata("LocalElements.kt") public void testLocalElements() throws Exception { - runTest("testData/structureView/fileStructure/LocalElements.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/LocalElements.kt"); } @TestMetadata("Render.kt") public void testRender() throws Exception { - runTest("testData/structureView/fileStructure/Render.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/Render.kt"); + } + + @TestMetadata("Script.kts") + public void testScript() throws Exception { + runTest("../../idea/tests/testData/structureView/fileStructure/Script.kts"); } @TestMetadata("SeveralClasses.kt") public void testSeveralClasses() throws Exception { - runTest("testData/structureView/fileStructure/SeveralClasses.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/SeveralClasses.kt"); } @TestMetadata("Simple.kt") public void testSimple() throws Exception { - runTest("testData/structureView/fileStructure/Simple.kt"); + runTest("../../idea/tests/testData/structureView/fileStructure/Simple.kt"); } } diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.after deleted file mode 100644 index 6b9b514371ec..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.after +++ /dev/null @@ -1,10 +0,0 @@ --AnonymousObjectMembers.kt - -C - -bar(): Unit - -object : Runnable - run(): Unit - xyzzy(): Unit - -f: Runnable - -object : Runnable - run(): Unit - xyzzy(): Unit \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.kt deleted file mode 100644 index bf7ac65a8761..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/AnonymousObjectMembers.kt +++ /dev/null @@ -1,15 +0,0 @@ -class C { - val f = object : Runnable { - fun run() { } - - fun xyzzy() { } - } - - fun bar() { - val g = object : Runnable { - fun run() { } - - fun xyzzy() { } - } - } -} \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.Data.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.Data.kt deleted file mode 100644 index 5863771b3a69..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.Data.kt +++ /dev/null @@ -1,62 +0,0 @@ -interface First { - fun foo123() - fun foo12_() - fun foo1_3() - fun foo_23() - - val bar123: String - val bar12_: String - val bar1_3: String - val bar_23: String - - fun foo1__() - fun foo_2_() - fun foo__3() - - val bar1__: String - val bar_2_: String - val bar__3: String - - fun foo___() - val bar___: String -} - -abstract class A1 : First { - override fun foo123() {} - override fun foo12_() {} - override fun foo1_3() {} - - override val bar123 = "test" - override val bar12_ = "test" - override val bar1_3 = "test" - - override fun foo1__() {} - override val bar1__ = "test" -} - -abstract class A2 : A1() { - override fun foo123() {} - override fun foo12_() {} - override fun foo_23() {} - - override val bar123 = "test" - override val bar12_ = "test" - override val bar_23 = "test" - - override fun foo_2_() {} - override val bar_2_ = "test" -} - -open class A3 : A2() { - override fun foo123() {} - override fun foo1_3() {} - override fun foo_23() {} - - override val bar123 = "test" - override val bar1_3 = "test" - override val bar_23 = "test" - - override fun foo__3() {} - override val bar__3 = "test" -} - diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.after deleted file mode 100644 index ad83439ef609..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.after +++ /dev/null @@ -1,21 +0,0 @@ --CheckLocationForKotlin.kt - -Third - bar123: String location=→A3 - bar12_: String location=→A2 - bar1_3: String location=→A3 - bar1__: String location=→A1 - bar_23: String location=→A3 - bar_2_: String location=→A2 - bar__3: String location=→A3 - bar___: String location=→First - equals(Any?): Boolean location=→Any - foo123(): Unit location=→A3 - foo12_(): Unit location=→A2 - foo1_3(): Unit location=→A3 - foo1__(): Unit location=→A1 - foo_23(): Unit location=→A3 - foo_2_(): Unit location=→A2 - foo__3(): Unit location=→A3 - foo___(): Unit location=→First - hashCode(): Int location=→Any - toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.kt deleted file mode 100644 index 6b01557d9457..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckLocationForKotlin.kt +++ /dev/null @@ -1,5 +0,0 @@ -class Third : A3() { - -} - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.Data.java b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.Data.java deleted file mode 100644 index 01324c5c0842..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.Data.java +++ /dev/null @@ -1,40 +0,0 @@ -public class JavaClass { - public interface First { - void foo123(); - void foo12_(); - void foo1_3(); - void foo_23(); - - void foo1__(); - void foo_2_(); - void foo__3(); - - void foo___(); - } - - public static abstract class A1 implements First { - @Override public void foo123() {} - @Override public void foo12_() {} - @Override public void foo1_3() {} - - @Override public void foo1__() {} - } - - public static abstract class A2 extends A1 { - @Override public void foo123() {} - @Override public void foo12_() {} - @Override public void foo_23() {} - - @Override public void foo_2_() {} - } - - public static class A3 extends A2 { - @Override public void foo123() {} - @Override public void foo1_3() {} - @Override public void foo_23() {} - - @Override public void foo__3() {} - - // @Override public void foo___() {} // Removed intentionally - } -} diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.after deleted file mode 100644 index 2df957421e3d..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.after +++ /dev/null @@ -1,13 +0,0 @@ --CheckMemberLocationForJava.kt - -Some - equals(Any?): Boolean location=→Any - foo123(): Unit location=→A3 - foo12_(): Unit location=→A2 - foo1_3(): Unit location=→A3 - foo1__(): Unit location=→A1 - foo_23(): Unit location=→A3 - foo_2_(): Unit location=→A2 - foo__3(): Unit location=→A3 - foo___(): Unit location=→First - hashCode(): Int location=→Any - toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.kt deleted file mode 100644 index 6130e8fc25ac..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/CheckMemberLocationForJava.kt +++ /dev/null @@ -1,3 +0,0 @@ -class Some: JavaClass.A3() - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.Data.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.Data.kt deleted file mode 100644 index 48de19719efc..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.Data.kt +++ /dev/null @@ -1,5 +0,0 @@ -interface First - -interface Second : First { - fun foo() -} \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.after deleted file mode 100644 index 1843706c6b84..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.after +++ /dev/null @@ -1,6 +0,0 @@ --DoNotShowParentsInLocationJava.kt - -Third - equals(Any?): Boolean location=→Any - foo(): Unit location=→Second - hashCode(): Int location=→Any - toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.kt deleted file mode 100644 index 8ad176bf8ea3..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/DoNotShowParentsInLocationJava.kt +++ /dev/null @@ -1,3 +0,0 @@ -interface Third: Second - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/EmptyFile.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/EmptyFile.after deleted file mode 100644 index 370952a863e5..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/EmptyFile.after +++ /dev/null @@ -1 +0,0 @@ -EmptyFile.kt \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/EmptyFile.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/EmptyFile.kt deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.Data.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.Data.kt deleted file mode 100644 index e4726da3caee..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.Data.kt +++ /dev/null @@ -1,9 +0,0 @@ -interface Some { - fun first() - fun second() -} - -class ClassSome: Some { - override fun first() {} - override fun second() {} -} \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.after deleted file mode 100644 index 5df556ccda0e..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.after +++ /dev/null @@ -1,7 +0,0 @@ --InheritedDelegationMethods.kt - -Test - equals(Any?): Boolean location=→Any - first(): Unit location=→Some - hashCode(): Int location=→Any - second(): Unit location=→Some - toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.kt deleted file mode 100644 index a48ef3f43f97..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedDelegationMethods.kt +++ /dev/null @@ -1,3 +0,0 @@ -class Test: Some by ClassSome() - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.Data.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.Data.kt deleted file mode 100644 index 86c17c7db65a..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.Data.kt +++ /dev/null @@ -1,6 +0,0 @@ -open class A { - class I1 - inner class I2 - - fun foo() {} -} \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.after deleted file mode 100644 index 5acfd464532e..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.after +++ /dev/null @@ -1,6 +0,0 @@ --InheritedInnerClasses.kt - -B - equals(Any?): Boolean location=→Any - foo(): Unit location=→A - hashCode(): Int location=→Any - toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.kt deleted file mode 100644 index 45a3b2d02d20..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedInnerClasses.kt +++ /dev/null @@ -1,5 +0,0 @@ -class B: A() - -// Inner classes are not shown, same to Java - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.kt deleted file mode 100644 index e36c9969a437..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.kt +++ /dev/null @@ -1,8 +0,0 @@ -import java.util.concurrent.Callable - -public abstract class InheritedJavaMembers() : Callable { - fun test() { - } -} - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.after deleted file mode 100644 index 1102ca5642bc..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.after +++ /dev/null @@ -1,11 +0,0 @@ --InheritedLocalKotlin.kt - -A - a: Int - equals(Any?): Boolean location=→Any - hashCode(): Int location=→Any - some(): Unit - toString(): String location=→Any - -B - a: Int location=→TA - some(): Unit location=→TA - TA \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.kt deleted file mode 100644 index 401529a3a7e3..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedLocalKotlin.kt +++ /dev/null @@ -1,15 +0,0 @@ -interface TA { - fun some() - val a: Int -} - -class A : TA { - override fun some() { - } - - override val a: Int = 0 -} - -abstract class B : TA - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.after deleted file mode 100644 index 50d4a74adb89..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.after +++ /dev/null @@ -1,7 +0,0 @@ --InheritedMembers.kt - -Test - equals(Any?): Boolean location=→Any - hashCode(): Int location=→Any - run(): Unit location=→Runnable - test(): Unit - toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.kt deleted file mode 100644 index ca41c13b56a3..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembers.kt +++ /dev/null @@ -1,7 +0,0 @@ -class Test: Runnable { - fun test() { - - } -} - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersOfEnum.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersOfEnum.kt deleted file mode 100644 index 2666c7f25716..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersOfEnum.kt +++ /dev/null @@ -1,6 +0,0 @@ -enum class Test { - FIRST, - SECOND -} - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.Data.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.Data.kt deleted file mode 100644 index 53e4e92b97f3..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.Data.kt +++ /dev/null @@ -1,7 +0,0 @@ -interface First { - fun foo(a: T) -} - -interface Second : First { - val a: U -} \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.after deleted file mode 100644 index 89d7c03c944e..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.after +++ /dev/null @@ -1,7 +0,0 @@ --InheritedMembersWithSubstitutedTypes.kt - -Third - a: U location=→Second - equals(Any?): Boolean location=→Any - foo(T): Unit location=→First - hashCode(): Int location=→Any - toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.kt deleted file mode 100644 index 4f56362050ce..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.kt +++ /dev/null @@ -1,5 +0,0 @@ -interface Third: Second - -// Original type names are shown in members, behaviour is same to Java. - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.Data.java b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.Data.java deleted file mode 100644 index 7c44096e4a9a..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.Data.java +++ /dev/null @@ -1,9 +0,0 @@ -public class TestSAM { - public interface SamClass { - void foo(); - } - - void foo(SamClass samClass) { - - } -} diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.after deleted file mode 100644 index 976211c15c70..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.after +++ /dev/null @@ -1,6 +0,0 @@ --InheritedSAMConversion.kt - -KotlinTest - equals(Any?): Boolean location=→Any - foo(TestSAM.SamClass!): Unit location=→TestSAM - hashCode(): Int location=→Any - toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.kt deleted file mode 100644 index 8921da07298f..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSAMConversion.kt +++ /dev/null @@ -1,6 +0,0 @@ -class KotlinTest : TestSAM - -// TODO: Show both methods - synthetic and original (base mehtod without Kotlin signature) -// TODO: Show location for synthetic method - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.after deleted file mode 100644 index b131dea14486..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.after +++ /dev/null @@ -1,5 +0,0 @@ --InheritedSynthesizedFromDataClass.kt - -class TestData(a: Int) - a: Int - constructor(a: Int) - fun some() \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.kt deleted file mode 100644 index cc624f804acd..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.kt +++ /dev/null @@ -1,5 +0,0 @@ -data class TestData(val a: Int) { - fun some() {} -} - -// WITH_INHERITED \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.after deleted file mode 100644 index 429f32a67a70..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.after +++ /dev/null @@ -1,7 +0,0 @@ --LocalElements.kt - -foo(): Unit - bar(): Unit - -X - - - quux(): Unit - xyzzy(): Unit \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.kt deleted file mode 100644 index 88cdac5467cb..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/LocalElements.kt +++ /dev/null @@ -1,13 +0,0 @@ -fun foo() { - fun bar() { } - - class X { - init { - fun quux() { - } - } - - fun xyzzy() { - } - } -} diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.kt deleted file mode 100644 index 26586d075fcb..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.kt +++ /dev/null @@ -1,54 +0,0 @@ -//package test.render - -fun test1() {} -fun test2(a: String?) {} -fun test3(t: T, u: U) {} -fun test4(t: T) {} -fun test5(): String = "some" -fun test6(): Comparable = "some" - -fun String.extension1() {} -fun Comparable.extension2() {} - -val a: Int = 1 -val Comparable.a = "String" -internal val b = object {} - -class A1 -class A2(val a: Int, var b: String = "some") -class A3(val a: Int) { - var b = "some" -} -class A4(val t: T?) -class A5 { - class Inner1 - inner class Inner2 -} -class A6 { - companion object { - fun test() {} - } -} -class A7 { - val a: Int - - init { - a = 1 - } -} - -enum class Enum1 { - FIRST, - SECOND -} - -interface Trait -interface Trait1: Trait - -class TestWithWhere where T: Any? -fun testWithWhere() where T: String {} - -class WithDefaultArgs(val a: Int = 1, b: String = "str") -fun withDefaulArgs(a: Int = 1, b: String = "str") {} - - diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.after deleted file mode 100644 index 618c426eddd7..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.after +++ /dev/null @@ -1,5 +0,0 @@ --SeveralClasses.kt - A - B - Other - Some \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.kt deleted file mode 100644 index 97e4808d2850..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/SeveralClasses.kt +++ /dev/null @@ -1,4 +0,0 @@ -interface A -open class B -class Some: B(), A -class Other: A \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.after b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.after deleted file mode 100644 index f6d13367b2bb..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.after +++ /dev/null @@ -1,7 +0,0 @@ --Simple.kt - -Test - constructor Test(String) - foo(): Int - other(): Unit - some: Int - str: String \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.kt deleted file mode 100644 index 024b9c3d0d86..000000000000 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Simple.kt +++ /dev/null @@ -1,5 +0,0 @@ -class Test(val str: String) { - private val some = 1 - protected fun foo() = some - public fun other() {} -} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/structureView/KotlinFileStructureTestBase.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/structureView/KotlinFileStructureTestBase.kt index bc2435b676c1..c952f4e2ec8f 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/structureView/KotlinFileStructureTestBase.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/structureView/KotlinFileStructureTestBase.kt @@ -39,7 +39,7 @@ abstract class KotlinFileStructureTestBase : KotlinLightCodeInsightFixtureTestCa ) } - protected fun getFileName(ext: String): String { + protected open fun getFileName(ext: String): String { return getTestName(false) + if (StringUtil.isEmpty(ext)) "" else ".$ext" } diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.after b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedJavaMembers.fir.after similarity index 100% rename from plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedJavaMembers.after rename to plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedJavaMembers.fir.after diff --git a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembers.after b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembers.after index 310b334b4513..50d4a74adb89 100644 --- a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembers.after +++ b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembers.after @@ -2,5 +2,6 @@ -Test equals(Any?): Boolean location=→Any hashCode(): Int location=→Any + run(): Unit location=→Runnable test(): Unit - toString(): String location=→Any + toString(): String location=→Any \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembers.kt b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembers.kt index 540c361d06ae..ca41c13b56a3 100644 --- a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembers.kt +++ b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembers.kt @@ -1,4 +1,4 @@ -class Test: Runable { +class Test: Runnable { fun test() { } diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersOfEnum.after b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembersOfEnum.fir.after similarity index 100% rename from plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/InheritedMembersOfEnum.after rename to plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembersOfEnum.fir.after diff --git a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.fir.after b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.fir.after new file mode 100644 index 000000000000..d757ce6bf245 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedSynthesizedFromDataClass.fir.after @@ -0,0 +1,7 @@ +-InheritedSynthesizedFromDataClass.kt + -Derived + a: Int + field: Int + some(): Unit location=→TestData + -TestData + constructor TestData(Int) \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.after b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/Render.fir.after similarity index 96% rename from plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.after rename to plugins/kotlin/idea/tests/testData/structureView/fileStructure/Render.fir.after index f7a27220ce93..beac0c94c747 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/testData/structureView/fileStructure/Render.after +++ b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/Render.fir.after @@ -28,6 +28,8 @@ object Comparable.a: String Comparable.extension2(): Unit + Interface + Interface1 String.extension1(): Unit test1(): Unit test2(String?): Unit @@ -37,8 +39,6 @@ test6(): Comparable TestWithWhere testWithWhere(): Unit - Trait - Trait1 withDefaulArgs(Int, String): Unit -WithDefaultArgs a: Int diff --git a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2StructureViewTests.kt b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2StructureViewTests.kt index f9ee22d5f79c..6ee5266d222d 100644 --- a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2StructureViewTests.kt +++ b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2StructureViewTests.kt @@ -8,7 +8,7 @@ import org.jetbrains.kotlin.testGenerator.model.* internal fun MutableTWorkspace.generateK2StructureViewTests() { testGroup("code-insight/kotlin.code-insight.k2") { testClass { - model("structureView/fileStructure", pattern = Patterns.KT_OR_KTS_WITHOUT_DOTS) + model("../../../idea/tests/testData/structureView/fileStructure", pattern = Patterns.KT_OR_KTS_WITHOUT_DOTS) } } } \ No newline at end of file From b6e1ba10c61eef33c5d6b48e4b3e3af27577631b Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 22 Jun 2023 14:34:13 +0200 Subject: [PATCH 015/226] [kotlin] k2 file structure: update according to renderer changes GitOrigin-RevId: e055325608d3dd21b8baa53b0683f3cafd14d18b --- .../KotlinPsiElementMemberChooserObject.kt | 4 ++-- .../KotlinFirStructureElementPresentation.kt | 15 +++++++++----- .../core/overrideImplement/KtClassMember.kt | 17 ++++++++-------- .../KtGenerateMembersHandler.kt | 5 ++--- .../keywords/OverrideKeywordHandler.kt | 4 ++-- .../InheritedMembersOfEnum.fir.after | 20 +++++++++---------- .../fileStructure/Render.fir.after | 6 +++--- .../memberInfo/K2MemberInfoSupport.kt | 4 ++-- 8 files changed, 40 insertions(+), 35 deletions(-) diff --git a/plugins/kotlin/base/code-insight/src/org/jetbrains/kotlin/idea/base/codeInsight/KotlinPsiElementMemberChooserObject.kt b/plugins/kotlin/base/code-insight/src/org/jetbrains/kotlin/idea/base/codeInsight/KotlinPsiElementMemberChooserObject.kt index 1cca948ce965..6eb253ffa507 100644 --- a/plugins/kotlin/base/code-insight/src/org/jetbrains/kotlin/idea/base/codeInsight/KotlinPsiElementMemberChooserObject.kt +++ b/plugins/kotlin/base/code-insight/src/org/jetbrains/kotlin/idea/base/codeInsight/KotlinPsiElementMemberChooserObject.kt @@ -13,7 +13,7 @@ import com.intellij.util.concurrency.AppExecutorUtil import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.analyze import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource -import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererModifierFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererKeywordFilter import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol @@ -42,7 +42,7 @@ class KotlinPsiElementMemberChooserObject( companion object { private val renderer = KtDeclarationRendererForSource.WITH_SHORT_NAMES.with { modifiersRenderer = modifiersRenderer.with { - modifierFilter = KtRendererModifierFilter.NONE + keywordsRenderer = keywordsRenderer.with { keywordFilter = KtRendererKeywordFilter.NONE } } } diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/structureView/KotlinFirStructureElementPresentation.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/structureView/KotlinFirStructureElementPresentation.kt index 79861fd0ac9d..3f99dbb9eca4 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/structureView/KotlinFirStructureElementPresentation.kt +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/structureView/KotlinFirStructureElementPresentation.kt @@ -12,12 +12,12 @@ import com.intellij.psi.PsiNamedElement import com.intellij.util.PsiIconUtil import com.intellij.util.ui.StartupUiUtil import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.analysis.api.renderer.base.KtKeywordRenderer +import org.jetbrains.kotlin.analysis.api.renderer.base.KtKeywordsRenderer import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtCallableReturnTypeFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.bodies.KtParameterDefaultValueRenderer import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource -import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererModifierFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererKeywordFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.KtTypeParametersRenderer import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.callables.KtConstructorSymbolRenderer import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.callables.KtFunctionSymbolRenderer @@ -49,14 +49,19 @@ internal class KotlinFirStructureElementPresentation( } modifiersRenderer = modifiersRenderer.with { - modifierFilter = KtRendererModifierFilter.NONE + keywordsRenderer = keywordsRenderer.with { keywordFilter = KtRendererKeywordFilter.NONE } } superTypesFilter = KtSuperTypesFilter.NONE parameterDefaultValueRenderer = KtParameterDefaultValueRenderer.THREE_DOTS typeParametersRenderer = KtTypeParametersRenderer.NO_TYPE_PARAMETERS - keywordRender = - KtKeywordRenderer.AsWordWithFilter { keyword -> keyword == KtTokens.CONSTRUCTOR_KEYWORD || keyword == KtTokens.OBJECT_KEYWORD || keyword == KtTokens.COMPANION_KEYWORD } + keywordsRenderer = KtKeywordsRenderer.AS_WORD.with { + keywordFilter = KtRendererKeywordFilter.onlyWith( + KtTokens.CONSTRUCTOR_KEYWORD, + KtTokens.OBJECT_KEYWORD, + KtTokens.COMPANION_KEYWORD + ) + } returnTypeFilter = KtCallableReturnTypeFilter.ALWAYS classOrObjectRenderer = KtNamedClassOrObjectSymbolRenderer.AS_SOURCE_WITHOUT_PRIMARY_CONSTRUCTOR parameterDefaultValueRenderer = KtParameterDefaultValueRenderer.NO_DEFAULT_VALUE diff --git a/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtClassMember.kt b/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtClassMember.kt index 4d697e9fe8e2..bfd1637207d2 100644 --- a/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtClassMember.kt +++ b/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtClassMember.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.analysis.api.annotations.annotations import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtDeclarationRenderer import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource -import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererModifierFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererKeywordFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererOtherModifiersProvider import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol @@ -119,7 +119,7 @@ fun KtAnalysisSession.generateMember( } modifiersRenderer = modifiersRenderer.with { - modifierFilter = KtRendererModifierFilter.without(KtTokens.OPERATOR_KEYWORD) + keywordsRenderer = keywordsRenderer.with { keywordFilter = KtRendererKeywordFilter.without(KtTokens.OPERATOR_KEYWORD) } modalityProvider = modalityProvider.onlyIf { s -> s != symbol } @@ -298,21 +298,22 @@ private object RenderOptions { annotationFilter = KtRendererAnnotationsFilter.NONE } modifiersRenderer = modifiersRenderer.with { - modifierFilter = KtRendererModifierFilter.onlyWith(KtTokens.OVERRIDE_KEYWORD) + keywordsRenderer = keywordsRenderer.with { keywordFilter = KtRendererKeywordFilter.onlyWith(KtTokens.OVERRIDE_KEYWORD) } } } val actualRenderOptions = overrideRenderOptions.with { modifiersRenderer = modifiersRenderer.with { - modifierFilter = modifierFilter or - KtRendererModifierFilter.onlyWith(KtTokens.INNER_KEYWORD) or - KtRendererModifierFilter.onlyWith(KtTokens.VISIBILITY_MODIFIERS) - KtRendererModifierFilter.onlyWith(KtTokens.MODALITY_MODIFIERS) + keywordsRenderer = keywordsRenderer.with { + keywordFilter = + keywordFilter or KtRendererKeywordFilter.onlyWith(KtTokens.INNER_KEYWORD) or KtRendererKeywordFilter.onlyWith(KtTokens.VISIBILITY_MODIFIERS) + KtRendererKeywordFilter.onlyWith(KtTokens.MODALITY_MODIFIERS) + } } } val expectRenderOptions = actualRenderOptions.with { modifiersRenderer = modifiersRenderer.with { - modifierFilter = modifierFilter or KtRendererModifierFilter.onlyWith(KtTokens.ACTUAL_KEYWORD) + keywordsRenderer = keywordsRenderer.with { keywordFilter = keywordFilter or KtRendererKeywordFilter.onlyWith(KtTokens.ACTUAL_KEYWORD) } } } } diff --git a/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt b/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt index d297db10b582..bdbe89571c82 100644 --- a/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt +++ b/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt @@ -9,7 +9,6 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.SmartPsiElementPointer import com.intellij.psi.codeStyle.CodeStyleManager -import com.intellij.psi.stubs.StubElement import org.jetbrains.annotations.ApiStatus import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt import org.jetbrains.kotlin.idea.core.insertMembersAfter @@ -19,7 +18,7 @@ import org.jetbrains.kotlin.analysis.api.analyze import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource -import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererModifierFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererKeywordFilter import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.base.analysis.api.utils.invokeShortening import org.jetbrains.kotlin.lexer.KtTokens @@ -342,7 +341,7 @@ abstract class KtGenerateMembersHandler( annotationFilter = KtRendererAnnotationsFilter.NONE } modifiersRenderer = modifiersRenderer.with { - modifierFilter = KtRendererModifierFilter.onlyWith(KtTokens.OVERRIDE_KEYWORD) + keywordsRenderer = keywordsRenderer.with { keywordFilter = KtRendererKeywordFilter.onlyWith(KtTokens.OVERRIDE_KEYWORD) } } } } diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/keywords/OverrideKeywordHandler.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/keywords/OverrideKeywordHandler.kt index 0ad2df6d47b8..a70b0cb0a2f4 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/keywords/OverrideKeywordHandler.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/keywords/OverrideKeywordHandler.kt @@ -13,10 +13,10 @@ import org.jetbrains.kotlin.analysis.api.analyze import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource -import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererModifierFilter import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtVariableSymbol +import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererKeywordFilter import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality import org.jetbrains.kotlin.descriptors.Modality @@ -183,7 +183,7 @@ internal class OverrideKeywordHandler( annotationFilter = KtRendererAnnotationsFilter.NONE } modifiersRenderer = modifiersRenderer.with { - modifierFilter = KtRendererModifierFilter.onlyWith(KtTokens.TYPE_MODIFIER_KEYWORDS) + keywordsRenderer = keywordsRenderer.with { keywordFilter = KtRendererKeywordFilter.onlyWith(KtTokens.TYPE_MODIFIER_KEYWORDS) } } } } diff --git a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembersOfEnum.fir.after b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembersOfEnum.fir.after index 181edb4e398c..a54337caaaed 100644 --- a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembersOfEnum.fir.after +++ b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/InheritedMembersOfEnum.fir.after @@ -1,13 +1,13 @@ -InheritedMembersOfEnum.kt - -enum class Test + -Test + clone(): Any location=→Enum + compareTo(E): Int location=→Enum + equals(Any?): Boolean location=→Enum + finalize(): Unit location=→Enum FIRST - fun clone(): Any location=→Enum - fun compareTo(other: E): Int location=→Enum - fun equals(other: Any?): Boolean location=→Enum - fun finalize() location=→Enum - fun getDeclaringClass(): Class location=→Enum - fun hashCode(): Int location=→Enum - fun toString(): String location=→Enum + getDeclaringClass(): Class location=→Enum + hashCode(): Int location=→Enum + name: String location=→Enum + ordinal: Int location=→Enum SECOND - val name: String location=→Enum - val ordinal: Int location=→Enum \ No newline at end of file + toString(): String location=→Enum \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/Render.fir.after b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/Render.fir.after index beac0c94c747..0b46bbfc316a 100644 --- a/plugins/kotlin/idea/tests/testData/structureView/fileStructure/Render.fir.after +++ b/plugins/kotlin/idea/tests/testData/structureView/fileStructure/Render.fir.after @@ -1,7 +1,4 @@ -Render.kt - - Enum1 - FIRST - SECOND A1 -A2 a: Int @@ -28,6 +25,9 @@ object Comparable.a: String Comparable.extension2(): Unit + -Enum1 + FIRST + SECOND Interface Interface1 String.extension1(): Unit diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/memberInfo/K2MemberInfoSupport.kt b/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/memberInfo/K2MemberInfoSupport.kt index 96329202342e..739de81600d3 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/memberInfo/K2MemberInfoSupport.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/memberInfo/K2MemberInfoSupport.kt @@ -2,7 +2,7 @@ package org.jetbrains.kotlin.idea.k2.refactoring.memberInfo import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.analysis.api.renderer.base.KtKeywordRenderer +import org.jetbrains.kotlin.analysis.api.renderer.base.KtKeywordsRenderer import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.callables.KtPropertyAccessorsRenderer @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.psi.KtNamedDeclaration class K2MemberInfoSupport : KotlinMemberInfoSupport { private val renderer = KtDeclarationRendererForSource.WITH_SHORT_NAMES.with { annotationRenderer = annotationRenderer.with { - keywordRender = KtKeywordRenderer.NONE + keywordsRenderer = KtKeywordsRenderer.NONE annotationFilter = KtRendererAnnotationsFilter.NONE superTypesFilter = KtSuperTypesFilter.NONE propertyAccessorsRenderer = KtPropertyAccessorsRenderer.NONE From ec1ef68088444a7141331a342e89ede491964fb7 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Thu, 22 Jun 2023 23:51:20 -0700 Subject: [PATCH 016/226] FIR UAST: test update (simple name for local type) GitOrigin-RevId: 80825d79817779d50c8e716b7d44bd63ff1b7d7f --- .../testData/legacyRenderLog/BrokenMethod.render.fir.txt | 6 +++--- .../tests/testData/legacyTypes/BrokenMethod.types.fir.txt | 6 +++--- .../tests/testData/legacyValues/BrokenMethod.values.fir.txt | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/BrokenMethod.render.fir.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/BrokenMethod.render.fir.txt index c3ce4458a262..5ede3753ffb3 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/BrokenMethod.render.fir.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyRenderLog/BrokenMethod.render.fir.txt @@ -10,17 +10,17 @@ public final class BrokenMethodKt { public fun hashCode() : int = UastEmptyExpression public fun equals(@org.jetbrains.annotations.Nullable other: java.lang.Object) : boolean = UastEmptyExpression public static final class Used { - @null public static final var Companion: TestUsed.Used.Companion + @null public static final var Companion: Companion @org.jetbrains.annotations.NotNull private final var parameter: java.lang.Object public final fun getParameter() : java.lang.Object = UastEmptyExpression public fun Used(@org.jetbrains.annotations.NotNull parameter: java.lang.Object) = UastEmptyExpression public final fun component1() : java.lang.Object = UastEmptyExpression - public final fun copy(@org.jetbrains.annotations.NotNull parameter: java.lang.Object) : TestUsed.Used = UastEmptyExpression + public final fun copy(@org.jetbrains.annotations.NotNull parameter: java.lang.Object) : Used = UastEmptyExpression public fun toString() : java.lang.String = UastEmptyExpression public fun hashCode() : int = UastEmptyExpression public fun equals(@org.jetbrains.annotations.Nullable other: java.lang.Object) : boolean = UastEmptyExpression public static final class Companion { - public final fun doStuff1(@org.jetbrains.annotations.NotNull $this$doStuff1: java.lang.Object) : TestUsed.Used { + public final fun doStuff1(@org.jetbrains.annotations.NotNull $this$doStuff1: java.lang.Object) : Used { return (this) } private fun Companion() = UastEmptyExpression diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/BrokenMethod.types.fir.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/BrokenMethod.types.fir.txt index b76b6896e012..d7a2f4dd06a4 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/BrokenMethod.types.fir.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyTypes/BrokenMethod.types.fir.txt @@ -22,7 +22,7 @@ UFile (package = ) [public final class BrokenMethodKt {...] UParameter (name = other) [@org.jetbrains.annotations.Nullable var other: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.Nullable) [@org.jetbrains.annotations.Nullable] UClass (name = Used) [public static final class Used {...}] - UField (name = Companion) [@null public static final var Companion: TestUsed.Used.Companion] + UField (name = Companion) [@null public static final var Companion: Companion] UAnnotation (fqName = null) [@null] UField (name = parameter) [@org.jetbrains.annotations.NotNull private final var parameter: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] @@ -31,7 +31,7 @@ UFile (package = ) [public final class BrokenMethodKt {...] UParameter (name = parameter) [@org.jetbrains.annotations.NotNull var parameter: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UMethod (name = component1) [public final fun component1() : java.lang.Object = UastEmptyExpression] - UMethod (name = copy) [public final fun copy(@org.jetbrains.annotations.NotNull parameter: java.lang.Object) : TestUsed.Used = UastEmptyExpression] + UMethod (name = copy) [public final fun copy(@org.jetbrains.annotations.NotNull parameter: java.lang.Object) : Used = UastEmptyExpression] UParameter (name = parameter) [@org.jetbrains.annotations.NotNull var parameter: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UMethod (name = toString) [public fun toString() : java.lang.String = UastEmptyExpression] @@ -40,7 +40,7 @@ UFile (package = ) [public final class BrokenMethodKt {...] UParameter (name = other) [@org.jetbrains.annotations.Nullable var other: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.Nullable) [@org.jetbrains.annotations.Nullable] UClass (name = Companion) [public static final class Companion {...}] - UMethod (name = doStuff1) [public final fun doStuff1(@org.jetbrains.annotations.NotNull $this$doStuff1: java.lang.Object) : TestUsed.Used {...}] + UMethod (name = doStuff1) [public final fun doStuff1(@org.jetbrains.annotations.NotNull $this$doStuff1: java.lang.Object) : Used {...}] UParameter (name = $this$doStuff1) [@org.jetbrains.annotations.NotNull var $this$doStuff1: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UBlockExpression [{...}] diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/BrokenMethod.values.fir.txt b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/BrokenMethod.values.fir.txt index f45fb46ee492..8254989fc8b9 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/BrokenMethod.values.fir.txt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/testData/legacyValues/BrokenMethod.values.fir.txt @@ -22,7 +22,7 @@ UFile (package = ) [public final class BrokenMethodKt {...] UParameter (name = other) [@org.jetbrains.annotations.Nullable var other: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.Nullable) [@org.jetbrains.annotations.Nullable] UClass (name = Used) [public static final class Used {...}] - UField (name = Companion) [@null public static final var Companion: TestUsed.Used.Companion] + UField (name = Companion) [@null public static final var Companion: Companion] UAnnotation (fqName = null) [@null] UField (name = parameter) [@org.jetbrains.annotations.NotNull private final var parameter: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] @@ -31,7 +31,7 @@ UFile (package = ) [public final class BrokenMethodKt {...] UParameter (name = parameter) [@org.jetbrains.annotations.NotNull var parameter: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UMethod (name = component1) [public final fun component1() : java.lang.Object = UastEmptyExpression] - UMethod (name = copy) [public final fun copy(@org.jetbrains.annotations.NotNull parameter: java.lang.Object) : TestUsed.Used = UastEmptyExpression] + UMethod (name = copy) [public final fun copy(@org.jetbrains.annotations.NotNull parameter: java.lang.Object) : Used = UastEmptyExpression] UParameter (name = parameter) [@org.jetbrains.annotations.NotNull var parameter: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UMethod (name = toString) [public fun toString() : java.lang.String = UastEmptyExpression] @@ -40,7 +40,7 @@ UFile (package = ) [public final class BrokenMethodKt {...] UParameter (name = other) [@org.jetbrains.annotations.Nullable var other: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.Nullable) [@org.jetbrains.annotations.Nullable] UClass (name = Companion) [public static final class Companion {...}] - UMethod (name = doStuff1) [public final fun doStuff1(@org.jetbrains.annotations.NotNull $this$doStuff1: java.lang.Object) : TestUsed.Used {...}] + UMethod (name = doStuff1) [public final fun doStuff1(@org.jetbrains.annotations.NotNull $this$doStuff1: java.lang.Object) : Used {...}] UParameter (name = $this$doStuff1) [@org.jetbrains.annotations.NotNull var $this$doStuff1: java.lang.Object] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] UBlockExpression [{...}] = Nothing From 8c774a2d46330a872776c523265ecac6f07831a5 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Wed, 10 May 2023 19:01:52 +0300 Subject: [PATCH 017/226] [kotlin k2] Enable QuickFixMultiModuleTest in K2 KTIJ-23199 GitOrigin-RevId: ea1a1a7e0a208844676fdf010edc349b109eda29 --- ...bstractHighLevelQuickFixMultiModuleTest.kt | 21 + ...LevelQuickFixMultiModuleTestGenerated.java | 1465 +++++++++++++++++ .../AbstractQuickFixMultiModuleTest.kt | 2 +- .../fir/testGenerator/FirGenerateTests.kt | 8 +- 4 files changed, 1493 insertions(+), 3 deletions(-) create mode 100644 plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/AbstractHighLevelQuickFixMultiModuleTest.kt create mode 100644 plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiModuleTestGenerated.java diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/AbstractHighLevelQuickFixMultiModuleTest.kt b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/AbstractHighLevelQuickFixMultiModuleTest.kt new file mode 100644 index 000000000000..bbe13d78ae23 --- /dev/null +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/AbstractHighLevelQuickFixMultiModuleTest.kt @@ -0,0 +1,21 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.fir.quickfix + +import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixMultiModuleTest +import org.jetbrains.kotlin.idea.test.findFileWithCaret +import org.jetbrains.kotlin.test.utils.IgnoreTests + +abstract class AbstractHighLevelQuickFixMultiModuleTest : AbstractQuickFixMultiModuleTest() { + override fun isFirPlugin(): Boolean = true + + override fun doQuickFixTest(dirPath: String) { + val actionFile = project.findFileWithCaret() + val actionFilePath = actionFile.virtualFile.toNioPath() + IgnoreTests.runTestIfEnabledByFileDirective( + actionFilePath, + enableTestDirective = IgnoreTests.DIRECTIVES.FIR_COMPARISON, + ) { + super.doQuickFixTest(dirPath) + } + } +} \ No newline at end of file diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiModuleTestGenerated.java b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiModuleTestGenerated.java new file mode 100644 index 000000000000..1b4bd3a07b01 --- /dev/null +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiModuleTestGenerated.java @@ -0,0 +1,1465 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +package org.jetbrains.kotlin.idea.fir.quickfix; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.idea.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.jetbrains.kotlin.idea.base.test.TestRoot; +import org.junit.runner.RunWith; + +/** + * This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}. + * DO NOT MODIFY MANUALLY. + */ +@SuppressWarnings("all") +@TestRoot("fir") +@TestDataPath("$CONTENT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +@TestMetadata("../idea/tests/testData/multiModuleQuickFix") +public abstract class HighLevelQuickFixMultiModuleTestGenerated extends AbstractHighLevelQuickFixMultiModuleTest { + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker") + public static class AccessibilityChecker extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("annotationOnClass") + public void testAnnotationOnClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/annotationOnClass/"); + } + + @TestMetadata("classPrimaryConstructor") + public void testClassPrimaryConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/classPrimaryConstructor/"); + } + + @TestMetadata("classSecondaryConstructor") + public void testClassSecondaryConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/classSecondaryConstructor/"); + } + + @TestMetadata("classUpperBounds") + public void testClassUpperBounds() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/classUpperBounds/"); + } + + @TestMetadata("errorType") + public void testErrorType() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/errorType/"); + } + + @TestMetadata("memberFunction") + public void testMemberFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/memberFunction/"); + } + + @TestMetadata("memberFunctionAndNestedClass") + public void testMemberFunctionAndNestedClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/memberFunctionAndNestedClass/"); + } + + @TestMetadata("memberFunctionParentType") + public void testMemberFunctionParentType() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/memberFunctionParentType/"); + } + + @TestMetadata("memberFunctionParentType2") + public void testMemberFunctionParentType2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/memberFunctionParentType2/"); + } + + @TestMetadata("nestedClassWithTypeParam") + public void testNestedClassWithTypeParam() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/nestedClassWithTypeParam/"); + } + + @TestMetadata("topLevelFunParameter") + public void testTopLevelFunParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunParameter/"); + } + + @TestMetadata("topLevelFunReturnType") + public void testTopLevelFunReturnType() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunReturnType/"); + } + + @TestMetadata("topLevelFunTypeParameter") + public void testTopLevelFunTypeParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunTypeParameter/"); + } + + @TestMetadata("topLevelFunUpperBounds") + public void testTopLevelFunUpperBounds() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds/"); + } + + @TestMetadata("topLevelFunUpperBounds2") + public void testTopLevelFunUpperBounds2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds2/"); + } + + @TestMetadata("topLevelProperty") + public void testTopLevelProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/topLevelProperty/"); + } + + @TestMetadata("topLevelPropertyTypeParam2") + public void testTopLevelPropertyTypeParam2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParam2/"); + } + + @TestMetadata("topLevelPropertyTypeParamBound") + public void testTopLevelPropertyTypeParamBound() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParamBound/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/addDependency") + public static class AddDependency extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("class") + public void testClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addDependency/class/"); + } + + @TestMetadata("topLevelFunction") + public void testTopLevelFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addDependency/topLevelFunction/"); + } + + @TestMetadata("topLevelFunction2") + public void testTopLevelFunction2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addDependency/topLevelFunction2/"); + } + + @TestMetadata("topLevelProperty") + public void testTopLevelProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addDependency/topLevelProperty/"); + } + + @TestMetadata("topLevelProperty2") + public void testTopLevelProperty2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addDependency/topLevelProperty2/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers") + public static class AddMissingActualMembers extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("classFunction") + public void testClassFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classFunction/"); + } + + @TestMetadata("classFunctionSameSignature") + public void testClassFunctionSameSignature() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classFunctionSameSignature/"); + } + + @TestMetadata("classFunctionWithConstructor") + public void testClassFunctionWithConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classFunctionWithConstructor/"); + } + + @TestMetadata("classFunctionWithConstructorAndParameters") + public void testClassFunctionWithConstructorAndParameters() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classFunctionWithConstructorAndParameters/"); + } + + @TestMetadata("classFunctionWithIncompatibleConstructor") + public void testClassFunctionWithIncompatibleConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classFunctionWithIncompatibleConstructor/"); + } + + @TestMetadata("classOverloadedFunction") + public void testClassOverloadedFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classOverloadedFunction/"); + } + + @TestMetadata("classPropertyInConstructor") + public void testClassPropertyInConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classPropertyInConstructor/"); + } + + @TestMetadata("classSomeProperties") + public void testClassSomeProperties() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classSomeProperties/"); + } + + @TestMetadata("classWithIncompilableFunction") + public void testClassWithIncompilableFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/classWithIncompilableFunction/"); + } + + @TestMetadata("companionAbsence") + public void testCompanionAbsence() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/companionAbsence/"); + } + + @TestMetadata("membersWithIncorrectType") + public void testMembersWithIncorrectType() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/membersWithIncorrectType/"); + } + + @TestMetadata("primaryConstructorAbsence") + public void testPrimaryConstructorAbsence() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/primaryConstructorAbsence/"); + } + + @TestMetadata("propertyWithIncorrectType") + public void testPropertyWithIncorrectType() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/propertyWithIncorrectType/"); + } + + @TestMetadata("secondaryConstructorAbsence") + public void testSecondaryConstructorAbsence() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addMissingActualMembers/secondaryConstructorAbsence/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/addThrowAnnotation") + public static class AddThrowAnnotation extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("common") + public void testCommon() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addThrowAnnotation/common/"); + } + + @TestMetadata("js") + public void testJs() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addThrowAnnotation/js/"); + } + + @TestMetadata("jvm") + public void testJvm() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addThrowAnnotation/jvm/"); + } + + @TestMetadata("jvmWithoutStdlib") + public void testJvmWithoutStdlib() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/addThrowAnnotation/jvmWithoutStdlib/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/canSealedSubClassBeObject") + public static class CanSealedSubClassBeObject extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("notConvertActualSubClass") + public void testNotConvertActualSubClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/canSealedSubClassBeObject/notConvertActualSubClass/"); + } + + @TestMetadata("notConvertExpectSubClass") + public void testNotConvertExpectSubClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/canSealedSubClassBeObject/notConvertExpectSubClass/"); + } + + @TestMetadata("notConvertImplicitExpectSubClass") + public void testNotConvertImplicitExpectSubClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/canSealedSubClassBeObject/notConvertImplicitExpectSubClass/"); + } + + @TestMetadata("notGenerateEqualsAndHashCodeForSealedInCommon") + public void testNotGenerateEqualsAndHashCodeForSealedInCommon() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/canSealedSubClassBeObject/notGenerateEqualsAndHashCodeForSealedInCommon/"); + } + + @TestMetadata("notGenerateEqualsAndHashCodeForSealedInJvmForExpect") + public void testNotGenerateEqualsAndHashCodeForSealedInJvmForExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/canSealedSubClassBeObject/notGenerateEqualsAndHashCodeForSealedInJvmForExpect/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/changeModifier") + public static class ChangeModifier extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("internal") + public void testInternal() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeModifier/internal/"); + } + + @TestMetadata("public") + public void testPublic() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeModifier/public/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/changeSignature") + public static class ChangeSignature extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("actual") + public void testActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeSignature/actual/"); + } + + @TestMetadata("expect") + public void testExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeSignature/expect/"); + } + + @TestMetadata("override") + public void testOverride() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeSignature/override/"); + } + + @TestMetadata("override2") + public void testOverride2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeSignature/override2/"); + } + + @TestMetadata("override3") + public void testOverride3() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeSignature/override3/"); + } + + @TestMetadata("override4") + public void testOverride4() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeSignature/override4/"); + } + + @TestMetadata("override5") + public void testOverride5() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeSignature/override5/"); + } + + @TestMetadata("override6") + public void testOverride6() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/changeSignature/override6/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/createActual") + public static class CreateActual extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("abstract") + public void testAbstract() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/abstract/"); + } + + @TestMetadata("abstractClassWithJdk") + public void testAbstractClassWithJdk() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/abstractClassWithJdk/"); + } + + @TestMetadata("annotation") + public void testAnnotation() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/annotation/"); + } + + @TestMetadata("annotationOptionalExpectation") + public void testAnnotationOptionalExpectation() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/annotationOptionalExpectation/"); + } + + @TestMetadata("annotationOptionalExpectationNoDir") + public void testAnnotationOptionalExpectationNoDir() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/annotationOptionalExpectationNoDir/"); + } + + @TestMetadata("annotationWithComment") + public void testAnnotationWithComment() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/annotationWithComment/"); + } + + @TestMetadata("class") + public void testClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/class/"); + } + + @TestMetadata("classWithBase") + public void testClassWithBase() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/classWithBase/"); + } + + @TestMetadata("classWithJdk") + public void testClassWithJdk() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/classWithJdk/"); + } + + @TestMetadata("classWithSuperTypeFromOtherPackage") + public void testClassWithSuperTypeFromOtherPackage() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/classWithSuperTypeFromOtherPackage/"); + } + + @TestMetadata("constructorWithDelegation") + public void testConstructorWithDelegation() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/constructorWithDelegation/"); + } + + @TestMetadata("constructorWithJdk") + public void testConstructorWithJdk() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/constructorWithJdk/"); + } + + @TestMetadata("createWithImport") + public void testCreateWithImport() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/createWithImport/"); + } + + @TestMetadata("defaultParameterInExpected") + public void testDefaultParameterInExpected() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/defaultParameterInExpected/"); + } + + @TestMetadata("defaultParameterInExpectedClass") + public void testDefaultParameterInExpectedClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/defaultParameterInExpectedClass/"); + } + + @TestMetadata("defaultParameterInExpectedConstructor") + public void testDefaultParameterInExpectedConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/defaultParameterInExpectedConstructor/"); + } + + @TestMetadata("enum") + public void testEnum() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/enum/"); + } + + @TestMetadata("expectSealedInCommonWhen") + public void testExpectSealedInCommonWhen() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/expectSealedInCommonWhen/"); + } + + @TestMetadata("forbiddenForLeafSourceSets") + public void testForbiddenForLeafSourceSets() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/forbiddenForLeafSourceSets/"); + } + + @TestMetadata("function") + public void testFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/function/"); + } + + @TestMetadata("functionSameFile") + public void testFunctionSameFile() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/functionSameFile/"); + } + + @TestMetadata("inlineClass") + public void testInlineClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/inlineClass/"); + } + + @TestMetadata("interface") + public void testInterface() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/interface/"); + } + + @TestMetadata("nested") + public void testNested() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/nested/"); + } + + @TestMetadata("object") + public void testObject() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/object/"); + } + + @TestMetadata("package") + public void testPackage() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/package/"); + } + + @TestMetadata("packageIncorrect") + public void testPackageIncorrect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/packageIncorrect/"); + } + + @TestMetadata("packageIncorrectEmpty") + public void testPackageIncorrectEmpty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/packageIncorrectEmpty/"); + } + + @TestMetadata("primaryConstructor") + public void testPrimaryConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/primaryConstructor/"); + } + + @TestMetadata("property") + public void testProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/property/"); + } + + @TestMetadata("sealed") + public void testSealed() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/sealed/"); + } + + @TestMetadata("sealedInCommonWhen") + public void testSealedInCommonWhen() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/sealedInCommonWhen/"); + } + + @TestMetadata("sealedSubclass") + public void testSealedSubclass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/sealedSubclass/"); + } + + @TestMetadata("valueClass") + public void testValueClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/valueClass/"); + } + + @TestMetadata("valueClassWithGenerics") + public void testValueClassWithGenerics() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/valueClassWithGenerics/"); + } + + @TestMetadata("withFakeJvm") + public void testWithFakeJvm() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/withFakeJvm/"); + } + + @TestMetadata("withRootPackage") + public void testWithRootPackage() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/withRootPackage/"); + } + + @TestMetadata("withTest") + public void testWithTest() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/withTest/"); + } + + @TestMetadata("withTestDummy") + public void testWithTestDummy() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActual/withTestDummy/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/createActualExplicitApi") + public static class CreateActualExplicitApi extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("class") + public void testClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActualExplicitApi/class/"); + } + + @TestMetadata("function") + public void testFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createActualExplicitApi/function/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/createExpect") + public static class CreateExpect extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("annotation") + public void testAnnotation() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/annotation/"); + } + + @TestMetadata("annotation2") + public void testAnnotation2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/annotation2/"); + } + + @TestMetadata("class") + public void testClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/class/"); + } + + @TestMetadata("classWithAnnotation") + public void testClassWithAnnotation() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/classWithAnnotation/"); + } + + @TestMetadata("classWithSuperClassAndTypeParameter") + public void testClassWithSuperClassAndTypeParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/classWithSuperClassAndTypeParameter/"); + } + + @TestMetadata("classWithSuperTypeFromOtherPackage") + public void testClassWithSuperTypeFromOtherPackage() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/classWithSuperTypeFromOtherPackage/"); + } + + @TestMetadata("commented") + public void testCommented() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/commented/"); + } + + @TestMetadata("companion") + public void testCompanion() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/companion/"); + } + + @TestMetadata("createWithImport") + public void testCreateWithImport() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/createWithImport/"); + } + + @TestMetadata("dataClass") + public void testDataClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/dataClass/"); + } + + @TestMetadata("dataObject") + public void testDataObject() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/dataObject/"); + } + + @TestMetadata("enum") + public void testEnum() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/enum/"); + } + + @TestMetadata("enumComplex") + public void testEnumComplex() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/enumComplex/"); + } + + @TestMetadata("enumEmpty") + public void testEnumEmpty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/enumEmpty/"); + } + + @TestMetadata("funWithAccessibleAlias") + public void testFunWithAccessibleAlias() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/funWithAccessibleAlias/"); + } + + @TestMetadata("funWithAccessibleExpansion") + public void testFunWithAccessibleExpansion() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/funWithAccessibleExpansion/"); + } + + @TestMetadata("funWithAccessibleParameter") + public void testFunWithAccessibleParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/funWithAccessibleParameter/"); + } + + @TestMetadata("funWithAccessibleTypeFromCommon") + public void testFunWithAccessibleTypeFromCommon() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/funWithAccessibleTypeFromCommon/"); + } + + @TestMetadata("funWithJdk") + public void testFunWithJdk() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/funWithJdk/"); + } + + @TestMetadata("funWithPrivateModifier") + public void testFunWithPrivateModifier() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/funWithPrivateModifier/"); + } + + @TestMetadata("function") + public void testFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/function/"); + } + + @TestMetadata("function2") + public void testFunction2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/function2/"); + } + + @TestMetadata("functionInInterface") + public void testFunctionInInterface() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/functionInInterface/"); + } + + @TestMetadata("functionWithImplementationInInterface") + public void testFunctionWithImplementationInInterface() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/functionWithImplementationInInterface/"); + } + + @TestMetadata("functionWithImplementationInInterface2") + public void testFunctionWithImplementationInInterface2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/functionWithImplementationInInterface2/"); + } + + @TestMetadata("hierarchy") + public void testHierarchy() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/hierarchy/"); + } + + @TestMetadata("inlineClass") + public void testInlineClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/inlineClass/"); + } + + @TestMetadata("inlineClass2") + public void testInlineClass2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/inlineClass2/"); + } + + @TestMetadata("innerClassWithTypeParam") + public void testInnerClassWithTypeParam() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/innerClassWithTypeParam/"); + } + + @TestMetadata("innerClassWithTypeParam2") + public void testInnerClassWithTypeParam2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/innerClassWithTypeParam2/"); + } + + @TestMetadata("innerEnum") + public void testInnerEnum() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/innerEnum/"); + } + + @TestMetadata("memberFunctionAndNestedClass") + public void testMemberFunctionAndNestedClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/memberFunctionAndNestedClass/"); + } + + @TestMetadata("nestedClass") + public void testNestedClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/nestedClass/"); + } + + @TestMetadata("noAccessOnMember") + public void testNoAccessOnMember() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/noAccessOnMember/"); + } + + @TestMetadata("onMember") + public void testOnMember() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/onMember/"); + } + + @TestMetadata("primaryConstructor") + public void testPrimaryConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/primaryConstructor/"); + } + + @TestMetadata("property") + public void testProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/property/"); + } + + @TestMetadata("property2") + public void testProperty2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/property2/"); + } + + @TestMetadata("propertyInConstructor") + public void testPropertyInConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/propertyInConstructor/"); + } + + @TestMetadata("propertyWithConstModifier") + public void testPropertyWithConstModifier() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/propertyWithConstModifier/"); + } + + @TestMetadata("propertyWithLateinitModifier") + public void testPropertyWithLateinitModifier() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/propertyWithLateinitModifier/"); + } + + @TestMetadata("propertyWithPrivateModifier") + public void testPropertyWithPrivateModifier() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/propertyWithPrivateModifier/"); + } + + @TestMetadata("sealedClass") + public void testSealedClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/sealedClass/"); + } + + @TestMetadata("stdlibWithJavaAlias") + public void testStdlibWithJavaAlias() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/stdlibWithJavaAlias/"); + } + + @TestMetadata("superTypeFromStdlib") + public void testSuperTypeFromStdlib() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/superTypeFromStdlib/"); + } + + @TestMetadata("topLevelFunctionWithAnnotations") + public void testTopLevelFunctionWithAnnotations() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/topLevelFunctionWithAnnotations/"); + } + + @TestMetadata("topLevelPropertyWithTypeParam") + public void testTopLevelPropertyWithTypeParam() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/topLevelPropertyWithTypeParam/"); + } + + @TestMetadata("typeAlias") + public void testTypeAlias() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/typeAlias/"); + } + + @TestMetadata("withAliases") + public void testWithAliases() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withAliases/"); + } + + @TestMetadata("withAnnotations") + public void testWithAnnotations() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withAnnotations/"); + } + + @TestMetadata("withConstructorWithParametersWithoutValVar") + public void testWithConstructorWithParametersWithoutValVar() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withConstructorWithParametersWithoutValVar/"); + } + + @TestMetadata("withInitializer") + public void testWithInitializer() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withInitializer/"); + } + + @TestMetadata("withPlatformNested") + public void testWithPlatformNested() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withPlatformNested/"); + } + + @TestMetadata("withRootPackage") + public void testWithRootPackage() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withRootPackage/"); + } + + @TestMetadata("withSecondaryConstructor") + public void testWithSecondaryConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withSecondaryConstructor/"); + } + + @TestMetadata("withSecondaryConstructor2") + public void testWithSecondaryConstructor2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withSecondaryConstructor2/"); + } + + @TestMetadata("withSupertype") + public void testWithSupertype() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withSupertype/"); + } + + @TestMetadata("withVararg") + public void testWithVararg() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/createExpect/withVararg/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/fixNativeThrowsErrors") + public static class FixNativeThrowsErrors extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("addCancellationException1") + public void testAddCancellationException1() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/fixNativeThrowsErrors/addCancellationException1/"); + } + + @TestMetadata("addCancellationException2") + public void testAddCancellationException2() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/fixNativeThrowsErrors/addCancellationException2/"); + } + + @TestMetadata("addCancellationException3") + public void testAddCancellationException3() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/fixNativeThrowsErrors/addCancellationException3/"); + } + + @TestMetadata("addCancellationException4") + public void testAddCancellationException4() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/fixNativeThrowsErrors/addCancellationException4/"); + } + + @TestMetadata("removeEmptyThrows") + public void testRemoveEmptyThrows() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/fixNativeThrowsErrors/removeEmptyThrows/"); + } + + @TestMetadata("removeThrowsOnIncompatibleOverride") + public void testRemoveThrowsOnIncompatibleOverride() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/fixNativeThrowsErrors/removeThrowsOnIncompatibleOverride/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter") + public static class FunctionTypeReceiverToParameter extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("classFunctionConstructor") + public void testClassFunctionConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/classFunctionConstructor/"); + } + + @TestMetadata("classFunctionParameter") + public void testClassFunctionParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/classFunctionParameter/"); + } + + @TestMetadata("classFunctionReturn") + public void testClassFunctionReturn() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/classFunctionReturn/"); + } + + @TestMetadata("classProperty") + public void testClassProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/classProperty/"); + } + + @TestMetadata("functionParameter") + public void testFunctionParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/functionParameter/"); + } + + @TestMetadata("functionReturn") + public void testFunctionReturn() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/functionReturn/"); + } + + @TestMetadata("interfaceFunctionParameter") + public void testInterfaceFunctionParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/interfaceFunctionParameter/"); + } + + @TestMetadata("interfaceFunctionReturn") + public void testInterfaceFunctionReturn() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/interfaceFunctionReturn/"); + } + + @TestMetadata("interfaceProperty") + public void testInterfaceProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/interfaceProperty/"); + } + + @TestMetadata("property") + public void testProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/functionTypeReceiverToParameter/property/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/initializeProperty") + public static class InitializeProperty extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("notInitializeNonActualParameterWithConstructorParameter") + public void testNotInitializeNonActualParameterWithConstructorParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/initializeProperty/notInitializeNonActualParameterWithConstructorParameter/"); + } + + @TestMetadata("notInitializeWithConstructorParameter") + public void testNotInitializeWithConstructorParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/initializeProperty/notInitializeWithConstructorParameter/"); + } + + @TestMetadata("notMoveNonActualParamterToActualConstructor") + public void testNotMoveNonActualParamterToActualConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/initializeProperty/notMoveNonActualParamterToActualConstructor/"); + } + + @TestMetadata("notMoveToActualConstructor") + public void testNotMoveToActualConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/initializeProperty/notMoveToActualConstructor/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/inlineToValue") + public static class InlineToValue extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("commonWithJvm") + public void testCommonWithJvm() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/inlineToValue/commonWithJvm/"); + } + + @TestMetadata("genericParameter") + public void testGenericParameter() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/inlineToValue/genericParameter/"); + } + + @TestMetadata("JS") + public void testJS() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/inlineToValue/JS/"); + } + + @TestMetadata("JVM") + public void testJVM() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/inlineToValue/JVM/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/makeOverridenMemberOpen") + public static class MakeOverridenMemberOpen extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("actual") + public void testActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/makeOverridenMemberOpen/actual/"); + } + + @TestMetadata("expect") + public void testExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/makeOverridenMemberOpen/expect/"); + } + + @TestMetadata("hasAbstract") + public void testHasAbstract() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/makeOverridenMemberOpen/hasAbstract/"); + } + + @TestMetadata("hasOpen") + public void testHasOpen() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/makeOverridenMemberOpen/hasOpen/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/other") + public static class Other extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("actualImplementAsConstructorParam") + public void testActualImplementAsConstructorParam() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/actualImplementAsConstructorParam/"); + } + + @TestMetadata("actualNoImplementAsConstructorParam") + public void testActualNoImplementAsConstructorParam() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/actualNoImplementAsConstructorParam/"); + } + + @TestMetadata("actualWithoutExpect") + public void testActualWithoutExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/actualWithoutExpect/"); + } + + @TestMetadata("addActualToClass") + public void testAddActualToClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/addActualToClass/"); + } + + @TestMetadata("addActualToClassMember") + public void testAddActualToClassMember() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/addActualToClassMember/"); + } + + @TestMetadata("addActualToTopLevelMember") + public void testAddActualToTopLevelMember() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/addActualToTopLevelMember/"); + } + + @TestMetadata("addAnnotationTargetToActual") + public void testAddAnnotationTargetToActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/addAnnotationTargetToActual/"); + } + + @TestMetadata("addAnnotationTargetToExpect") + public void testAddAnnotationTargetToExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/addAnnotationTargetToExpect/"); + } + + @TestMetadata("addFunctionToCommonClassFromJavaUsage") + public void testAddFunctionToCommonClassFromJavaUsage() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/addFunctionToCommonClassFromJavaUsage/"); + } + + @TestMetadata("addOperatorByActual") + public void testAddOperatorByActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/addOperatorByActual/"); + } + + @TestMetadata("addOperatorByExpect") + public void testAddOperatorByExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/addOperatorByExpect/"); + } + + @TestMetadata("cancelMakeAbstractFromActual") + public void testCancelMakeAbstractFromActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/cancelMakeAbstractFromActual/"); + } + + @TestMetadata("convertActualEnumToSealedClass") + public void testConvertActualEnumToSealedClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/convertActualEnumToSealedClass/"); + } + + @TestMetadata("convertActualSealedClassToEnum") + public void testConvertActualSealedClassToEnum() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/convertActualSealedClassToEnum/"); + } + + @TestMetadata("convertExpectEnumToSealedClass") + public void testConvertExpectEnumToSealedClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/convertExpectEnumToSealedClass/"); + } + + @TestMetadata("convertExpectSealedClassToEnum") + public void testConvertExpectSealedClassToEnum() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/convertExpectSealedClassToEnum/"); + } + + @TestMetadata("convertPropertyGetterToInitializer") + public void testConvertPropertyGetterToInitializer() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/convertPropertyGetterToInitializer/"); + } + + @TestMetadata("convertPropertyToFunction") + public void testConvertPropertyToFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/convertPropertyToFunction/"); + } + + @TestMetadata("createClassFromUsageImport") + public void testCreateClassFromUsageImport() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/createClassFromUsageImport/"); + } + + @TestMetadata("createClassFromUsageRef") + public void testCreateClassFromUsageRef() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/createClassFromUsageRef/"); + } + + @TestMetadata("createFunInExpectClass") + public void testCreateFunInExpectClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/createFunInExpectClass/"); + } + + @TestMetadata("createTestOnExpect") + public void testCreateTestOnExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/createTestOnExpect/"); + } + + @TestMetadata("createValInExpectClass") + public void testCreateValInExpectClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/createValInExpectClass/"); + } + + @TestMetadata("createVarInExpectClass") + public void testCreateVarInExpectClass() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/createVarInExpectClass/"); + } + + @TestMetadata("deprecatedHeader") + public void testDeprecatedHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/deprecatedHeader/"); + } + + @TestMetadata("deprecatedHeaderImpl") + public void testDeprecatedHeaderImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/deprecatedHeaderImpl/"); + } + + @TestMetadata("deprecatedImpl") + public void testDeprecatedImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/deprecatedImpl/"); + } + + @TestMetadata("deprecatedImplHeader") + public void testDeprecatedImplHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/deprecatedImplHeader/"); + } + + @TestMetadata("functionTypeParameterToReceiverByHeader") + public void testFunctionTypeParameterToReceiverByHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/functionTypeParameterToReceiverByHeader/"); + } + + @TestMetadata("functionTypeParameterToReceiverByImpl") + public void testFunctionTypeParameterToReceiverByImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/functionTypeParameterToReceiverByImpl/"); + } + + @TestMetadata("functionTypeReceiverToParameterByHeader") + public void testFunctionTypeReceiverToParameterByHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/functionTypeReceiverToParameterByHeader/"); + } + + @TestMetadata("functionTypeReceiverToParameterByImpl") + public void testFunctionTypeReceiverToParameterByImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/functionTypeReceiverToParameterByImpl/"); + } + + @TestMetadata("generateEqualsInExpect") + public void testGenerateEqualsInExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/generateEqualsInExpect/"); + } + + @TestMetadata("generateHashCodeInExpect") + public void testGenerateHashCodeInExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/generateHashCodeInExpect/"); + } + + @TestMetadata("implementAbstractExpectMemberInheritedFromInterface") + public void testImplementAbstractExpectMemberInheritedFromInterface() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/implementAbstractExpectMemberInheritedFromInterface/"); + } + + @TestMetadata("implementMembersInActualClassNoExpectMember") + public void testImplementMembersInActualClassNoExpectMember() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/implementMembersInActualClassNoExpectMember/"); + } + + @TestMetadata("implementMembersInImplClassNonImplInheritor") + public void testImplementMembersInImplClassNonImplInheritor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/implementMembersInImplClassNonImplInheritor/"); + } + + @TestMetadata("importClassInCommon") + public void testImportClassInCommon() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/importClassInCommon/"); + } + + @TestMetadata("importClassInFromProductionInCommonTests") + public void testImportClassInFromProductionInCommonTests() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/importClassInFromProductionInCommonTests/"); + } + + @TestMetadata("importCommonClassInJs") + public void testImportCommonClassInJs() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/importCommonClassInJs/"); + } + + @TestMetadata("importCommonClassInJvm") + public void testImportCommonClassInJvm() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/importCommonClassInJvm/"); + } + + @TestMetadata("importCommonFunInJvm") + public void testImportCommonFunInJvm() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/importCommonFunInJvm/"); + } + + @TestMetadata("importExpectClassWithActualInJvm") + public void testImportExpectClassWithActualInJvm() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/importExpectClassWithActualInJvm/"); + } + + @TestMetadata("importExpectClassWithoutActualInJvm") + public void testImportExpectClassWithoutActualInJvm() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/importExpectClassWithoutActualInJvm/"); + } + + @TestMetadata("importFunInCommon") + public void testImportFunInCommon() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/importFunInCommon/"); + } + + @TestMetadata("makeAbstractFromActual") + public void testMakeAbstractFromActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/makeAbstractFromActual/"); + } + + @TestMetadata("makeInlineFromExpect") + public void testMakeInlineFromExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/makeInlineFromExpect/"); + } + + @TestMetadata("makeInternalFromExpect") + public void testMakeInternalFromExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/makeInternalFromExpect/"); + } + + @TestMetadata("makeOpenFromActual") + public void testMakeOpenFromActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/makeOpenFromActual/"); + } + + @TestMetadata("makeOpenFromExpect") + public void testMakeOpenFromExpect() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/makeOpenFromExpect/"); + } + + @TestMetadata("mayBeConstantWithActual") + public void testMayBeConstantWithActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/mayBeConstantWithActual/"); + } + + @TestMetadata("memberFunParameterToReceiverByHeader") + public void testMemberFunParameterToReceiverByHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberFunParameterToReceiverByHeader/"); + } + + @TestMetadata("memberFunParameterToReceiverByImpl") + public void testMemberFunParameterToReceiverByImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberFunParameterToReceiverByImpl/"); + } + + @TestMetadata("memberFunReceiverToParameterByHeader") + public void testMemberFunReceiverToParameterByHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberFunReceiverToParameterByHeader/"); + } + + @TestMetadata("memberFunReceiverToParameterByImpl") + public void testMemberFunReceiverToParameterByImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberFunReceiverToParameterByImpl/"); + } + + @TestMetadata("memberFunToExtensionByHeader") + public void testMemberFunToExtensionByHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberFunToExtensionByHeader/"); + } + + @TestMetadata("memberFunToExtensionByImpl") + public void testMemberFunToExtensionByImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberFunToExtensionByImpl/"); + } + + @TestMetadata("memberValToExtensionByHeader") + public void testMemberValToExtensionByHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberValToExtensionByHeader/"); + } + + @TestMetadata("memberValToExtensionByHeaderWithInapplicableImpl") + public void testMemberValToExtensionByHeaderWithInapplicableImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberValToExtensionByHeaderWithInapplicableImpl/"); + } + + @TestMetadata("memberValToExtensionByImpl") + public void testMemberValToExtensionByImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/memberValToExtensionByImpl/"); + } + + @TestMetadata("moveActualPropertyToExistentConstructor") + public void testMoveActualPropertyToExistentConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/moveActualPropertyToExistentConstructor/"); + } + + @TestMetadata("movePropertyToConstructor") + public void testMovePropertyToConstructor() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/movePropertyToConstructor/"); + } + + @TestMetadata("notMakeAbstractFromActual") + public void testNotMakeAbstractFromActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/notMakeAbstractFromActual/"); + } + + @TestMetadata("orderHeader") + public void testOrderHeader() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/orderHeader/"); + } + + @TestMetadata("orderImpl") + public void testOrderImpl() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/orderImpl/"); + } + + @TestMetadata("safeDeleteForbiddenFromActual") + public void testSafeDeleteForbiddenFromActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/safeDeleteForbiddenFromActual/"); + } + + @TestMetadata("safeDeleteFromActual") + public void testSafeDeleteFromActual() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/safeDeleteFromActual/"); + } + + @TestMetadata("safeDeleteUsedInAnotherPlatform") + public void testSafeDeleteUsedInAnotherPlatform() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/other/safeDeleteUsedInAnotherPlatform/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/packageDirectoryMismatch") + public static class PackageDirectoryMismatch extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("moveFileToAnotherPackage") + public void testMoveFileToAnotherPackage() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/packageDirectoryMismatch/moveFileToAnotherPackage/"); + } + + @TestMetadata("moveFileToCommonSourceRoot") + public void testMoveFileToCommonSourceRoot() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/packageDirectoryMismatch/moveFileToCommonSourceRoot/"); + } + + @TestMetadata("moveFileToJvmSourceRoot") + public void testMoveFileToJvmSourceRoot() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/packageDirectoryMismatch/moveFileToJvmSourceRoot/"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/multiModuleQuickFix/redundantNullableReturnType") + public static class RedundantNullableReturnType extends AbstractHighLevelQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("actualMethod") + public void testActualMethod() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/redundantNullableReturnType/actualMethod/"); + } + + @TestMetadata("actualTopLevelFunction") + public void testActualTopLevelFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/redundantNullableReturnType/actualTopLevelFunction/"); + } + + @TestMetadata("actualTopLevelProperty") + public void testActualTopLevelProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/redundantNullableReturnType/actualTopLevelProperty/"); + } + + @TestMetadata("expectMemberProperty") + public void testExpectMemberProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/redundantNullableReturnType/expectMemberProperty/"); + } + + @TestMetadata("expectTopLevelFunction") + public void testExpectTopLevelFunction() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/redundantNullableReturnType/expectTopLevelFunction/"); + } + + @TestMetadata("expectTopLevelProperty") + public void testExpectTopLevelProperty() throws Exception { + runTest("../idea/tests/testData/multiModuleQuickFix/redundantNullableReturnType/expectTopLevelProperty/"); + } + } +} diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt index 87d962ead522..7842a179956a 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt @@ -55,7 +55,7 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), Quic return null } - private fun doQuickFixTest(dirPath: String) { + protected open fun doQuickFixTest(dirPath: String) { val actionFile = project.findFileWithCaret() val virtualFile = actionFile.virtualFile!! val mainFile = virtualFile.toIOFile()?.takeIf(File::exists) ?: error("unable to lookup source io file") diff --git a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt index 68c6faa3c4c2..969e55bdef71 100644 --- a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt +++ b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt @@ -21,9 +21,12 @@ import org.jetbrains.kotlin.idea.fir.findUsages.AbstractKotlinFindUsagesWithLibr import org.jetbrains.kotlin.idea.fir.findUsages.AbstractKotlinFindUsagesWithStdlibFirTest import org.jetbrains.kotlin.idea.fir.imports.AbstractFirJvmOptimizeImportsTest import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirLibraryModuleDeclarationResolveTest +import org.jetbrains.kotlin.idea.fir.navigation.AbstractFirGotoTypeDeclarationTest import org.jetbrains.kotlin.idea.fir.parameterInfo.AbstractFirParameterInfoTest import org.jetbrains.kotlin.idea.fir.quickfix.AbstractHighLevelQuickFixMultiFileTest +import org.jetbrains.kotlin.idea.fir.quickfix.AbstractHighLevelQuickFixMultiModuleTest import org.jetbrains.kotlin.idea.fir.quickfix.AbstractHighLevelQuickFixTest +import org.jetbrains.kotlin.idea.fir.resolve.* import org.jetbrains.kotlin.idea.fir.search.AbstractHLImplementationSearcherTest import org.jetbrains.kotlin.idea.fir.shortenRefs.AbstractFirShortenRefsTest import org.jetbrains.kotlin.idea.k2.refactoring.rename.AbstractFirRenameTest @@ -36,8 +39,6 @@ import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_OR_KTS_WITHOUT_DOTS import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_WITHOUT_DOTS import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_WITHOUT_DOT_AND_FIR_PREFIX import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_WITHOUT_FIR_PREFIX -import org.jetbrains.kotlin.idea.fir.resolve.* -import org.jetbrains.kotlin.idea.fir.navigation.AbstractFirGotoTypeDeclarationTest import org.jetbrains.kotlin.testGenerator.model.Patterns.TEST import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_OR_KTS @@ -160,6 +161,9 @@ private fun assembleWorkspace(): TWorkspace = workspace { ) } + testClass { + model("multiModuleQuickFix", pattern = DIRECTORY, depth = 1) + } testClass { model("shortenRefsFir", pattern = KT_WITHOUT_DOTS, testMethodName = "doTestWithMuting") From 33f9d6f36318d9704c829de647eaec3c954b934d Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Thu, 18 May 2023 13:45:47 +0300 Subject: [PATCH 018/226] [kotlin k2] Import: skip annotations when rendering declarations in tests This way it is easier to align rendered declarations in K1 and K2 and reuse the test data ^KTIJ-25990 GitOrigin-RevId: 50656d967f3eda6655619a030f33c793b38b34cc --- .../idea/actions/AbstractKotlinAddImportActionTest.kt | 8 ++++++-- .../idea/actions/kotlinAddImportAction/KotlinDurations.kt | 4 ++-- .../kotlinAddImportAction/KotlinDurations.kt.after | 4 ++-- .../actions/kotlinAddImportAction/KotlinDurations2.kt | 4 ++-- .../kotlinAddImportAction/KotlinDurations2.kt.after | 4 ++-- .../actions/kotlinAddImportAction/KotlinMinCollections.kt | 4 ++-- .../kotlinAddImportAction/KotlinMinCollections.kt.after | 4 ++-- .../idea/actions/kotlinAddImportAction/KotlinMinInt.kt | 4 ++-- .../actions/kotlinAddImportAction/KotlinMinInt.kt.after | 4 ++-- .../idea/actions/kotlinAddImportAction/Varargs.kt | 4 ++-- .../idea/actions/kotlinAddImportAction/Varargs.kt.after | 4 ++-- .../idea/actions/kotlinAddImportAction/Varargs2.kt | 4 ++-- .../idea/actions/kotlinAddImportAction/Varargs2.kt.after | 4 ++-- .../idea/actions/kotlinAddImportAction/Varargs3.kt | 4 ++-- .../idea/actions/kotlinAddImportAction/Varargs3.kt.after | 4 ++-- 15 files changed, 34 insertions(+), 30 deletions(-) diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractKotlinAddImportActionTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractKotlinAddImportActionTest.kt index 3d736c9110d7..5d6347b3285b 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractKotlinAddImportActionTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractKotlinAddImportActionTest.kt @@ -67,10 +67,14 @@ abstract class AbstractKotlinAddImportActionTest : KotlinLightCodeInsightFixture myFixture.checkResultByFile("${fileName()}.after") } + private val debugRenderer = DescriptorRenderer.DEBUG_TEXT.withOptions { + annotationFilter = { false } + } + private fun DeclarationDescriptor.variantName() = when(this) { is ClassDescriptor -> - fqNameOrNull()?.toString()?.let { "class $it" } ?: DescriptorRenderer.DEBUG_TEXT.render(this) + fqNameOrNull()?.toString()?.let { "class $it" } ?: debugRenderer.render(this) else -> - DescriptorRenderer.DEBUG_TEXT.render(this) + debugRenderer.render(this) } } diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt index 86101c64af10..290aaecee42a 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt @@ -1,6 +1,6 @@ // WITH_STDLIB -// EXPECT_VARIANT_IN_ORDER "@kotlin.internal.InlineOnly public final val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time.Duration.Companion" -// EXPECT_VARIANT_IN_ORDER "@kotlin.Deprecated @kotlin.DeprecatedSinceKotlin @kotlin.SinceKotlin @kotlin.time.ExperimentalTime public val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time" +// EXPECT_VARIANT_IN_ORDER "public final val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time.Duration.Companion" +// EXPECT_VARIANT_IN_ORDER "public val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time" package root fun foo() { diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt.after index cf3141ce2e97..194d95543492 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt.after @@ -1,6 +1,6 @@ // WITH_STDLIB -// EXPECT_VARIANT_IN_ORDER "@kotlin.internal.InlineOnly public final val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time.Duration.Companion" -// EXPECT_VARIANT_IN_ORDER "@kotlin.Deprecated @kotlin.DeprecatedSinceKotlin @kotlin.SinceKotlin @kotlin.time.ExperimentalTime public val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time" +// EXPECT_VARIANT_IN_ORDER "public final val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time.Duration.Companion" +// EXPECT_VARIANT_IN_ORDER "public val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time" package root import kotlin.time.Duration.Companion.seconds diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt index 736d4170c616..6774ea29fc0e 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt @@ -1,6 +1,6 @@ // WITH_STDLIB -// EXPECT_VARIANT_IN_ORDER "@kotlin.internal.InlineOnly public final val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time.Duration.Companion" -// EXPECT_VARIANT_IN_ORDER "@kotlin.Deprecated @kotlin.DeprecatedSinceKotlin @kotlin.SinceKotlin @kotlin.time.ExperimentalTime public val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time" +// EXPECT_VARIANT_IN_ORDER "public final val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time.Duration.Companion" +// EXPECT_VARIANT_IN_ORDER "public val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time" package root fun foo(x: Int?) = x.seconds diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt.after index 60045c7dc963..67b5bd8cf631 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt.after @@ -1,6 +1,6 @@ // WITH_STDLIB -// EXPECT_VARIANT_IN_ORDER "@kotlin.internal.InlineOnly public final val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time.Duration.Companion" -// EXPECT_VARIANT_IN_ORDER "@kotlin.Deprecated @kotlin.DeprecatedSinceKotlin @kotlin.SinceKotlin @kotlin.time.ExperimentalTime public val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time" +// EXPECT_VARIANT_IN_ORDER "public final val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time.Duration.Companion" +// EXPECT_VARIANT_IN_ORDER "public val kotlin.Int.seconds: kotlin.time.Duration defined in kotlin.time" package root import kotlin.time.Duration.Companion.seconds diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt index d9d33a080010..9f2d86c37846 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt @@ -1,6 +1,6 @@ // WITH_STDLIB -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt.after index 4b88a3b861da..7beca397c378 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt.after @@ -1,6 +1,6 @@ // WITH_STDLIB -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt index d25c897798df..ee2e9dff704b 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt @@ -1,9 +1,9 @@ // WITH_STDLIB -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Int, b: kotlin.Int): kotlin.Int defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Int, b: kotlin.Int): kotlin.Int defined in kotlin.math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.StrictMath" -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?), @org.jetbrains.annotations.Nullable p1: (java.util.Comparator..java.util.Comparator?)): (T..T?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?), p1: (java.util.Comparator..java.util.Comparator?)): (T..T?) defined in java.util.Collections" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Long, p1: kotlin.Long): kotlin.Long defined in java.lang.Long" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt.after index bb5faabf4272..66fc29779364 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt.after @@ -1,9 +1,9 @@ // WITH_STDLIB -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Int, b: kotlin.Int): kotlin.Int defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Int, b: kotlin.Int): kotlin.Int defined in kotlin.math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.StrictMath" -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?), @org.jetbrains.annotations.Nullable p1: (java.util.Comparator..java.util.Comparator?)): (T..T?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?), p1: (java.util.Comparator..java.util.Comparator?)): (T..T?) defined in java.util.Collections" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Long, p1: kotlin.Long): kotlin.Long defined in java.lang.Long" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt index 7d49f45cfc2e..c2cc232f4c6a 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt @@ -1,10 +1,10 @@ // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun min(vararg l: kotlin.Int): kotlin.Unit defined in foo in file Varargs.dependency.kt" -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Int, b: kotlin.Int): kotlin.Int defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Int, b: kotlin.Int): kotlin.Int defined in kotlin.math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.StrictMath" -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Long, p1: kotlin.Long): kotlin.Long defined in java.lang.Long" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt.after index 07ad5b55dc42..536e4228e105 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt.after @@ -1,10 +1,10 @@ // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun min(vararg l: kotlin.Int): kotlin.Unit defined in foo in file Varargs.dependency.kt" -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Int, b: kotlin.Int): kotlin.Int defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Int, b: kotlin.Int): kotlin.Int defined in kotlin.math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Math" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.StrictMath" -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Long, p1: kotlin.Long): kotlin.Long defined in java.lang.Long" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt index 65e750f412fa..2751a3be2437 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt @@ -1,7 +1,7 @@ // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun min(vararg l: kotlin.String): kotlin.Unit defined in foo in file Varargs2.dependency.kt" -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt.after index 9caf51fca0fa..2c9b5883dd83 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt.after @@ -1,7 +1,7 @@ // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun min(vararg l: kotlin.String): kotlin.Unit defined in foo in file Varargs2.dependency.kt" -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt index 9f22337ed211..deb106353c80 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt @@ -1,7 +1,7 @@ // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun min(vararg l: kotlin.Int): kotlin.Unit defined in foo in file Varargs3.dependency.kt" -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt.after index c1b2c740fd92..e52bc90d43eb 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt.after @@ -1,7 +1,7 @@ // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun min(vararg l: kotlin.Int): kotlin.Unit defined in foo in file Varargs3.dependency.kt" -// EXPECT_VARIANT_IN_ORDER "@kotlin.SinceKotlin @kotlin.internal.InlineOnly public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" -// EXPECT_VARIANT_IN_ORDER "public open fun min(@org.jetbrains.annotations.NotNull p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" +// EXPECT_VARIANT_IN_ORDER "public inline fun min(a: kotlin.Double, b: kotlin.Double): kotlin.Double defined in kotlin.math" +// EXPECT_VARIANT_IN_ORDER "public open fun min(p0: (kotlin.collections.MutableCollection..kotlin.collections.Collection<(T..T?)>?)): (T..T?) where T : (kotlin.Comparable<(T..T?)>..kotlin.Comparable<(T..T?)>?) defined in java.util.Collections" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Double, p1: kotlin.Double): kotlin.Double defined in java.lang.Double" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Float, p1: kotlin.Float): kotlin.Float defined in java.lang.Float" // EXPECT_VARIANT_IN_ORDER "public open fun min(p0: kotlin.Int, p1: kotlin.Int): kotlin.Int defined in java.lang.Integer" From 46f783c60b13bfc2d4f431cec99c67aa00acf52b Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Thu, 18 May 2023 14:54:30 +0300 Subject: [PATCH 019/226] [kotlin k2] Import: enable KotlinAddImportActionTest in K2 Move `KotlinAddActionInfo` to frontend-independent module and `DeclarationDescriptor.variantNameForDebug()` to K1 module ^KTIJ-25990 GitOrigin-RevId: 5d3570bf1b473733b234906ddc803397734769ec --- .../idea/quickfix/fixes/ImportQuickFix.kt | 66 ++++-- .../actions/AbstractK2AddImportActionTest.kt | 21 ++ .../K2AddImportActionTestGenerated.java | 190 ++++++++++++++++++ .../kotlin.fir.frontend-independent.iml | 1 + .../idea/actions/KotlinAddImportActionInfo.kt | 23 +++ .../idea/actions/KotlinAddImportAction.kt | 39 ++-- ....kt => AbstractAddImportActionTestBase.kt} | 25 +-- .../actions/AbstractK1AddImportActionTest.kt | 4 + ...va => K1AddImportActionTestGenerated.java} | 2 +- .../actions/kotlinAddImportAction/Class1.kt | 1 + .../kotlinAddImportAction/Class1.kt.after | 1 + .../actions/kotlinAddImportAction/Class2.kt | 1 + .../kotlinAddImportAction/Class2.kt.after | 1 + .../ConstructorOverloadsPresent.kt | 1 + .../ConstructorOverloadsPresent.kt.after | 1 + .../kotlinAddImportAction/ExtendingClass1.kt | 1 + .../ExtendingClass1.kt.after | 1 + .../SingleMethodAvailable.kt | 1 + .../SingleMethodAvailable.kt.after | 1 + .../KotlinLightCodeInsightFixtureTestCase.kt | 1 - .../fe10/testGenerator/Fe10GenerateTests.kt | 4 +- .../fir/testGenerator/FirGenerateTests.kt | 5 + 22 files changed, 335 insertions(+), 56 deletions(-) create mode 100644 plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/AbstractK2AddImportActionTest.kt create mode 100644 plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/K2AddImportActionTestGenerated.java create mode 100644 plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionInfo.kt rename plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/{AbstractKotlinAddImportActionTest.kt => AbstractAddImportActionTestBase.kt} (72%) create mode 100644 plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractK1AddImportActionTest.kt rename plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/{KotlinAddImportActionTestGenerated.java => K1AddImportActionTestGenerated.java} (98%) diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt index 03113a48047e..ec2e99c85906 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt @@ -19,10 +19,15 @@ import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.parentsOfType import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KtFirDiagnostic -import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol +import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtCallableReturnTypeFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtDeclarationRenderer +import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource +import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererVisibilityModifierProvider +import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility +import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint +import org.jetbrains.kotlin.idea.actions.KotlinAddImportActionInfo import org.jetbrains.kotlin.idea.base.analysis.api.utils.KtSymbolFromIndexProvider import org.jetbrains.kotlin.idea.base.psi.imports.addImport import org.jetbrains.kotlin.idea.base.resources.KotlinBundle @@ -39,8 +44,9 @@ import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability class ImportQuickFix( element: KtElement, - private val importCandidates: List + private val importCandidates: List ) : QuickFixActionBase(element), HintAction { + data class ImportCandidate(val fqName: FqName, val renderedDeclaration: String) init { require(importCandidates.isNotEmpty()) @@ -73,7 +79,7 @@ class ImportQuickFix( val project = file.project val elementRange = element.textRange - val autoImportHintText = KotlinBundle.message("fix.import.question", importCandidates.first().asString()) + val autoImportHintText = KotlinBundle.message("fix.import.question", importCandidates.first().fqName.asString()) HintManager.getInstance().showQuestionHint( editor, @@ -120,7 +126,7 @@ class ImportQuickFix( private val project: Project, private val editor: Editor, private val file: KtFile, - private val importCandidates: List + private val importCandidates: List ) : QuestionAction { init { @@ -128,9 +134,10 @@ class ImportQuickFix( } override fun execute(): Boolean { + KotlinAddImportActionInfo.executeListener?.onExecute(listOf(importCandidates.map { it.renderedDeclaration })) when (importCandidates.size) { 1 -> { - addImport(importCandidates.single()) + addImport(importCandidates.single().fqName) return true } @@ -151,7 +158,7 @@ class ImportQuickFix( return JBPopupFactory.getInstance() .createPopupChooserBuilder(importCandidates) .setTitle(KotlinBundle.message("action.add.import.chooser.title")) - .setItemChosenCallback { selectedValue: FqName -> addImport(selectedValue) } + .setItemChosenCallback { selectedValue: ImportCandidate -> addImport(selectedValue.fqName) } .createPopup() } @@ -175,12 +182,43 @@ class ImportQuickFix( if (isSelectorInQualified(element)) null else createImportNameFix(indexProvider, element, element.getReferencedNameAsName()) } + else -> null } listOfNotNull(quickFix) } + private val renderer: KtDeclarationRenderer = KtDeclarationRendererForSource.WITH_QUALIFIED_NAMES.with { + modifiersRenderer = modifiersRenderer.with { + visibilityProvider = KtRendererVisibilityModifierProvider.WITH_IMPLICIT_VISIBILITY + } + annotationRenderer = annotationRenderer.with { + annotationFilter = KtRendererAnnotationsFilter.NONE + } + returnTypeFilter = KtCallableReturnTypeFilter.ALWAYS + } + + + context(KtAnalysisSession) + private fun renderSymbol(symbol: KtDeclarationSymbol): String = prettyPrint { + val fqName = symbol.getFqName() + if (symbol is KtNamedClassOrObjectSymbol) { + append("class $fqName") + } else { + renderer.renderDeclaration(symbol, printer = this) + } + + when (symbol) { + is KtCallableSymbol -> symbol.callableIdIfNonLocal?.packageName + is KtClassLikeSymbol -> symbol.classIdIfNonLocal?.packageFqName + else -> null + }?.let { packageName -> + append(" defined in ${packageName.asString()}") + symbol.psi?.containingFile?.let { append(" in file ${it.name}") } + } + } + fun KtAnalysisSession.createImportNameFix( indexProvider: KtSymbolFromIndexProvider, element: KtReferenceExpression, @@ -220,14 +258,16 @@ class ImportQuickFix( indexProvider: KtSymbolFromIndexProvider, unresolvedName: Name, isVisible: (KtCallableSymbol) -> Boolean - ): List { + ): List { val callablesCandidates = indexProvider.getKotlinCallableSymbolsByName(unresolvedName) { it.canBeImported() } + - indexProvider.getJavaCallableSymbolsByName(unresolvedName) { it.canBeImported() } + indexProvider.getJavaCallableSymbolsByName(unresolvedName) { it.canBeImported() } return callablesCandidates .filter(isVisible) - .mapNotNull { it.callableIdIfNonLocal?.asSingleFqName() } + .mapNotNull { symbol -> + symbol.callableIdIfNonLocal?.asSingleFqName()?.let { ImportCandidate(it, renderSymbol(symbol)) } + } .toList() } @@ -235,14 +275,14 @@ class ImportQuickFix( indexProvider: KtSymbolFromIndexProvider, unresolvedName: Name, isVisible: (KtNamedClassOrObjectSymbol) -> Boolean - ): List { + ): List { val classesCandidates = indexProvider.getKotlinClassesByName(unresolvedName) { it.canBeImported() } + indexProvider.getJavaClassesByName(unresolvedName) { it.canBeImported() } return classesCandidates .filter(isVisible) - .mapNotNull { it.classIdIfNonLocal?.asSingleFqName() } + .mapNotNull { symbol -> symbol.classIdIfNonLocal?.asSingleFqName()?.let { ImportCandidate(it, renderSymbol(symbol)) } } .toList() } } diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/AbstractK2AddImportActionTest.kt b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/AbstractK2AddImportActionTest.kt new file mode 100644 index 000000000000..3405b9da76c5 --- /dev/null +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/AbstractK2AddImportActionTest.kt @@ -0,0 +1,21 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.fir.actions + +import org.jetbrains.kotlin.idea.actions.AbstractAddImportActionTestBase +import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.test.utils.IgnoreTests + +abstract class AbstractK2AddImportActionTest : AbstractAddImportActionTestBase() { + override fun isFirPlugin(): Boolean = true + + override fun getDefaultProjectDescriptor(): KotlinLightProjectDescriptor { + return KotlinWithJdkAndRuntimeLightProjectDescriptor.getInstance() + } + + override fun doTest(unused: String) { + IgnoreTests.runTestIfEnabledByFileDirective(dataFilePath(), IgnoreTests.DIRECTIVES.FIR_COMPARISON) { + super.doTest(unused) + } + } +} \ No newline at end of file diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/K2AddImportActionTestGenerated.java b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/K2AddImportActionTestGenerated.java new file mode 100644 index 000000000000..467c946e0b94 --- /dev/null +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/K2AddImportActionTestGenerated.java @@ -0,0 +1,190 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +package org.jetbrains.kotlin.idea.fir.actions; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.idea.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.jetbrains.kotlin.idea.base.test.TestRoot; +import org.junit.runner.RunWith; + +/** + * This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}. + * DO NOT MODIFY MANUALLY. + */ +@SuppressWarnings("all") +@TestRoot("fir") +@TestDataPath("$CONTENT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +@TestMetadata("../idea/tests/testData/idea/actions/kotlinAddImportAction") +public class K2AddImportActionTestGenerated extends AbstractK2AddImportActionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("Class1.kt") + public void testClass1() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt"); + } + + @TestMetadata("Class2.kt") + public void testClass2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt"); + } + + @TestMetadata("ClassWhenExtIsImported.kt") + public void testClassWhenExtIsImported() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/ClassWhenExtIsImported.kt"); + } + + @TestMetadata("ConstructorOverloadsPresent.kt") + public void testConstructorOverloadsPresent() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt"); + } + + @TestMetadata("ExtReceiver.kt") + public void testExtReceiver() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver.kt"); + } + + @TestMetadata("ExtReceiver2.kt") + public void testExtReceiver2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver2.kt"); + } + + @TestMetadata("ExtReceiver3.kt") + public void testExtReceiver3() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt"); + } + + @TestMetadata("ExtReceiver4.kt") + public void testExtReceiver4() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt"); + } + + @TestMetadata("ExtendingClass1.kt") + public void testExtendingClass1() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt"); + } + + @TestMetadata("ExtendingClass2.kt") + public void testExtendingClass2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass2.kt"); + } + + @TestMetadata("KotlinDurations.kt") + public void testKotlinDurations() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations.kt"); + } + + @TestMetadata("KotlinDurations2.kt") + public void testKotlinDurations2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinDurations2.kt"); + } + + @TestMetadata("KotlinMinCollections.kt") + public void testKotlinMinCollections() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinCollections.kt"); + } + + @TestMetadata("KotlinMinInt.kt") + public void testKotlinMinInt() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/KotlinMinInt.kt"); + } + + @TestMetadata("MultipleMethodsAvailable.kt") + public void testMultipleMethodsAvailable() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt"); + } + + @TestMetadata("MultipleMethodsAvailable2.kt") + public void testMultipleMethodsAvailable2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt"); + } + + @TestMetadata("Nullable1.kt") + public void testNullable1() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Nullable1.kt"); + } + + @TestMetadata("Nullable2.kt") + public void testNullable2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Nullable2.kt"); + } + + @TestMetadata("Nullable3.kt") + public void testNullable3() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Nullable3.kt"); + } + + @TestMetadata("OverloadsPresent.kt") + public void testOverloadsPresent() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/OverloadsPresent.kt"); + } + + @TestMetadata("PlusAssignOperator.kt") + public void testPlusAssignOperator() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/PlusAssignOperator.kt"); + } + + @TestMetadata("PlusAssignOperator2.kt") + public void testPlusAssignOperator2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/PlusAssignOperator2.kt"); + } + + @TestMetadata("PlusAssignOperatorCall.kt") + public void testPlusAssignOperatorCall() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/PlusAssignOperatorCall.kt"); + } + + @TestMetadata("PlusAssignOperatorCall2.kt") + public void testPlusAssignOperatorCall2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/PlusAssignOperatorCall2.kt"); + } + + @TestMetadata("PlusOperator.kt") + public void testPlusOperator() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/PlusOperator.kt"); + } + + @TestMetadata("PlusOperator1.kt") + public void testPlusOperator1() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/PlusOperator1.kt"); + } + + @TestMetadata("PlusOperatorCall1.kt") + public void testPlusOperatorCall1() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/PlusOperatorCall1.kt"); + } + + @TestMetadata("SingleMethodAvailable.kt") + public void testSingleMethodAvailable() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt"); + } + + @TestMetadata("TypeAlias.kt") + public void testTypeAlias() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/TypeAlias.kt"); + } + + @TestMetadata("VarargSpreadOperator.kt") + public void testVarargSpreadOperator() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt"); + } + + @TestMetadata("Varargs.kt") + public void testVarargs() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs.kt"); + } + + @TestMetadata("Varargs2.kt") + public void testVarargs2() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs2.kt"); + } + + @TestMetadata("Varargs3.kt") + public void testVarargs3() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt"); + } +} diff --git a/plugins/kotlin/frontend-independent/kotlin.fir.frontend-independent.iml b/plugins/kotlin/frontend-independent/kotlin.fir.frontend-independent.iml index 67e2238eab9a..bb7a55b7c09d 100644 --- a/plugins/kotlin/frontend-independent/kotlin.fir.frontend-independent.iml +++ b/plugins/kotlin/frontend-independent/kotlin.fir.frontend-independent.iml @@ -30,5 +30,6 @@ + \ No newline at end of file diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionInfo.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionInfo.kt new file mode 100644 index 000000000000..ac58b81e7381 --- /dev/null +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionInfo.kt @@ -0,0 +1,23 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.actions + +import com.intellij.openapi.Disposable +import com.intellij.openapi.util.Disposer +import org.jetbrains.annotations.TestOnly + +/** Test hooks allowing inspection of data used for KotlinAddImportAction. **/ +object KotlinAddImportActionInfo { + interface ExecuteListener { + fun onExecute(variants: List>) + } + + @Volatile + var executeListener: ExecuteListener? = null + + @TestOnly + fun setExecuteListener(disposable: Disposable, listener: ExecuteListener) { + assert(executeListener == null) + executeListener = listener + Disposer.register(disposable) { executeListener = null } + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index cabc6acfcdd9..50ffc9a0c32a 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -49,7 +49,9 @@ import org.jetbrains.kotlin.name.parentOrNull import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.ImportPath +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import java.awt.BorderLayout import javax.swing.Icon import javax.swing.JPanel @@ -180,7 +182,9 @@ class KotlinAddImportAction internal constructor( if (!element.isValid) return false val variantsList = variantsList() - KotlinAddImportActionInfo.executeListener?.onExecute(variantsList.map { it.descriptorsToImport.toList() }) + KotlinAddImportActionInfo.executeListener?.onExecute(variantsList.map { + it.descriptorsToImport.map { descriptorToImport -> descriptorToImport.variantNameForDebug() }.toList() + }) if (variantsList.isEmpty()) return false @@ -292,6 +296,20 @@ class KotlinAddImportAction internal constructor( } } } + + companion object { + private val debugRenderer = DescriptorRenderer.DEBUG_TEXT.withOptions { + annotationFilter = { false } + } + + private fun DeclarationDescriptor.variantNameForDebug() = when (this) { + is ClassDescriptor -> + fqNameOrNull()?.toString()?.let { "class $it" } ?: debugRenderer.render(this) + + else -> + debugRenderer.render(this) + } + } } internal interface ComparablePriority : Comparable @@ -418,21 +436,4 @@ private class SingleImportVariant( project = project, ) { override val hint: String get() = excludeFqNameCheck.asString() -} - -/** Test hooks allowing inspection of data used for KotlinAddImportAction. **/ -object KotlinAddImportActionInfo { - interface ExecuteListener { - fun onExecute(variants: List>) - } - - @Volatile - internal var executeListener: ExecuteListener? = null - - @TestOnly - fun setExecuteListener(disposable: Disposable, listener: ExecuteListener) { - assert(executeListener == null) - executeListener = listener - Disposer.register(disposable) { executeListener = null } - } -} +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractKotlinAddImportActionTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt similarity index 72% rename from plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractKotlinAddImportActionTest.kt rename to plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt index 5d6347b3285b..1ef7fb8dea62 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractKotlinAddImportActionTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt @@ -2,17 +2,13 @@ package org.jetbrains.kotlin.idea.actions import com.intellij.openapi.util.io.FileUtil -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase -import org.jetbrains.kotlin.renderer.DescriptorRenderer -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import java.io.File -abstract class AbstractKotlinAddImportActionTest : KotlinLightCodeInsightFixtureTestCase() { +abstract class AbstractAddImportActionTestBase : KotlinLightCodeInsightFixtureTestCase() { - protected fun doTest(unused: String) { + protected open fun doTest(unused: String) { val fixture = myFixture val dependencySuffixes = listOf(".dependency.kt", ".dependency1.kt", ".dependency2.kt") @@ -29,9 +25,9 @@ abstract class AbstractKotlinAddImportActionTest : KotlinLightCodeInsightFixture fixture.configureByFile(fileName()) - var actualVariants: List>? = null + var actualVariants: List>? = null val executeListener = object : KotlinAddImportActionInfo.ExecuteListener { - override fun onExecute(variants: List>) { + override fun onExecute(variants: List>) { assertNull(actualVariants) actualVariants = variants } @@ -47,7 +43,7 @@ abstract class AbstractKotlinAddImportActionTest : KotlinLightCodeInsightFixture val expectedAbsentVariantNames = InTextDirectivesUtils.findListWithPrefixes(fixture.file.text, "EXPECT_VARIANT_NOT_PRESENT") if (expectedVariantNames.isNotEmpty() || expectedAbsentVariantNames.isNotEmpty()) { - val actualVariantNames = actualVariants!!.flatten().map { it.variantName() } + val actualVariantNames = actualVariants!!.flatten() for (i in expectedVariantNames.indices) { assertTrue( @@ -66,15 +62,4 @@ abstract class AbstractKotlinAddImportActionTest : KotlinLightCodeInsightFixture myFixture.checkResultByFile("${fileName()}.after") } - - private val debugRenderer = DescriptorRenderer.DEBUG_TEXT.withOptions { - annotationFilter = { false } - } - - private fun DeclarationDescriptor.variantName() = when(this) { - is ClassDescriptor -> - fqNameOrNull()?.toString()?.let { "class $it" } ?: debugRenderer.render(this) - else -> - debugRenderer.render(this) - } } diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractK1AddImportActionTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractK1AddImportActionTest.kt new file mode 100644 index 000000000000..ad33d4b03454 --- /dev/null +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractK1AddImportActionTest.kt @@ -0,0 +1,4 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.actions + +abstract class AbstractK1AddImportActionTest : AbstractAddImportActionTestBase() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java similarity index 98% rename from plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionTestGenerated.java rename to plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java index 6734d864822a..5504bc42f8b9 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java @@ -18,7 +18,7 @@ import org.junit.runner.RunWith; @TestDataPath("$CONTENT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("testData/idea/actions/kotlinAddImportAction") -public class KotlinAddImportActionTestGenerated extends AbstractKotlinAddImportActionTest { +public class K1AddImportActionTestGenerated extends AbstractK1AddImportActionTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt index eb3f0547016a..a5638566ab9f 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "class package2.MyClass" // EXPECT_VARIANT_IN_ORDER "class package3.MyClass" package root diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt.after index 52340ae09f92..1e15cec1ce92 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class1.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "class package2.MyClass" // EXPECT_VARIANT_IN_ORDER "class package3.MyClass" package root diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt index fd46c9046ff5..1934fc4fccbb 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "class package3.MyClass" // EXPECT_VARIANT_IN_ORDER "class package2.MyClass" package root diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt.after index 3b9e2c03c28b..b756d6d37c3c 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/Class2.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "class package3.MyClass" // EXPECT_VARIANT_IN_ORDER "class package2.MyClass" package root diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt index c716b3ae92f7..4ba71525d591 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "class root.p.Bar" // EXPECT_VARIANT_IN_ORDER "class root.q.Bar" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt.after index 5a912ec967cd..60c224ae9971 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ConstructorOverloadsPresent.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "class root.p.Bar" // EXPECT_VARIANT_IN_ORDER "class root.q.Bar" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt index 48ed0371a54a..18893ba73ae1 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "class package2.MyClass" // EXPECT_VARIANT_IN_ORDER "class package3.MyClass" package root diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt.after index 0127a2990e7e..cea0a5d2b090 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtendingClass1.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "class package2.MyClass" // EXPECT_VARIANT_IN_ORDER "class package3.MyClass" package root diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt index 0675028f95f7..b1afcc1a1966 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON package root fun foo() { diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt.after index 4e824cf25d08..be8a77c1966f 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/SingleMethodAvailable.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON package root import root.p.bar diff --git a/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightCodeInsightFixtureTestCase.kt b/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightCodeInsightFixtureTestCase.kt index 4f7c983646bd..73bb78938b70 100644 --- a/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightCodeInsightFixtureTestCase.kt +++ b/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightCodeInsightFixtureTestCase.kt @@ -316,7 +316,6 @@ abstract class KotlinLightCodeInsightFixtureTestCase : KotlinLightCodeInsightFix } protected open fun getDefaultProjectDescriptor(): KotlinLightProjectDescriptor = KotlinLightProjectDescriptor.INSTANCE - protected fun performNotWriteEditorAction(actionId: String): Boolean { val dataContext = (myFixture.editor as EditorEx).dataContext diff --git a/plugins/kotlin/util/test-generator-fe10/test/org/jetbrains/kotlin/fe10/testGenerator/Fe10GenerateTests.kt b/plugins/kotlin/util/test-generator-fe10/test/org/jetbrains/kotlin/fe10/testGenerator/Fe10GenerateTests.kt index 9c90c983c3b9..2f5f96375148 100644 --- a/plugins/kotlin/util/test-generator-fe10/test/org/jetbrains/kotlin/fe10/testGenerator/Fe10GenerateTests.kt +++ b/plugins/kotlin/util/test-generator-fe10/test/org/jetbrains/kotlin/fe10/testGenerator/Fe10GenerateTests.kt @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.idea.AbstractExpressionSelectionTest import org.jetbrains.kotlin.idea.AbstractSmartSelectionTest import org.jetbrains.kotlin.idea.AbstractWorkSelectionTest import org.jetbrains.kotlin.idea.actions.AbstractGotoTestOrCodeActionTest -import org.jetbrains.kotlin.idea.actions.AbstractKotlinAddImportActionTest +import org.jetbrains.kotlin.idea.actions.AbstractK1AddImportActionTest import org.jetbrains.kotlin.idea.base.plugin.artifacts.TestKotlinArtifacts import org.jetbrains.kotlin.idea.caches.resolve.AbstractMultiModuleLineMarkerTest import org.jetbrains.kotlin.idea.caches.resolve.AbstractMultiPlatformHighlightingTest @@ -826,7 +826,7 @@ private fun assembleWorkspace(): TWorkspace = workspace { model("addImportAlias", pattern = KT_WITHOUT_DOTS) } - testClass { + testClass { model("idea/actions/kotlinAddImportAction", pattern = KT_WITHOUT_DOTS) } diff --git a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt index 969e55bdef71..e3db73644965 100644 --- a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt +++ b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt @@ -4,6 +4,7 @@ package org.jetbrains.kotlin.fir.testGenerator import org.jetbrains.fir.uast.test.* import org.jetbrains.kotlin.fir.testGenerator.codeinsight.generateK2CodeInsightTests +import org.jetbrains.kotlin.idea.fir.actions.AbstractK2AddImportActionTest import org.jetbrains.kotlin.idea.fir.analysis.providers.AbstractIdeKotlinAnnotationsResolverTest import org.jetbrains.kotlin.idea.fir.analysis.providers.sessions.AbstractSessionsInvalidationTest import org.jetbrains.kotlin.idea.fir.analysis.providers.trackers.AbstractProjectWideOutOfBlockKotlinModificationTrackerTest @@ -88,6 +89,10 @@ private fun assembleWorkspace(): TWorkspace = workspace { } testGroup("fir", testDataPath = "../idea/tests/testData") { + testClass { + model("idea/actions/kotlinAddImportAction", pattern = KT_WITHOUT_DOTS) + } + testClass { model("resolve/references", pattern = KT_WITHOUT_DOTS) } From 5abb68246f8392899a85ea7b4dee27e5792cbab2 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Tue, 9 May 2023 12:09:46 +0300 Subject: [PATCH 020/226] [kotlin k2] Import: extract frontend-independent part of calculation of text for import fix ^KTIJ-23199 GitOrigin-RevId: 890b28d744f0c4401f31938e4643ba03384f287f --- .../kotlin/idea/quickfix/ImportFixHelper.kt | 78 +++++++++++++++++++ .../kotlin/idea/quickfix/AbstractImportFix.kt | 75 +++--------------- 2 files changed, 90 insertions(+), 63 deletions(-) create mode 100644 plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt new file mode 100644 index 000000000000..dbe99a756c28 --- /dev/null +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt @@ -0,0 +1,78 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.codeInspection.util.IntentionName +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.parentOrNull +import java.util.* + +object ImportFixHelper { + enum class ImportKind(private val key: String, val groupedByPackage: Boolean = false) { + CLASS("text.class.0", true), + PROPERTY("text.property.0"), + OBJECT("text.object.0", true), + FUNCTION("text.function.0"), + EXTENSION_PROPERTY("text.extension.property.0"), + EXTENSION_FUNCTION("text.extension.function.0"), + OPERATOR("text.operator.0"); + + fun toText(number: Int) = KotlinBundle.message(key, if (number == 1) 1 else 2) + } + + class ImportInfo>(val kind: ImportKind, val name: String, val priority: T) + + @IntentionName + fun > calculateTextForFix(importInfos: Iterable>, suggestions: Iterable): String { + val importNamesGroupedByKind = importInfos.groupBy(keySelector = { it.kind }) { it } + + return if (importNamesGroupedByKind.size == 1) { + val (kind, names) = importNamesGroupedByKind.entries.first() + val sortedImportInfos = TreeSet>(compareBy({ it.priority }, { it.name })) + sortedImportInfos.addAll(names) + val firstName = sortedImportInfos.first().name + val singlePackage = suggestions.groupBy { it.parentOrNull() ?: FqName.ROOT }.size == 1 + + if (singlePackage) { + val sortedByName = sortedImportInfos.toSortedSet(compareBy { it.name }) + val size = sortedByName.size + if (size == 2) { + KotlinBundle.message( + "fix.import.kind.0.name.1.and.name.2", + kind.toText(size), + sortedByName.first().name, + sortedByName.last().name + ) + } else { + KotlinBundle.message("fix.import.kind.0.name.1.2", kind.toText(size), firstName, size - 1) + } + } else if (kind.groupedByPackage) { + KotlinBundle.message("fix.import.kind.0.name.1.2", kind.toText(1), firstName, 0) + } else { + val groupBy = sortedImportInfos.map { it.name }.toSortedSet().groupBy { it.substringBefore('.') } + val value = groupBy.entries.first().value + val first = value.first() + val multiple = if (value.size == 1) 0 else 1 + when { + groupBy.size != 1 -> KotlinBundle.message( + "fix.import.kind.0.name.1.2", + kind.toText(1), + first.substringAfter('.'), + multiple + ) + + value.size == 2 -> KotlinBundle.message( + "fix.import.kind.0.name.1.and.name.2", + kind.toText(value.size), + first, + value.last() + ) + + else -> KotlinBundle.message("fix.import.kind.0.name.1.2", kind.toText(1), first, multiple) + } + } + } else { + KotlinBundle.message("fix.import") + } + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt index 3914b3fa5aee..b056a2ffd173 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt @@ -18,11 +18,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.IntellijInternalApi import com.intellij.packageDependencies.DependencyValidationManager -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiErrorElement -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiModifier -import com.intellij.psi.SmartPsiElementPointer +import com.intellij.psi.* import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.elementType import com.intellij.util.Processors @@ -57,7 +53,6 @@ import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.parentOrNull import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtPsiUtil.isSelectorInQualified @@ -81,7 +76,6 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments import org.jetbrains.kotlin.utils.addToStdlib.safeAs -import java.util.* /** * Check possibility and perform fix for unresolved references. @@ -148,16 +142,16 @@ abstract class ImportFixBase protected constructor( val languageVersionSettings = ktFile.languageVersionSettings val prioritizer = Prioritizer(ktFile, element) - val kindNameGroupedByKind = descriptors.mapNotNull { descriptor -> + val importInfos = descriptors.mapNotNull { descriptor -> val kind = when { - descriptor.isExtensionProperty -> ImportKind.EXTENSION_PROPERTY - descriptor is PropertyDescriptor -> ImportKind.PROPERTY - descriptor is ClassConstructorDescriptor -> ImportKind.CLASS - descriptor is FunctionDescriptor && descriptor.isOperator -> ImportKind.OPERATOR - descriptor is FunctionDescriptor && descriptor.isExtension -> ImportKind.EXTENSION_FUNCTION - descriptor is FunctionDescriptor -> ImportKind.FUNCTION - DescriptorUtils.isObject(descriptor) -> ImportKind.OBJECT - descriptor is ClassDescriptor -> ImportKind.CLASS + descriptor.isExtensionProperty -> ImportFixHelper.ImportKind.EXTENSION_PROPERTY + descriptor is PropertyDescriptor -> ImportFixHelper.ImportKind.PROPERTY + descriptor is ClassConstructorDescriptor -> ImportFixHelper.ImportKind.CLASS + descriptor is FunctionDescriptor && descriptor.isOperator -> ImportFixHelper.ImportKind.OPERATOR + descriptor is FunctionDescriptor && descriptor.isExtension -> ImportFixHelper.ImportKind.EXTENSION_FUNCTION + descriptor is FunctionDescriptor -> ImportFixHelper.ImportKind.FUNCTION + DescriptorUtils.isObject(descriptor) -> ImportFixHelper.ImportKind.OBJECT + descriptor is ClassDescriptor -> ImportFixHelper.ImportKind.CLASS else -> null } ?: return@mapNotNull null @@ -180,54 +174,9 @@ abstract class ImportFixBase protected constructor( append(it.asString()) } } - ImportName(kind, name, prioritizer.priority(descriptor, languageVersionSettings)) - }.groupBy(keySelector = { it.kind }) { it } - - return if (kindNameGroupedByKind.size == 1) { - val (kind, names) = kindNameGroupedByKind.entries.first() - val sortedImportNames = TreeSet(compareBy({ it.priority }, { it.name })) - sortedImportNames.addAll(names) - val firstName = sortedImportNames.first().name - val singlePackage = suggestions.groupBy { it.parentOrNull() ?: FqName.ROOT }.size == 1 - - if (singlePackage) { - val sortedByName = sortedImportNames.toSortedSet(compareBy { it.name }) - val size = sortedByName.size - if (size == 2) { - KotlinBundle.message("fix.import.kind.0.name.1.and.name.2", kind.toText(size), sortedByName.first().name, sortedByName.last().name) - } else { - KotlinBundle.message("fix.import.kind.0.name.1.2", kind.toText(size), firstName, size - 1) - } - } else if (kind.groupedByPackage) { - KotlinBundle.message("fix.import.kind.0.name.1.2", kind.toText(1), firstName, 0) - } else { - val groupBy = sortedImportNames.map { it.name }.toSortedSet().groupBy { it.substringBefore('.') } - val value = groupBy.entries.first().value - val first = value.first() - val multiple = if (value.size == 1) 0 else 1 - when { - groupBy.size != 1 -> KotlinBundle.message("fix.import.kind.0.name.1.2", kind.toText(1), first.substringAfter('.'), multiple) - value.size == 2 -> KotlinBundle.message("fix.import.kind.0.name.1.and.name.2", kind.toText(value.size), first, value.last()) - else -> KotlinBundle.message("fix.import.kind.0.name.1.2", kind.toText(1), first, multiple) - } - } - } else { - KotlinBundle.message("fix.import") + ImportFixHelper.ImportInfo(kind, name, prioritizer.priority(descriptor, languageVersionSettings)) } - } - - private class ImportName(val kind: ImportKind, val name: String, val priority: ComparablePriority) - - private enum class ImportKind(private val key: String, val groupedByPackage: Boolean = false) { - CLASS("text.class.0", true), - PROPERTY("text.property.0"), - OBJECT("text.object.0", true), - FUNCTION("text.function.0"), - EXTENSION_PROPERTY("text.extension.property.0"), - EXTENSION_FUNCTION("text.extension.function.0"), - OPERATOR("text.operator.0"); - - fun toText(number: Int) = KotlinBundle.message(key, if (number == 1) 1 else 2) + return ImportFixHelper.calculateTextForFix(importInfos, suggestions) } override fun getText(): String = text From cf45c8c76e20638e377835e5886d007dd9071529 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Fri, 12 May 2023 11:00:49 +0300 Subject: [PATCH 021/226] [kotlin k2] Import: move `ImportableFqNameClassifier` KTIJ-25990 GitOrigin-RevId: 2fc78d942f3526917488c1c83d9790fa85ff5ac7 --- .../kotlin/idea/completion/AllClassesCompletion.kt | 1 + .../jetbrains/kotlin/idea/completion/CompletionSession.kt | 2 ++ .../jetbrains/kotlin/idea/completion/CompletionUtils.kt | 1 + .../kotlin/idea/completion/ReferenceVariantsCollector.kt | 1 + .../src/org/jetbrains/kotlin/idea/completion/Weighers.kt | 1 + .../idea/completion/impl/k2/weighers/NotImportedWeigher.kt | 2 +- .../kotlin/idea/completion/impl/k2/weighers/Weighers.kt | 2 +- .../idea/completion/implCommon/completionUtilsNoResolve.kt | 6 ------ .../idea/base/utils/fqname}/ImportableFqNameClassifier.kt | 7 ++----- .../jetbrains/kotlin/idea/base/utils/fqname/fqNameUtil.kt | 3 +++ .../jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) rename plugins/kotlin/{completion/impl-shared/src/org/jetbrains/kotlin/idea/completion/implCommon => frontend-independent/src/org/jetbrains/kotlin/idea/base/utils/fqname}/ImportableFqNameClassifier.kt (90%) diff --git a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/AllClassesCompletion.kt b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/AllClassesCompletion.kt index 6156ef220738..0284ee2e83f7 100644 --- a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/AllClassesCompletion.kt +++ b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/AllClassesCompletion.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters import org.jetbrains.kotlin.idea.base.facet.platform.platform import org.jetbrains.kotlin.idea.base.psi.kotlinFqName +import org.jetbrains.kotlin.idea.base.utils.fqname.isJavaClassNotToBeUsedInKotlin import org.jetbrains.kotlin.idea.caches.KotlinShortNamesCache import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper import org.jetbrains.kotlin.idea.resolve.ResolutionFacade diff --git a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index fab6445efb12..d0ac989487f8 100644 --- a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -22,6 +22,8 @@ import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo.ModuleOrigin import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo.OriginCapability import org.jetbrains.kotlin.idea.base.psi.isInsideAnnotationEntryArgumentList +import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier +import org.jetbrains.kotlin.idea.base.utils.fqname.isJavaClassNotToBeUsedInKotlin import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.util.getResolveScope import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper diff --git a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt index 855f5f4f9990..3df91b7d7c15 100644 --- a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt +++ b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.KotlinIcons +import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler import org.jetbrains.kotlin.idea.completion.smart.KeywordProbability import org.jetbrains.kotlin.idea.completion.smart.keywordProbability diff --git a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/ReferenceVariantsCollector.kt b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/ReferenceVariantsCollector.kt index 3a7cdb08feb3..2c986abb4555 100644 --- a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/ReferenceVariantsCollector.kt +++ b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/ReferenceVariantsCollector.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.completion import com.intellij.codeInsight.completion.PrefixMatcher import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper import org.jetbrains.kotlin.idea.core.util.externalDescriptors diff --git a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/Weighers.kt b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/Weighers.kt index b95469ea89f6..f51c0cfb28a7 100644 --- a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/Weighers.kt +++ b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/Weighers.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.base.codeInsight.isEnumValuesSoftDeprecateEnabled import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings +import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.completion.implCommon.weighers.SoftDeprecationWeigher import org.jetbrains.kotlin.idea.completion.smart.* import org.jetbrains.kotlin.idea.core.ExpectedInfo diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/NotImportedWeigher.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/NotImportedWeigher.kt index dd6b8f783454..a4692a734a2a 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/NotImportedWeigher.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/NotImportedWeigher.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtPackageSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol -import org.jetbrains.kotlin.idea.completion.ImportableFqNameClassifier +import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier import org.jetbrains.kotlin.psi.UserDataProperty internal object NotImportedWeigher { diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/Weighers.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/Weighers.kt index 42bcc9b36713..9b82a6f878ee 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/Weighers.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/Weighers.kt @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.idea.base.facet.platform.platform import org.jetbrains.kotlin.idea.base.projectStructure.compositeAnalysis.findAnalyzerServices import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings -import org.jetbrains.kotlin.idea.completion.ImportableFqNameClassifier +import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.completion.contributors.helpers.CompletionSymbolOrigin import org.jetbrains.kotlin.idea.completion.contributors.helpers.KtSymbolWithOrigin import org.jetbrains.kotlin.idea.completion.impl.k2.weighers.K2SoftDeprecationWeigher diff --git a/plugins/kotlin/completion/impl-shared/src/org/jetbrains/kotlin/idea/completion/implCommon/completionUtilsNoResolve.kt b/plugins/kotlin/completion/impl-shared/src/org/jetbrains/kotlin/idea/completion/implCommon/completionUtilsNoResolve.kt index 5a4ca431937b..651bb6c93c06 100644 --- a/plugins/kotlin/completion/impl-shared/src/org/jetbrains/kotlin/idea/completion/implCommon/completionUtilsNoResolve.kt +++ b/plugins/kotlin/completion/impl-shared/src/org/jetbrains/kotlin/idea/completion/implCommon/completionUtilsNoResolve.kt @@ -10,11 +10,8 @@ import com.intellij.patterns.StandardPatterns import com.intellij.psi.PsiElement import com.intellij.ui.JBColor import org.jetbrains.annotations.ApiStatus -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.load.java.javaToKotlinNameMap -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject @@ -170,9 +167,6 @@ fun referenceScope(declaration: KtNamedDeclaration): KtElement? = when (val pare else -> null } -fun FqName.isJavaClassNotToBeUsedInKotlin(): Boolean = - JavaToKotlinClassMap.isJavaPlatformClass(this) || javaToKotlinNameMap[this] != null - fun findValueArgument(expression: KtExpression): KtValueArgument? { // Search for value argument among parent and grandparent to avoid parsing errors like KTIJ-18231 return expression.parent as? KtValueArgument diff --git a/plugins/kotlin/completion/impl-shared/src/org/jetbrains/kotlin/idea/completion/implCommon/ImportableFqNameClassifier.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/base/utils/fqname/ImportableFqNameClassifier.kt similarity index 90% rename from plugins/kotlin/completion/impl-shared/src/org/jetbrains/kotlin/idea/completion/implCommon/ImportableFqNameClassifier.kt rename to plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/base/utils/fqname/ImportableFqNameClassifier.kt index 9b642183dc6f..be37aa770e84 100644 --- a/plugins/kotlin/completion/impl-shared/src/org/jetbrains/kotlin/idea/completion/implCommon/ImportableFqNameClassifier.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/base/utils/fqname/ImportableFqNameClassifier.kt @@ -1,9 +1,6 @@ -/* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package org.jetbrains.kotlin.idea.completion +package org.jetbrains.kotlin.idea.base.utils.fqname import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/base/utils/fqname/fqNameUtil.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/base/utils/fqname/fqNameUtil.kt index a57a2cbb7981..e444126e9d4d 100644 --- a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/base/utils/fqname/fqNameUtil.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/base/utils/fqname/fqNameUtil.kt @@ -57,3 +57,6 @@ val KotlinType.fqName: FqName? is AbbreviatedType -> abbreviation.fqName else -> constructor.declarationDescriptor?.fqNameOrNull() } + +fun FqName.isJavaClassNotToBeUsedInKotlin(): Boolean = + JavaToKotlinClassMap.isJavaPlatformClass(this) || this in javaToKotlinNameMap \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index 50ffc9a0c32a..5ca0d16127ab 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -31,7 +31,7 @@ import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.base.util.module import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde -import org.jetbrains.kotlin.idea.completion.ImportableFqNameClassifier +import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.completion.KotlinStatisticsInfo import org.jetbrains.kotlin.idea.completion.isDeprecatedAtCallSite import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress From c1eaad81cc7be59cfc2488b2f28f6114f6110ad5 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Fri, 12 May 2023 12:14:32 +0300 Subject: [PATCH 022/226] [kotlin k2] Import: move import prioritizer to frontend-independent module KTIJ-25990 GitOrigin-RevId: 5f7f257a4ce7e57922b3429144b0639e420772d6 --- .../kotlin/idea/quickfix/ImportPrioritizer.kt | 82 ++++++++++ .../idea/actions/KotlinAddImportAction.kt | 146 ++++++------------ .../kotlin/idea/quickfix/AbstractImportFix.kt | 8 +- 3 files changed, 135 insertions(+), 101 deletions(-) create mode 100644 plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportPrioritizer.kt diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportPrioritizer.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportPrioritizer.kt new file mode 100644 index 000000000000..8ec0ce2182d9 --- /dev/null +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportPrioritizer.kt @@ -0,0 +1,82 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.psi.PsiElement +import com.intellij.psi.WeighingComparable +import com.intellij.psi.WeighingService +import com.intellij.psi.statistics.StatisticsInfo +import com.intellij.psi.statistics.StatisticsManager +import com.intellij.psi.util.ProximityLocation +import com.intellij.psi.util.proximity.PsiProximityComparator +import org.jetbrains.kotlin.idea.base.util.module +import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtFile + +interface ImportComparablePriority : Comparable + +class ImportPrioritizer( + val file: KtFile, + isImportedByDefault: (FqName) -> Boolean, + private val compareNames: Boolean = true +) { + private val classifier = ImportableFqNameClassifier(file, isImportedByDefault) + private val statsManager = StatisticsManager.getInstance() + private val proximityLocation = ProximityLocation(file, file.module) + + inner class Priority( + declaration: PsiElement?, + val statisticsInfo: StatisticsInfo, + private val isDeprecated: Boolean, + private val fqName: FqName, + private val expressionWeight: Int, + ) : ImportComparablePriority { + private val classification: ImportableFqNameClassifier.Classification = classifier.classify(fqName, false) + private val lastUseRecency: Int = statsManager.getLastUseRecency(statisticsInfo) + private val proximityWeight: WeighingComparable = + WeighingService.weigh(PsiProximityComparator.WEIGHER_KEY, declaration, proximityLocation) + + override fun compareTo(other: ImportComparablePriority): Int { + other as Priority + + if (isDeprecated != other.isDeprecated) { + return if (isDeprecated) +1 else -1 + } + + val c1 = expressionWeight.compareTo(other.expressionWeight) + if (c1 != 0) { + // callExpressionWeigh is non-negative number + // Comparator contract says that if `a.compareTo(b)` returns -1 then `a` appears earlier than `b` + return -c1 + } + + val c2 = classification.compareTo(other.classification) + if (c2 != 0) return c2 + + val c3 = lastUseRecency.compareTo(other.lastUseRecency) + if (c3 != 0) return c3 + + val c4 = proximityWeight.compareTo(other.proximityWeight) + if (c4 != 0) return -c4 // n.b. reversed + + return if (compareNames) { + fqName.asString().compareTo(other.fqName.asString()) + } else { + 0 + } + } + } + + inner class GroupPriority(private val priorities: List) : ImportComparablePriority { + private val groupPriority = priorities.max() + + override fun compareTo(other: ImportComparablePriority): Int { + other as GroupPriority + + val c1 = groupPriority.compareTo(other.groupPriority) + if (c1 != 0) return c1 + + return other.priorities.size - priorities.size + } + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index 5ca0d16127ab..0005c023805f 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -18,24 +18,22 @@ import com.intellij.openapi.ui.popup.util.BaseListPopupStep import com.intellij.openapi.util.Disposer import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement -import com.intellij.psi.WeighingService import com.intellij.psi.statistics.StatisticsManager -import com.intellij.psi.util.ProximityLocation -import com.intellij.psi.util.proximity.PsiProximityComparator import org.jetbrains.annotations.TestOnly -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.PackageViewDescriptor import org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings import org.jetbrains.kotlin.idea.base.resources.KotlinBundle -import org.jetbrains.kotlin.idea.base.util.module import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde -import org.jetbrains.kotlin.idea.base.utils.fqname.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.completion.KotlinStatisticsInfo import org.jetbrains.kotlin.idea.completion.isDeprecatedAtCallSite import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress import org.jetbrains.kotlin.idea.imports.importableFqName +import org.jetbrains.kotlin.idea.quickfix.ImportComparablePriority +import org.jetbrains.kotlin.idea.quickfix.ImportPrioritizer import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors @@ -46,7 +44,9 @@ import org.jetbrains.kotlin.idea.util.application.underModalProgressOrUnderWrite import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.isOneSegmentFQN import org.jetbrains.kotlin.name.parentOrNull -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.renderer.DescriptorRenderer @@ -64,10 +64,12 @@ internal fun createSingleImportAction( fqNames: Collection ): KotlinAddImportAction { val file = element.containingKtFile - val prioritizer = Prioritizer(file, element) + val prioritizer = createPrioritizerForFile(file) + val expressionWeigher = ExpressionWeigher.createWeigher(element) + val variants = fqNames.asSequence().mapNotNull { fqName -> val sameFqNameDescriptors = file.resolveImportReference(fqName) - createVariantWithPriority(fqName, sameFqNameDescriptors, file, prioritizer, project) + createVariantWithPriority(fqName, sameFqNameDescriptors, prioritizer, expressionWeigher, project) }.sortedWith(compareBy({ it.priority }, { it.variant.hint })) return KotlinAddImportAction(project, editor, element, variants) @@ -80,12 +82,14 @@ internal fun createSingleImportActionForConstructor( fqNames: Collection ): KotlinAddImportAction { val file = element.containingKtFile - val prioritizer = Prioritizer(file) + val prioritizer = createPrioritizerForFile(file) + val expressionWeigher = ExpressionWeigher.createWeigher(element) + val variants = fqNames.asSequence().mapNotNull { fqName -> val sameFqNameDescriptors = file.resolveImportReference(fqName.parent()) .filterIsInstance() .flatMap { it.constructors } - createVariantWithPriority(fqName, sameFqNameDescriptors, file, prioritizer, project) + createVariantWithPriority(fqName, sameFqNameDescriptors, prioritizer, expressionWeigher, project) } return KotlinAddImportAction(project, editor, element, variants) @@ -94,12 +98,12 @@ internal fun createSingleImportActionForConstructor( private fun createVariantWithPriority( fqName: FqName, sameFqNameDescriptors: Collection, - file: KtFile, - prioritizer: Prioritizer, + prioritizer: ImportPrioritizer, + expressionWeigher: ExpressionWeigher, project: Project ): VariantWithPriority? { val descriptorsWithPriority = - sameFqNameDescriptors.map { it to prioritizer.priority(it, file.languageVersionSettings) }.sortedBy { it.second } + sameFqNameDescriptors.map { it to createDescriptorPriority(prioritizer, expressionWeigher, it) }.sortedBy { it.second } val priority = descriptorsWithPriority.firstOrNull()?.second ?: return null return VariantWithPriority(SingleImportVariant(fqName, descriptorsWithPriority.map { it.first }, project), priority) @@ -113,7 +117,9 @@ internal fun createGroupedImportsAction( fqNames: Collection ): KotlinAddImportAction { val file = element.containingKtFile - val prioritizer = DescriptorGroupPrioritizer(file) + val prioritizer = createPrioritizerForFile(file) + val expressionWeigher = ExpressionWeigher.createWeigher(element) + val variants = fqNames.groupBy { it.parentOrNull() ?: FqName.ROOT }.asSequence().map { val samePackageFqNames = it.value val descriptors = samePackageFqNames.flatMap { fqName -> file.resolveImportReference(fqName) } @@ -123,7 +129,7 @@ internal fun createGroupedImportsAction( SingleImportVariant(samePackageFqNames.first(), descriptors, project) } - val priority = prioritizer.priority(descriptors, file.languageVersionSettings) + val priority = createDescriptorGroupPriority(prioritizer, expressionWeigher, descriptors) VariantWithPriority(variant, priority) } @@ -312,94 +318,38 @@ class KotlinAddImportAction internal constructor( } } -internal interface ComparablePriority : Comparable +internal data class VariantWithPriority(val variant: AutoImportVariant, val priority: ImportComparablePriority) -internal data class VariantWithPriority(val variant: AutoImportVariant, val priority: ComparablePriority) - - -internal class Prioritizer( - private val file: KtFile, - element: PsiElement? = null, - private val compareNames: Boolean = true -) { - private val classifier = ImportableFqNameClassifier(file) { - ImportInsertHelper.getInstance(file.project).isImportedWithDefault(ImportPath(it, false), file) +internal fun createPrioritizerForFile(file: KtFile, compareNames: Boolean = true): ImportPrioritizer { + val isImportedByDefault = { fqName: FqName -> + ImportInsertHelper.getInstance(file.project).isImportedWithDefault(ImportPath(fqName, isAllUnder = false), file) } - private val statsManager = StatisticsManager.getInstance() - private val proximityLocation = ProximityLocation(file, file.module) - private val expressionWeigher = ExpressionWeigher.createWeigher(element) - - inner class Priority(descriptor: DeclarationDescriptor, languageVersionSettings: LanguageVersionSettings) : ComparablePriority { - private val isDeprecated = isDeprecatedAtCallSite(descriptor) { languageVersionSettings } - private val fqName = descriptor.importableFqName!! - private val classification = classifier.classify(fqName, false) - private val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor) - private val lastUseRecency = statsManager.getLastUseRecency(KotlinStatisticsInfo.forDescriptor(descriptor)) - private val proximityWeight = WeighingService.weigh(PsiProximityComparator.WEIGHER_KEY, declaration, proximityLocation) - private val callExpressionWeigh = expressionWeigher.weigh(descriptor) - - override fun compareTo(other: ComparablePriority): Int { - other as Priority - - if (isDeprecated != other.isDeprecated) { - return if (isDeprecated) +1 else -1 - } - - val c1 = callExpressionWeigh.compareTo(other.callExpressionWeigh) - if (c1 != 0) { - // callExpressionWeigh is non-negative number - // Comparator contract says that if `a.compareTo(b)` returns -1 then `a` appears earlier than `b` - return -c1 - } - - val c2 = classification.compareTo(other.classification) - if (c2 != 0) return c2 - - val c3 = lastUseRecency.compareTo(other.lastUseRecency) - if (c3 != 0) return c3 - - val c4 = proximityWeight.compareTo(other.proximityWeight) - if (c4 != 0) return -c4 // n.b. reversed - - return if (compareNames) { - fqName.asString().compareTo(other.fqName.asString()) - } else { - 0 - } - } - } - - fun priority( - descriptor: DeclarationDescriptor, - languageVersionSettings: LanguageVersionSettings, - ) = Priority(descriptor, languageVersionSettings) + return ImportPrioritizer(file, isImportedByDefault, compareNames) } -private class DescriptorGroupPrioritizer(file: KtFile) { - private val prioritizer = Prioritizer(file, compareNames = false) +internal fun createDescriptorPriority( + prioritizer: ImportPrioritizer, + expressionWeigher: ExpressionWeigher, + descriptor: DeclarationDescriptor +): ImportPrioritizer.Priority { + val languageVersionSettings = prioritizer.file.languageVersionSettings - inner class Priority( - val descriptors: List, - languageVersionSettings: LanguageVersionSettings - ) : ComparablePriority { - val ownDescriptorsPriority = descriptors.maxOf { prioritizer.priority(it, languageVersionSettings) } - - override fun compareTo(other: ComparablePriority): Int { - other as Priority - - val c1 = ownDescriptorsPriority.compareTo(other.ownDescriptorsPriority) - if (c1 != 0) return c1 - - return other.descriptors.size - descriptors.size - } - } - - fun priority( - descriptors: List, - languageVersionSettings: LanguageVersionSettings - ) = Priority(descriptors, languageVersionSettings) + return prioritizer.Priority( + declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(prioritizer.file.project, descriptor), + statisticsInfo = KotlinStatisticsInfo.forDescriptor(descriptor), + isDeprecated = isDeprecatedAtCallSite(descriptor) { languageVersionSettings }, + fqName = descriptor.importableFqName ?: error("Unexpected null for fully-qualified name of importable declaration"), + expressionWeight = expressionWeigher.weigh(descriptor), + ) } +internal fun createDescriptorGroupPriority( + prioritizer: ImportPrioritizer, + expressionWeigher: ExpressionWeigher, + descriptors: List +): ImportPrioritizer.GroupPriority = + prioritizer.GroupPriority(descriptors.map { createDescriptorPriority(prioritizer, expressionWeigher, it) }) + internal abstract class AutoImportVariant( val descriptorsToImport: Collection, val excludeFqNameCheck: FqName, diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt index b056a2ffd173..42d4d5bd4f57 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt @@ -139,8 +139,8 @@ abstract class ImportFixBase protected constructor( suggestionDescriptors.mapTo(hashSetOf()) { it.original }.takeIf { it.isNotEmpty() } ?: return "" val ktFile = element?.containingKtFile ?: return KotlinBundle.message("fix.import") - val languageVersionSettings = ktFile.languageVersionSettings - val prioritizer = Prioritizer(ktFile, element) + val prioritizer = createPrioritizerForFile(ktFile) + val expressionWeigher = ExpressionWeigher.createWeigher(element) val importInfos = descriptors.mapNotNull { descriptor -> val kind = when { @@ -174,7 +174,9 @@ abstract class ImportFixBase protected constructor( append(it.asString()) } } - ImportFixHelper.ImportInfo(kind, name, prioritizer.priority(descriptor, languageVersionSettings)) + val priority = createDescriptorPriority(prioritizer, expressionWeigher, descriptor) + + ImportFixHelper.ImportInfo(kind, name, priority) } return ImportFixHelper.calculateTextForFix(importInfos, suggestions) } From f4accfef6bc2bb51e0246e833b4ecc32393f0669 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Mon, 15 May 2023 11:49:44 +0300 Subject: [PATCH 023/226] [kotlin k2] Import: fix import fix invocation in unit test mode ^KTIJ-23199 GitOrigin-RevId: a7ccaa27d3e075855f4e87d9a6dc82ffb8385b86 --- .../jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt index ec2e99c85906..05194739175b 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt @@ -146,7 +146,10 @@ class ImportQuickFix( } else -> { - if (ApplicationManager.getApplication().isUnitTestMode) return false + if (ApplicationManager.getApplication().isUnitTestMode) { + addImport(importCandidates.first().fqName) + return true + } createImportSelectorPopup().showInBestPositionFor(editor) return true From 5b30afe46460ccfb0c4c948b0ba671e91b53d123 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Mon, 15 May 2023 10:59:24 +0300 Subject: [PATCH 024/226] [kotlin k2] Import: improve quick fix description ^KTIJ-23199 Fixed GitOrigin-RevId: c8a3c2c5604e021e11dfb43b532aefe7208f0b1d --- .../idea/codeinsight/utils/AnalysisUtils.kt | 11 +- .../idea/quickfix/fixes/ImportQuickFix.kt | 113 +++++++++++++++--- ...ghLevelQuickFixMultiFileTestGenerated.java | 5 + .../QuickFixMultiFileTestGenerated.java | 5 + .../kotlinAddImportAction/ExtReceiver3.kt | 1 + .../ExtReceiver3.kt.after | 1 + .../MultipleMethodsAvailable.kt | 1 + .../MultipleMethodsAvailable.kt.after | 1 + ...sNamePreferWithImportsFromPackage.after.kt | 2 - ...referWithImportsFromPackage.before.Main.kt | 2 - .../quickfix/autoImports/classImport.after.kt | 3 +- .../autoImports/classImport.before.Main.kt | 3 +- .../constructorParameterAnnotation.test | 2 - ...ionFunctionImportImplicitReceiver.after.kt | 3 +- ...ctionImportImplicitReceiver.before.Main.kt | 3 +- .../functionPreferNotDeprecated.test | 43 +++++++ ...tAliasClassAlreadyExistsCollision.after.kt | 3 +- ...ClassAlreadyExistsCollision.before.Main.kt | 3 +- ...iasFunctionAlreadyExistsCollision.after.kt | 1 - ...ctionAlreadyExistsCollision.before.Main.kt | 1 - .../quickfix/autoImports/importClass.after.kt | 2 - .../autoImports/importClass.before.Main.kt | 2 - .../autoImports/importFromRoot.after.kt | 3 +- .../autoImports/importFromRoot.before.Main.kt | 3 +- ...tInFirstPartInQualifiedExpression.after.kt | 1 - ...stPartInQualifiedExpression.before.Main.kt | 1 - .../autoImports/importInterface.after.kt | 1 - .../importInterface.before.Main.kt | 1 - ...portNullableInterfaceWithGenerics.after.kt | 1 - ...llableInterfaceWithGenerics.before.Main.kt | 1 - .../autoImports/memberImportFunction.test | 2 - .../autoImports/memberImportProperty.test | 2 - .../memberWithTopLevelConflict.after.kt | 1 - .../memberWithTopLevelConflict.before.Main.kt | 1 - .../noFunctionImportOnSimpleName.test | 1 - ...ImportInQualifiedUserTypeNotFirst.after.kt | 3 +- ...InQualifiedUserTypeNotFirst.before.Main.kt | 1 - ...tsForClassInExcludedPackage.before.Main.kt | 3 +- .../noImportsForExcludedClass.before.Main.kt | 3 +- ...orFunctionInExcludedPackage.before.Main.kt | 3 +- .../noMemberFunctionImportOnSimpleName.test | 2 - .../autoImports/notExcludedClass.after.kt | 3 +- .../notExcludedClass.before.Main.kt | 3 +- .../autoImports/objectImport.after.kt | 3 +- .../autoImports/objectImport.before.Main.kt | 3 +- ...FunctionImportWhenReceiverPresent.after.kt | 1 - ...onImportWhenReceiverPresent.before.Main.kt | 1 - .../autoImports/propertyImport.after.kt | 1 - .../autoImports/propertyImport.before.Main.kt | 1 - .../sameModuleImportPriority.after.kt | 3 +- .../sameModuleImportPriority.before.Main.kt | 3 +- .../quickfix/autoImports/sealedClass.test | 2 - .../quickfix/autoImports/sealedClass2.test | 2 - 53 files changed, 181 insertions(+), 90 deletions(-) create mode 100644 plugins/kotlin/idea/tests/testData/quickfix/autoImports/functionPreferNotDeprecated.test diff --git a/plugins/kotlin/code-insight/utils/src/org/jetbrains/kotlin/idea/codeinsight/utils/AnalysisUtils.kt b/plugins/kotlin/code-insight/utils/src/org/jetbrains/kotlin/idea/codeinsight/utils/AnalysisUtils.kt index 3740a970cc6a..66e71c67660b 100644 --- a/plugins/kotlin/code-insight/utils/src/org/jetbrains/kotlin/idea/codeinsight/utils/AnalysisUtils.kt +++ b/plugins/kotlin/code-insight/utils/src/org/jetbrains/kotlin/idea/codeinsight/utils/AnalysisUtils.kt @@ -3,8 +3,9 @@ package org.jetbrains.kotlin.idea.codeinsight.utils import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol +import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClass import org.jetbrains.kotlin.util.OperatorNameConventions @@ -30,3 +31,11 @@ fun KtDeclaration.isFinalizeMethod(): Boolean { && function.valueParameters.isEmpty() && function.getReturnKtType().isUnit } + +context(KtAnalysisSession) +fun KtSymbol.getFqNameIfPackageOrNonLocal(): FqName? = when (this) { + is KtPackageSymbol -> fqName + is KtCallableSymbol -> callableIdIfNonLocal?.asSingleFqName() + is KtClassLikeSymbol -> classIdIfNonLocal?.asSingleFqName() + else -> null +} \ No newline at end of file diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt index 05194739175b..c9608d7fa8ee 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt @@ -8,6 +8,7 @@ import com.intellij.codeInsight.daemon.impl.ShowAutoImportPass import com.intellij.codeInsight.hint.HintManager import com.intellij.codeInsight.hint.QuestionAction import com.intellij.codeInspection.HintAction +import com.intellij.codeInspection.util.IntentionName import com.intellij.lang.jvm.JvmModifier import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor @@ -15,6 +16,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.psi.* +import com.intellij.psi.statistics.StatisticsInfo import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.parentsOfType import org.jetbrains.kotlin.analysis.api.KtAnalysisSession @@ -25,14 +27,22 @@ import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtDeclarationRend import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererVisibilityModifierProvider import org.jetbrains.kotlin.analysis.api.symbols.* +import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint import org.jetbrains.kotlin.idea.actions.KotlinAddImportActionInfo import org.jetbrains.kotlin.idea.base.analysis.api.utils.KtSymbolFromIndexProvider import org.jetbrains.kotlin.idea.base.psi.imports.addImport +import org.jetbrains.kotlin.idea.base.facet.platform.platform +import org.jetbrains.kotlin.idea.base.projectStructure.compositeAnalysis.findAnalyzerServices +import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.idea.base.utils.fqname.isImported import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.diagnosticFixFactory import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.QuickFixActionBase +import org.jetbrains.kotlin.idea.codeinsight.utils.getFqNameIfPackageOrNonLocal +import org.jetbrains.kotlin.idea.quickfix.ImportFixHelper +import org.jetbrains.kotlin.idea.quickfix.ImportPrioritizer import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName @@ -41,9 +51,11 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtPsiUtil.isSelectorInQualified import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability +import org.jetbrains.kotlin.resolve.ImportPath class ImportQuickFix( element: KtElement, + @IntentionName private val text: String, private val importCandidates: List ) : QuickFixActionBase(element), HintAction { data class ImportCandidate(val fqName: FqName, val renderedDeclaration: String) @@ -52,7 +64,7 @@ class ImportQuickFix( require(importCandidates.isNotEmpty()) } - override fun getText(): String = KotlinBundle.message("fix.import") + override fun getText(): String = text override fun getFamilyName(): String = KotlinBundle.message("fix.import") @@ -222,6 +234,83 @@ class ImportQuickFix( } } + context(KtAnalysisSession) + private fun createImportFix( + element: KtElement, + importCandidateSymbols: List, + ): ImportQuickFix? { + if (importCandidateSymbols.isEmpty()) return null + + val analyzerServices = element.containingKtFile.platform.findAnalyzerServices(element.project) + val defaultImports = analyzerServices.getDefaultImports(element.languageVersionSettings, includeLowPriorityImports = true) + val excludedImports = analyzerServices.excludedImports + + val isImported = { fqName: FqName -> ImportPath(fqName, isAllUnder = false).isImported(defaultImports, excludedImports) } + val importPrioritizer = ImportPrioritizer(element.containingKtFile, isImported) + + val sortedImportCandidateSymbolsWithPriorities = importCandidateSymbols + .map { it to createPriorityForImportableSymbol(importPrioritizer, it) } + .sortedBy { (_, priority) -> priority } + + val sortedImportInfos = sortedImportCandidateSymbolsWithPriorities.mapNotNull { (candidateSymbol, priority) -> + val kind = candidateSymbol.getImportKind() ?: return@mapNotNull null + val name = candidateSymbol.getImportName() + ImportFixHelper.ImportInfo(kind, name, priority) + } + + val text = ImportFixHelper.calculateTextForFix( + sortedImportInfos, + suggestions = sortedImportCandidateSymbolsWithPriorities.map { (symbol, _) -> symbol.getFqName() }.distinct() + ) + + val sortedImportCandidates = sortedImportCandidateSymbolsWithPriorities + .map { (symbol, _) -> ImportCandidate(symbol.getFqName(), renderSymbol(symbol)) } + + return ImportQuickFix(element, text, sortedImportCandidates) + } + + context(KtAnalysisSession) + private fun KtDeclarationSymbol.getImportKind(): ImportFixHelper.ImportKind? = when { + this is KtPropertySymbol && isExtension -> ImportFixHelper.ImportKind.EXTENSION_PROPERTY + this is KtPropertySymbol -> ImportFixHelper.ImportKind.PROPERTY + + this is KtFunctionSymbol && isOperator -> ImportFixHelper.ImportKind.OPERATOR + this is KtFunctionSymbol && isExtension -> ImportFixHelper.ImportKind.EXTENSION_FUNCTION + this is KtFunctionSymbol -> ImportFixHelper.ImportKind.FUNCTION + + this is KtNamedClassOrObjectSymbol && classKind.isObject -> ImportFixHelper.ImportKind.OBJECT + this is KtNamedClassOrObjectSymbol -> ImportFixHelper.ImportKind.CLASS + + else -> null + } + + context(KtAnalysisSession) + private fun KtDeclarationSymbol.getImportName(): String = buildString { + if (this@getImportName !is KtNamedSymbol) error("Unexpected anonymous declaration") + + if (this@getImportName is KtCallableSymbol) { + val classSymbol = if (receiverType != null) receiverType?.expandedClassSymbol else originalContainingClassForOverride + classSymbol?.name?.let { append(it.asString()) } + } + + if (this.isNotEmpty()) append('.') + append(name.asString()) + } + + context(KtAnalysisSession) + private fun KtDeclarationSymbol.getFqName(): FqName = + getFqNameIfPackageOrNonLocal() ?: error("Unexpected null for fully-qualified name of importable symbol") + + context(KtAnalysisSession) + private fun createPriorityForImportableSymbol(prioritizer: ImportPrioritizer, symbol: KtDeclarationSymbol): ImportPrioritizer.Priority = + prioritizer.Priority( + declaration = symbol.psi, + statisticsInfo = StatisticsInfo.EMPTY, + isDeprecated = symbol.deprecationStatus != null, + fqName = symbol.getFqName(), + expressionWeight = 0, + ) + fun KtAnalysisSession.createImportNameFix( indexProvider: KtSymbolFromIndexProvider, element: KtReferenceExpression, @@ -235,10 +324,7 @@ class ImportQuickFix( val callableCandidates = collectCallableCandidates(indexProvider, unresolvedName, isVisible) val typeCandidates = collectTypesCandidates(indexProvider, unresolvedName, isVisible) - val importCandidates = (callableCandidates + typeCandidates).distinct() - if (importCandidates.isEmpty()) return null - - return ImportQuickFix(element, importCandidates) + return createImportFix(element, callableCandidates + typeCandidates) } private fun KtAnalysisSession.createImportTypeFix( @@ -251,26 +337,20 @@ class ImportQuickFix( val isVisible: (KtNamedClassOrObjectSymbol) -> Boolean = { isVisible(it, firFile, null, element) } - val acceptableClasses = collectTypesCandidates(indexProvider, unresolvedName, isVisible).distinct() - if (acceptableClasses.isEmpty()) return null - - return ImportQuickFix(element, acceptableClasses) + return createImportFix(element, collectTypesCandidates(indexProvider, unresolvedName, isVisible)) } private fun KtAnalysisSession.collectCallableCandidates( indexProvider: KtSymbolFromIndexProvider, unresolvedName: Name, isVisible: (KtCallableSymbol) -> Boolean - ): List { + ): List { val callablesCandidates = indexProvider.getKotlinCallableSymbolsByName(unresolvedName) { it.canBeImported() } + indexProvider.getJavaCallableSymbolsByName(unresolvedName) { it.canBeImported() } return callablesCandidates - .filter(isVisible) - .mapNotNull { symbol -> - symbol.callableIdIfNonLocal?.asSingleFqName()?.let { ImportCandidate(it, renderSymbol(symbol)) } - } + .filter { isVisible(it) && it.callableIdIfNonLocal != null } .toList() } @@ -278,14 +358,13 @@ class ImportQuickFix( indexProvider: KtSymbolFromIndexProvider, unresolvedName: Name, isVisible: (KtNamedClassOrObjectSymbol) -> Boolean - ): List { + ): List { val classesCandidates = indexProvider.getKotlinClassesByName(unresolvedName) { it.canBeImported() } + indexProvider.getJavaClassesByName(unresolvedName) { it.canBeImported() } return classesCandidates - .filter(isVisible) - .mapNotNull { symbol -> symbol.classIdIfNonLocal?.asSingleFqName()?.let { ImportCandidate(it, renderSymbol(symbol)) } } + .filter { isVisible(it) && it.classIdIfNonLocal != null } .toList() } } diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiFileTestGenerated.java b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiFileTestGenerated.java index e074dee6c703..4e578d396106 100644 --- a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiFileTestGenerated.java +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiFileTestGenerated.java @@ -300,6 +300,11 @@ public abstract class HighLevelQuickFixMultiFileTestGenerated extends AbstractHi runTest("../idea/tests/testData/quickfix/autoImports/functionImport.before.Main.kt"); } + @TestMetadata("functionPreferNotDeprecated.test") + public void testFunctionPreferNotDeprecated() throws Exception { + runTest("../idea/tests/testData/quickfix/autoImports/functionPreferNotDeprecated.test"); + } + @TestMetadata("importAliasClassAlreadyExists.before.Main.kt") public void testImportAliasClassAlreadyExists() throws Exception { runTest("../idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Main.kt"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 18433ae6254c..cc35e8e72e85 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -390,6 +390,11 @@ public abstract class QuickFixMultiFileTestGenerated extends AbstractQuickFixMul runTest("testData/quickfix/autoImports/functionImport.before.Main.kt"); } + @TestMetadata("functionPreferNotDeprecated.test") + public void testFunctionPreferNotDeprecated() throws Exception { + runTest("testData/quickfix/autoImports/functionPreferNotDeprecated.test"); + } + @TestMetadata("importAliasClassAlreadyExists.before.Main.kt") public void testImportAliasClassAlreadyExists() throws Exception { runTest("testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Main.kt"); diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt index 59208f151718..85ff07aa6dc6 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun sec(s: kotlin.String): kotlin.Unit defined in p1 in file ExtReceiver3.dependency.kt" // EXPECT_VARIANT_IN_ORDER "public fun root.A.sec(s: kotlin.String): kotlin.Unit defined in p2 in file ExtReceiver3.dependency1.kt" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt.after index 384ce347b901..104e54098188 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver3.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun sec(s: kotlin.String): kotlin.Unit defined in p1 in file ExtReceiver3.dependency.kt" // EXPECT_VARIANT_IN_ORDER "public fun root.A.sec(s: kotlin.String): kotlin.Unit defined in p2 in file ExtReceiver3.dependency1.kt" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt index 98245183eff0..3fc116e2b9f1 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "public fun bar(): kotlin.Unit defined in root.q" // EXPECT_VARIANT_IN_ORDER "public fun bar(): kotlin.Unit defined in root.r" // EXPECT_VARIANT_IN_ORDER "public fun bar(): kotlin.Unit defined in root.p" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt.after index 5ffdcb5a5d87..ca825dd3ecd0 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "public fun bar(): kotlin.Unit defined in root.q" // EXPECT_VARIANT_IN_ORDER "public fun bar(): kotlin.Unit defined in root.r" // EXPECT_VARIANT_IN_ORDER "public fun bar(): kotlin.Unit defined in root.p" diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/ambiguousNamePreferWithImportsFromPackage.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/ambiguousNamePreferWithImportsFromPackage.after.kt index e6f857daed3d..523841b3ed80 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/ambiguousNamePreferWithImportsFromPackage.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/ambiguousNamePreferWithImportsFromPackage.after.kt @@ -6,5 +6,3 @@ import dependency2.YYY fun foo(x: XXX) { } - -/* IGNORE_FIR */ \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/ambiguousNamePreferWithImportsFromPackage.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/ambiguousNamePreferWithImportsFromPackage.before.Main.kt index 52b6fd2c350b..42ba0fad6edd 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/ambiguousNamePreferWithImportsFromPackage.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/ambiguousNamePreferWithImportsFromPackage.before.Main.kt @@ -5,5 +5,3 @@ import dependency2.YYY fun foo(x: XXX) { } - -/* IGNORE_FIR */ \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/classImport.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/classImport.after.kt index f0f615eee03f..a483957800e7 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/classImport.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/classImport.after.kt @@ -5,5 +5,4 @@ import TestData.TestSample fun test() { val a = TestSample -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/classImport.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/classImport.before.Main.kt index 9528aa3f9f20..51abdef165e6 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/classImport.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/classImport.before.Main.kt @@ -3,5 +3,4 @@ fun test() { val a = TestSample -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/constructorParameterAnnotation.test b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/constructorParameterAnnotation.test index e6043aa76df3..4c01c4f501d3 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/constructorParameterAnnotation.test +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/constructorParameterAnnotation.test @@ -1,7 +1,6 @@ // FILE: first.before.kt // "Import class 'SomeAnnotation'" "true" // ERROR: Unresolved reference: SomeAnnotation -/* IGNORE_FIR */ package some class X(@set:SomeAnnotation var field: Int) @@ -15,7 +14,6 @@ annotation class SomeAnnotation // FILE: first.after.kt // "Import class 'SomeAnnotation'" "true" // ERROR: Unresolved reference: SomeAnnotation -/* IGNORE_FIR */ package some import other.SomeAnnotation diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.after.kt index 3945e95d98ee..d11caaef8146 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.after.kt @@ -6,5 +6,4 @@ import testingExtensionFunctionsImport.data.someFun fun String.some() { someFun() -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.before.Main.kt index 2cc23f982b15..0e9f4a62e549 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.before.Main.kt @@ -4,5 +4,4 @@ package testingExtensionFunctionsImport fun String.some() { someFun() -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/functionPreferNotDeprecated.test b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/functionPreferNotDeprecated.test new file mode 100644 index 000000000000..6aadedcdcc5c --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/functionPreferNotDeprecated.test @@ -0,0 +1,43 @@ +// FILE: first.before.kt +// "Import function 'xxx'" "true" +// ERROR: Unresolved reference: xxx + +package testing + +fun test() { + xxx() +} +//----------------------- + + +// FILE: second.kt + +package dependency + +@Deprecated("Use xxx from other") +fun xxx() {} + +//----------------------- + + +// FILE: other_second.kt + +package other + +fun xxx() {} + +//----------------------- + + +// FILE: first.after.kt +// "Import function 'xxx'" "true" +// ERROR: Unresolved reference: xxx + +package testing + +import other.xxx + +fun test() { + xxx() +} +//----------------------- diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.after.kt index d2ffcf62d6a6..137245680fec 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.after.kt @@ -6,5 +6,4 @@ import editor.completion.apx.ImportedClass as Class2 fun context() { class Class2 val c: ImportedClass -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Main.kt index 70cb3b07d3c5..644169f32df5 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Main.kt @@ -5,5 +5,4 @@ import editor.completion.apx.ImportedClass as Class2 fun context() { class Class2 val c: ImportedClass -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.after.kt index dab33bdef515..b47058478f5f 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.after.kt @@ -1,6 +1,5 @@ // "Import function 'importedFunA'" "true" // ERROR: Unresolved reference: importedFunA -/* IGNORE_FIR */ import editor.completion.apx.importedFunA import editor.completion.apx.importedFunA as funA fun context() { diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Main.kt index 0212e7a1fe8a..da680408521c 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Main.kt @@ -1,6 +1,5 @@ // "Import function 'importedFunA'" "true" // ERROR: Unresolved reference: importedFunA -/* IGNORE_FIR */ import editor.completion.apx.importedFunA as funA fun context() { fun funA() {} diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importClass.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importClass.after.kt index bda2d67e1ee7..f89ecd2af762 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importClass.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importClass.after.kt @@ -9,5 +9,3 @@ import kotlinpackage.two.Some fun test() { var x by Some("OK") } - -/* IGNORE_FIR */ \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importClass.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importClass.before.Main.kt index f587d80740ef..88a430af27eb 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importClass.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importClass.before.Main.kt @@ -7,5 +7,3 @@ package kotlinpackage.one fun test() { var x by Some("OK") } - -/* IGNORE_FIR */ \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importFromRoot.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importFromRoot.after.kt index ad54086a7a55..a59247e18440 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importFromRoot.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importFromRoot.after.kt @@ -6,5 +6,4 @@ import RootClass fun test() { RootClass() -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importFromRoot.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importFromRoot.before.Main.kt index e1d39c86a0b2..baa32904479c 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importFromRoot.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importFromRoot.before.Main.kt @@ -4,5 +4,4 @@ package non.root.name fun test() { RootClass() -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.after.kt index 201e40cd8c57..83ed7ae9f037 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.after.kt @@ -8,4 +8,3 @@ import some.Some fun testing() { Some.test() } -/* IGNORE_FIR */ diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt index 12653c5c875c..90e5e6b1e0c9 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt @@ -6,4 +6,3 @@ package testing fun testing() { Some.test() } -/* IGNORE_FIR */ diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInterface.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInterface.after.kt index 3e07da20dd59..37c26e9fee22 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInterface.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInterface.after.kt @@ -6,4 +6,3 @@ import importInterface.data.TestInterface fun test() { val a = TestInterface } -/* IGNORE_FIR */ diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInterface.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInterface.before.Main.kt index df082bfb7de0..c5ce21f2a121 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInterface.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importInterface.before.Main.kt @@ -4,4 +4,3 @@ fun test() { val a = TestInterface } -/* IGNORE_FIR */ diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importNullableInterfaceWithGenerics.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importNullableInterfaceWithGenerics.after.kt index 1d69359da011..f31b54a26ede 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importNullableInterfaceWithGenerics.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importNullableInterfaceWithGenerics.after.kt @@ -6,4 +6,3 @@ import importInterface.data.TestInterface fun test() { val a: TestInterface? = null } -/* IGNORE_FIR */ diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importNullableInterfaceWithGenerics.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importNullableInterfaceWithGenerics.before.Main.kt index 796b5aa4aa23..e91dff81e028 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importNullableInterfaceWithGenerics.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/importNullableInterfaceWithGenerics.before.Main.kt @@ -4,4 +4,3 @@ fun test() { val a: TestInterface? = null } -/* IGNORE_FIR */ diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberImportFunction.test b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberImportFunction.test index db25ef440371..679eab461aa5 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberImportFunction.test +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberImportFunction.test @@ -1,7 +1,6 @@ // FILE: main.before.kt // "Import function 'Foo.foobar'" "true" // ERROR: Unresolved reference: foobar -/* IGNORE_FIR */ //KT-9009 package foo @@ -22,7 +21,6 @@ object Foo { // FILE: main.after.kt // "Import function 'Foo.foobar'" "true" // ERROR: Unresolved reference: foobar -/* IGNORE_FIR */ //KT-9009 package foo diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberImportProperty.test b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberImportProperty.test index 1f73530f9f76..455d1b6f8fd3 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberImportProperty.test +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberImportProperty.test @@ -1,7 +1,6 @@ // FILE: main.before.kt // "Import property 'Foo.foobar'" "true" // ERROR: Unresolved reference: foobar -/* IGNORE_FIR */ //KT-9009 package foo @@ -21,7 +20,6 @@ object Foo { // FILE: main.after.kt // "Import property 'Foo.foobar'" "true" // ERROR: Unresolved reference: foobar -/* IGNORE_FIR */ //KT-9009 package foo diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberWithTopLevelConflict.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberWithTopLevelConflict.after.kt index 9315b3d256e9..3189c45713de 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberWithTopLevelConflict.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberWithTopLevelConflict.after.kt @@ -4,7 +4,6 @@ import p1.sleep // WITH_STDLIB // FULL_JDK // ERROR: Unresolved reference: sleep -/* IGNORE_FIR */ fun usage() { sleep() diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberWithTopLevelConflict.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberWithTopLevelConflict.before.Main.kt index dfe751f4fcb7..628c22e4ecc7 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberWithTopLevelConflict.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/memberWithTopLevelConflict.before.Main.kt @@ -2,7 +2,6 @@ // WITH_STDLIB // FULL_JDK // ERROR: Unresolved reference: sleep -/* IGNORE_FIR */ fun usage() { sleep() diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noFunctionImportOnSimpleName.test b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noFunctionImportOnSimpleName.test index 307451b1d905..cfdbe7fa597e 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noFunctionImportOnSimpleName.test +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noFunctionImportOnSimpleName.test @@ -22,4 +22,3 @@ package bar fun foobar() { } -/* IGNORE_FIR */ diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.after.kt index dbeb9a919afc..2622c46bac5d 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.after.kt @@ -3,5 +3,4 @@ package testing -class Some: testing.SomeTest -/* IGNORE_FIR */ \ No newline at end of file +class Some: testing.SomeTest \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.Main.kt index c4f4014c3a37..7740c6cc414a 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.Main.kt @@ -6,4 +6,3 @@ package testing class Some: testing.SomeTest -/* IGNORE_FIR */ diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForClassInExcludedPackage.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForClassInExcludedPackage.before.Main.kt index af85ea7df9d5..603002ae7a57 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForClassInExcludedPackage.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForClassInExcludedPackage.before.Main.kt @@ -6,5 +6,4 @@ // ACTION: Rename reference // ERROR: Unresolved reference: SomeClass -val x = SomeClass() -/* IGNORE_FIR */ \ No newline at end of file +val x = SomeClass() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForExcludedClass.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForExcludedClass.before.Main.kt index 85327b2432a5..5389e3dba78e 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForExcludedClass.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForExcludedClass.before.Main.kt @@ -6,5 +6,4 @@ // ACTION: Rename reference // ERROR: Unresolved reference: ExcludedClass -val x = ExcludedClass() -/* IGNORE_FIR */ \ No newline at end of file +val x = ExcludedClass() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForFunctionInExcludedPackage.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForFunctionInExcludedPackage.before.Main.kt index dc89b13e1f32..688de4033ce6 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForFunctionInExcludedPackage.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noImportsForFunctionInExcludedPackage.before.Main.kt @@ -5,5 +5,4 @@ // ACTION: Rename reference // ERROR: Unresolved reference: someFunction -val x = someFunction() -/* IGNORE_FIR */ \ No newline at end of file +val x = someFunction() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noMemberFunctionImportOnSimpleName.test b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noMemberFunctionImportOnSimpleName.test index 0fca6abe9209..81ae6fb1bf31 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noMemberFunctionImportOnSimpleName.test +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/noMemberFunctionImportOnSimpleName.test @@ -23,5 +23,3 @@ object Foo { fun foobar() { } } - -/* IGNORE_FIR */ \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/notExcludedClass.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/notExcludedClass.after.kt index 9c1f0df537bd..305877a4ac15 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/notExcludedClass.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/notExcludedClass.after.kt @@ -3,5 +3,4 @@ import somePackage.NotExcludedClass // "Import class 'NotExcludedClass'" "true" // ERROR: Unresolved reference: NotExcludedClass -val x = NotExcludedClass() -/* IGNORE_FIR */ \ No newline at end of file +val x = NotExcludedClass() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/notExcludedClass.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/notExcludedClass.before.Main.kt index 299e69ddfad1..5b5dd94090ee 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/notExcludedClass.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/notExcludedClass.before.Main.kt @@ -1,5 +1,4 @@ // "Import class 'NotExcludedClass'" "true" // ERROR: Unresolved reference: NotExcludedClass -val x = NotExcludedClass() -/* IGNORE_FIR */ \ No newline at end of file +val x = NotExcludedClass() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectImport.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectImport.after.kt index c08d688f19b2..b57f595d0bf6 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectImport.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectImport.after.kt @@ -5,5 +5,4 @@ package ccc import bbb.TestObject -val x = TestObject -/* IGNORE_FIR */ \ No newline at end of file +val x = TestObject \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectImport.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectImport.before.Main.kt index 36404644e9c0..31f3baf1ce3c 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectImport.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectImport.before.Main.kt @@ -3,5 +3,4 @@ package ccc -val x = TestObject -/* IGNORE_FIR */ \ No newline at end of file +val x = TestObject \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectMemberFunctionImportWhenReceiverPresent.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectMemberFunctionImportWhenReceiverPresent.after.kt index 14b7a2cf88da..db935d0fd198 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectMemberFunctionImportWhenReceiverPresent.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectMemberFunctionImportWhenReceiverPresent.after.kt @@ -1,6 +1,5 @@ // "Import function 'Some.foobar'" "true" // ERROR: Unresolved reference: foobar -/* IGNORE_FIR */ package p2 import p1.Some.foobar diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectMemberFunctionImportWhenReceiverPresent.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectMemberFunctionImportWhenReceiverPresent.before.Main.kt index d48b13335a2c..3b45d8f5c226 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectMemberFunctionImportWhenReceiverPresent.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/objectMemberFunctionImportWhenReceiverPresent.before.Main.kt @@ -1,6 +1,5 @@ // "Import function 'Some.foobar'" "true" // ERROR: Unresolved reference: foobar -/* IGNORE_FIR */ package p2 class A { diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/propertyImport.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/propertyImport.after.kt index 71a748405ab3..1466be14f07a 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/propertyImport.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/propertyImport.after.kt @@ -1,6 +1,5 @@ // "Import property 'someTestProp'" "true" // ERROR: Unresolved reference: someTestProp -/* IGNORE_FIR */ package test import test.data.someTestProp diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/propertyImport.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/propertyImport.before.Main.kt index 6cc4bfb7bf76..3b6c2c90c886 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/propertyImport.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/propertyImport.before.Main.kt @@ -1,6 +1,5 @@ // "Import property 'someTestProp'" "true" // ERROR: Unresolved reference: someTestProp -/* IGNORE_FIR */ package test fun foo() { diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sameModuleImportPriority.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sameModuleImportPriority.after.kt index d2cca3a61f8b..647a8981ec51 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sameModuleImportPriority.after.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sameModuleImportPriority.after.kt @@ -7,5 +7,4 @@ import some.Delegates fun foo() { val d = Delegates() -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sameModuleImportPriority.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sameModuleImportPriority.before.Main.kt index 021e67e46abd..b606f3a67854 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sameModuleImportPriority.before.Main.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sameModuleImportPriority.before.Main.kt @@ -5,5 +5,4 @@ package testing fun foo() { val d = Delegates() -} -/* IGNORE_FIR */ \ No newline at end of file +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sealedClass.test b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sealedClass.test index 0187fe2ff0af..5075f118ac31 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sealedClass.test +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sealedClass.test @@ -1,7 +1,6 @@ // FILE: first.before.kt // "Import class 'ClassToImport'" "true" // ERROR: Unresolved reference: ClassToImport -/* IGNORE_FIR */ package testing @@ -24,7 +23,6 @@ sealed class ClassToImport // FILE: first.after.kt // "Import class 'ClassToImport'" "true" // ERROR: Unresolved reference: ClassToImport -/* IGNORE_FIR */ package testing diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sealedClass2.test b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sealedClass2.test index 45c99c0302dc..1084249a0cc9 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sealedClass2.test +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/sealedClass2.test @@ -1,7 +1,6 @@ // FILE: first.before.kt // "Import class 'Class2'" "true" // ERROR: Unresolved reference: Class2 -/* IGNORE_FIR */ package testing @@ -25,7 +24,6 @@ class Class2: ClassToImport() // FILE: first.after.kt // "Import class 'Class2'" "true" // ERROR: Unresolved reference: Class2 -/* IGNORE_FIR */ package testing From 1507f06b7175cc4c822e0b95bdea8a68c03b97f7 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Fri, 19 May 2023 15:31:38 +0300 Subject: [PATCH 025/226] [kotlin k2] Import: add `ExpressionImportWeigher` based on K1 implementation This expression weigher is required for sorting import suggestions based on their suitability KTIJ-25990 GitOrigin-RevId: ceecda0a9af1d29998afa50b232c043423200d95 --- .../idea/base/analysis/api/utils/typeUtils.kt | 37 +++ .../FirCallableCompletionContributor.kt | 3 +- .../factories/FunctionLookupElementFactory.kt | 1 + .../idea/completion/impl/k2/lookups/utils.kt | 35 +-- .../impl/k2/weighers/ExpectedTypeWeigher.kt | 2 +- .../quickfix/fixes/ExpressionImportWeigher.kt | 233 ++++++++++++++++++ .../idea/quickfix/fixes/ImportQuickFix.kt | 11 +- .../kotlin/idea/quickfix/ImportFixHelper.kt | 25 ++ .../kotlin/idea/actions/ExpressionWeigher.kt | 29 +-- .../K1AddImportActionTestGenerated.java | 5 + .../kotlinAddImportAction/ExtReceiver4.kt | 1 + .../ExtReceiver4.kt.after | 1 + .../MultipleMethodsAvailable2.kt | 1 + .../MultipleMethodsAvailable2.kt.after | 1 + .../VarargSpreadOperator.dependency1.kt | 3 + .../VarargSpreadOperator.dependency2.kt | 3 + .../VarargSpreadOperator.kt | 9 + .../VarargSpreadOperator.kt.after | 11 + 18 files changed, 348 insertions(+), 63 deletions(-) create mode 100644 plugins/kotlin/base/analysis-api/analysis-api-utils/src/org/jetbrains/kotlin/idea/base/analysis/api/utils/typeUtils.kt create mode 100644 plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ExpressionImportWeigher.kt create mode 100644 plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.dependency1.kt create mode 100644 plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.dependency2.kt create mode 100644 plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt create mode 100644 plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt.after diff --git a/plugins/kotlin/base/analysis-api/analysis-api-utils/src/org/jetbrains/kotlin/idea/base/analysis/api/utils/typeUtils.kt b/plugins/kotlin/base/analysis-api/analysis-api-utils/src/org/jetbrains/kotlin/idea/base/analysis/api/utils/typeUtils.kt new file mode 100644 index 000000000000..c94123686f0b --- /dev/null +++ b/plugins/kotlin/base/analysis-api/analysis-api-utils/src/org/jetbrains/kotlin/idea/base/analysis/api/utils/typeUtils.kt @@ -0,0 +1,37 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.base.analysis.api.utils + +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection +import org.jetbrains.kotlin.analysis.api.components.buildClassType +import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol +import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability +import org.jetbrains.kotlin.analysis.api.types.KtTypeParameterType + +/** + * Checks whether [this] is possibly a subtype of [superType] by replacing all type arguments in [superType] with star projections and + * checking subtyping relation between [this] and obtained type. For example, `MutableList>` is possibly a subtype of + * `List>`, because MutableList>` is a subtype of `List<*>`. + * + * This check only approximates the possibility of the subtyping relation. + * An accurate estimation requires the use of the constraint system, which can lead to a loss in performance. + */ +context(KtAnalysisSession) +infix fun KtType.isPossiblySubTypeOf(superType: KtType): Boolean { + if (this is KtTypeParameterType) return this.hasCommonSubTypeWith(superType) + + if (superType is KtTypeParameterType) return superType.symbol.upperBounds.all { this isPossiblySubTypeOf it } + + val superTypeWithReplacedTypeArguments = superType.expandedClassSymbol?.let { symbol -> + buildClassTypeWithStarProjections(symbol, superType.nullability) + } + return superTypeWithReplacedTypeArguments != null && this isSubTypeOf superTypeWithReplacedTypeArguments +} + +private fun KtAnalysisSession.buildClassTypeWithStarProjections(symbol: KtClassOrObjectSymbol, nullability: KtTypeNullability): KtType = + buildClassType(symbol) { + repeat(symbol.typeParameters.size) { + argument(KtStarTypeProjection(token)) + } + }.withNullability(nullability) \ No newline at end of file diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirCallableCompletionContributor.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirCallableCompletionContributor.kt index 63515c9e24fb..afb82f1afde8 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirCallableCompletionContributor.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirCallableCompletionContributor.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.analysis.api.types.KtFunctionalType import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.idea.base.analysis.api.utils.isPossiblySubTypeOf import org.jetbrains.kotlin.idea.base.fir.codeInsight.HLIndexHelper import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings import org.jetbrains.kotlin.idea.base.psi.isInsideAnnotationEntryArgumentList @@ -32,11 +33,9 @@ import org.jetbrains.kotlin.idea.completion.checkers.ExtensionApplicabilityCheck import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.context.FirNameReferencePositionContext import org.jetbrains.kotlin.idea.completion.contributors.helpers.* -import org.jetbrains.kotlin.idea.completion.contributors.helpers.ShadowedCallablesFilter import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionOptions import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionStrategy import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy -import org.jetbrains.kotlin.idea.completion.lookups.isPossiblySubTypeOf import org.jetbrains.kotlin.idea.completion.weighers.WeighingContext import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.psi.* diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/factories/FunctionLookupElementFactory.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/factories/FunctionLookupElementFactory.kt index 71ae7a5bb7bd..7d0158f25b18 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/factories/FunctionLookupElementFactory.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/factories/FunctionLookupElementFactory.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.analysis.api.signatures.KtFunctionLikeSignature import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.analysis.api.types.* +import org.jetbrains.kotlin.idea.base.analysis.api.utils.isPossiblySubTypeOf import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferencesInRange import org.jetbrains.kotlin.idea.base.analysis.withRootPrefixIfNeeded import org.jetbrains.kotlin.idea.completion.KotlinCompletionCharFilter diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/utils.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/utils.kt index 864ca60f136f..2c173c104635 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/utils.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/lookups/utils.kt @@ -12,15 +12,9 @@ import com.intellij.refactoring.suggested.endOffset import com.intellij.refactoring.suggested.startOffset import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection -import org.jetbrains.kotlin.analysis.api.components.buildClassType import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt import org.jetbrains.kotlin.analysis.api.signatures.KtCallableSignature -import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol -import org.jetbrains.kotlin.analysis.api.types.KtType -import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability -import org.jetbrains.kotlin.analysis.api.types.KtTypeParameterType import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferencesInRange import org.jetbrains.kotlin.idea.base.codeInsight.KotlinIconProvider.getIconFor import org.jetbrains.kotlin.idea.completion.contributors.helpers.insertString @@ -97,31 +91,4 @@ private fun KtSuperExpression.setSuperTypeQualifier( private fun getSuperTypeQualifierRange(typeReference: KtTypeReference): TextRange = TextRange( (typeReference.prevLeaf { it.elementType == KtTokens.LT } ?: typeReference).startOffset, (typeReference.nextLeaf { it.elementType == KtTokens.GT } ?: typeReference).endOffset -) - -/** - * Checks whether [this] is possibly a subtype of [superType] by replacing all type arguments in [superType] with star projections and - * checking subtyping relation between [this] and obtained type. For example, `MutableList>` is possibly a subtype of - * `List>`, because MutableList>` is a subtype of `List<*>`. - * - * This check only approximates the possibility of the subtyping relation. - * An accurate estimation requires the use of the constraint system, which can lead to a loss in performance. - */ -context(KtAnalysisSession) -internal infix fun KtType.isPossiblySubTypeOf(superType: KtType): Boolean { - if (this is KtTypeParameterType) return this.hasCommonSubTypeWith(superType) - - if (superType is KtTypeParameterType) return superType.symbol.upperBounds.all { this isPossiblySubTypeOf it } - - val superTypeWithReplacedTypeArguments = superType.expandedClassSymbol?.let { symbol -> - buildClassTypeWithStarProjections(symbol, superType.nullability) - } - return superTypeWithReplacedTypeArguments != null && this isSubTypeOf superTypeWithReplacedTypeArguments -} - -private fun KtAnalysisSession.buildClassTypeWithStarProjections(symbol: KtClassOrObjectSymbol, nullability: KtTypeNullability): KtType = - buildClassType(symbol) { - repeat(symbol.typeParameters.size) { - argument(KtStarTypeProjection(token)) - } - }.withNullability(nullability) \ No newline at end of file +) \ No newline at end of file diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/ExpectedTypeWeigher.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/ExpectedTypeWeigher.kt index e837a3da97db..4875e1c47eda 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/ExpectedTypeWeigher.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/weighers/ExpectedTypeWeigher.kt @@ -12,9 +12,9 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability +import org.jetbrains.kotlin.idea.base.analysis.api.utils.isPossiblySubTypeOf import org.jetbrains.kotlin.idea.completion.KeywordLookupObject import org.jetbrains.kotlin.idea.completion.impl.k2.lookups.factories.NamedArgumentLookupObject -import org.jetbrains.kotlin.idea.completion.lookups.isPossiblySubTypeOf import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.UserDataProperty diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ExpressionImportWeigher.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ExpressionImportWeigher.kt new file mode 100644 index 000000000000..270b51ca5009 --- /dev/null +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ExpressionImportWeigher.kt @@ -0,0 +1,233 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.quickfix.fixes + +import com.intellij.psi.PsiElement +import com.intellij.util.applyIf +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeOwner +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.symbols.* +import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability +import org.jetbrains.kotlin.idea.base.analysis.api.utils.isPossiblySubTypeOf +import org.jetbrains.kotlin.idea.codeinsight.utils.getFqNameIfPackageOrNonLocal +import org.jetbrains.kotlin.idea.quickfix.ImportFixHelper +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.types.expressions.OperatorConventions + +/** + * Implementation in K1: [org.jetbrains.kotlin.idea.actions.ExpressionWeigher] + */ +interface ExpressionImportWeigher { + context(KtAnalysisSession) + fun weigh(symbol: KtDeclarationSymbol): Int + + companion object { + context(KtAnalysisSession) + fun createWeigher(element: PsiElement?): ExpressionImportWeigher = + when (element) { + is KtNameReferenceExpression -> CallExpressionImportWeigher( + token, + calculateReceiverTypes(element), + calculateValueArgumentTypes(element), + ) + + is KtOperationReferenceExpression -> { + val operatorName = element.operationSignTokenType?.let { operationSignTokenType -> + OperatorConventions.getNameForOperationSymbol(operationSignTokenType, false, true) + } + + val parent = element.parent + if (parent is KtBinaryExpression) { + OperatorExpressionImportWeigher( + token, + operatorName, + parent.left?.getKtType(), + parent.right?.getKtType(), + ) + } else OperatorExpressionImportWeigher(token, operatorName) + } + + else -> Empty + } + + context(KtAnalysisSession) + private fun calculateReceiverTypes(element: KtNameReferenceExpression): List { + val receiverExpression = element.getParentOfType(false)?.receiverExpression + + return if (receiverExpression != null) { + val explicitType = receiverExpression.getKtType() + // use non-nullable type if safe call is used i.e `val value: T? = ...; value?.smth() + val correctedExplicitType = explicitType?.applyIf(receiverExpression.parent is KtSafeQualifiedExpression) { + withNullability(KtTypeNullability.NON_NULLABLE) + } + listOfNotNull(correctedExplicitType) + } else { + element.containingKtFile.getScopeContextForPosition(element).implicitReceivers.map { it.type } + } + } + + context(KtAnalysisSession) + private fun calculateValueArgumentTypes(element: KtNameReferenceExpression): List { + val callExpression = element.getParentOfType(strict = false) + val valueArgumentList = callExpression?.valueArgumentList ?: return emptyList() + + val valueArguments = valueArgumentList.arguments + return valueArguments.map { it.getArgumentExpression()?.getKtType() } + } + + object Empty : ExpressionImportWeigher { + context(KtAnalysisSession) + override fun weigh(symbol: KtDeclarationSymbol): Int = 0 + } + } +} + +internal abstract class AbstractExpressionImportWeigher : ExpressionImportWeigher { + context(KtAnalysisSession) + override fun weigh(symbol: KtDeclarationSymbol): Int { + val fqName = symbol.getFqNameIfPackageOrNonLocal() + val baseWeight = fqName?.let { ImportFixHelper.calculateWeightBasedOnFqName(it, symbol.sourcePsi()) } ?: 0 + + return baseWeight + ownWeigh(symbol) + } + + context(KtAnalysisSession) + protected abstract fun ownWeigh(symbol: KtDeclarationSymbol): Int + + context(KtAnalysisSession) + protected fun weighType(presentType: KtType, typeFromImport: KtType, baseWeight: Int): Int? { + val adjustedType: KtType + val nullablesWeight = if (presentType.nullability.isNullable == typeFromImport.nullability.isNullable) { + adjustedType = presentType + 2 + } else { + adjustedType = presentType.applyIf(presentType.nullability.isNullable) { withNullability(KtTypeNullability.NON_NULLABLE) } + // no reason to make `typeFromImport` not nullable as `T` is a subtype of `T?` + 0 + } + + return if (adjustedType.isPossiblySubTypeOf(typeFromImport)) { + 100 * baseWeight + 10 + nullablesWeight + } else { + null + } + } +} + +internal class CallExpressionImportWeigher( + override val token: KtLifetimeToken, + private val presentReceiverTypes: List, + private val valueArgumentTypes: List, +) : AbstractExpressionImportWeigher(), KtLifetimeOwner { + + context(KtAnalysisSession) + override fun ownWeigh(symbol: KtDeclarationSymbol): Int = withValidityAssertion { + when { + symbol is KtCallableSymbol -> calculateWeight(symbol, presentReceiverTypes, valueArgumentTypes) + // TODO: some constructors could be not visible + symbol is KtClassOrObjectSymbol && presentReceiverTypes.isEmpty() -> { + val constructors = symbol.getDeclaredMemberScope().getConstructors() + constructors.maxOfOrNull { calculateWeight(it, presentReceiverTypes = emptyList(), valueArgumentTypes) } ?: 0 + } + + else -> 0 + } + } + + context(KtAnalysisSession) + private fun calculateWeight( + symbolToBeImported: KtCallableSymbol, + presentReceiverTypes: List, + presentValueArgumentTypes: List, + ): Int { + var weight = 0 + + val receiverTypeFromImport = symbolToBeImported.receiverType + if (receiverTypeFromImport != null) { + weight = presentReceiverTypes.mapNotNull { weighType(it, receiverTypeFromImport, weight) }.maxOrNull() ?: weight + } + + if (symbolToBeImported is KtFunctionLikeSymbol) { + val symbolValueParameters = symbolToBeImported.valueParameters + val symbolHasVarargParameter = symbolValueParameters.any { it.isVararg } + weight += if (symbolValueParameters.size >= presentValueArgumentTypes.size || symbolHasVarargParameter) { + // same number of arguments is better than bigger number + if (symbolValueParameters.size == presentValueArgumentTypes.size || symbolHasVarargParameter) 1 else 0 + } else { + // apply only base weight if target has fewer parameters than expected + return weight + } + + // TODO: it does not cover the following cases: + // - named parameters + // - default value, e.g. `param: Int = ""` + // - functional types, e.g. `Int.() -> Unit` + // - functional references, e.g. `::foo` + + val valueParametersFromImportIterator = symbolValueParameters.iterator() + var valueParameterFromImport: KtValueParameterSymbol? = null + + // update weight each time argument type matches the type of parameter from import; break once a mismatch appears + for (valueArgumentType in presentValueArgumentTypes) { + if (!valueParametersFromImportIterator.hasNext() || valueArgumentType == null) { + break + } + // don't update current parameter from import if it's vararg + // TODO: cover the case with vararg argument followed by named arguments + if (valueParameterFromImport == null || !valueParameterFromImport.isVararg) { + valueParameterFromImport = valueParametersFromImportIterator.next() + } + val valueParameterType = valueParameterFromImport.returnType + + var updatedWeight = weighType(valueArgumentType, valueParameterType, weight) + + if (updatedWeight == null && valueParameterFromImport.isVararg && valueArgumentType.isArrayOrPrimitiveArray()) { + val arrayElementType = valueArgumentType.getArrayElementType() ?: break + updatedWeight = weighType(arrayElementType, valueParameterType, weight) + } + + weight = updatedWeight ?: break + } + } + return weight + } +} + +internal class OperatorExpressionImportWeigher( + override val token: KtLifetimeToken, + private val operatorName: Name?, + private val leftOperandType: KtType? = null, + private val rightOperandType: KtType? = null, +) : AbstractExpressionImportWeigher(), KtLifetimeOwner { + + context(KtAnalysisSession) + override fun weigh(symbol: KtDeclarationSymbol): Int { + val functionSymbol = (symbol as? KtFunctionSymbol)?.takeIf { it.isOperator } ?: return 0 + + return super.weigh(functionSymbol) + } + + context(KtAnalysisSession) + override fun ownWeigh(symbol: KtDeclarationSymbol): Int = withValidityAssertion { + symbol as KtFunctionSymbol + + val name = symbol.name + + var weight = 0 + if (name == operatorName) { + weight += 8 + } + if (leftOperandType != null) { + weight = symbol.receiverType?.let { weighType(leftOperandType, it, weight) } ?: weight + } + if (rightOperandType != null) { + weight = symbol.valueParameters.firstOrNull()?.returnType?.let { weighType(rightOperandType, it, weight) } ?: weight + } + + return weight + } +} \ No newline at end of file diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt index c9608d7fa8ee..ffb49bb8ff98 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt @@ -247,9 +247,10 @@ class ImportQuickFix( val isImported = { fqName: FqName -> ImportPath(fqName, isAllUnder = false).isImported(defaultImports, excludedImports) } val importPrioritizer = ImportPrioritizer(element.containingKtFile, isImported) + val expressionImportWeigher = ExpressionImportWeigher.createWeigher(element) val sortedImportCandidateSymbolsWithPriorities = importCandidateSymbols - .map { it to createPriorityForImportableSymbol(importPrioritizer, it) } + .map { it to createPriorityForImportableSymbol(importPrioritizer, expressionImportWeigher, it) } .sortedBy { (_, priority) -> priority } val sortedImportInfos = sortedImportCandidateSymbolsWithPriorities.mapNotNull { (candidateSymbol, priority) -> @@ -302,13 +303,17 @@ class ImportQuickFix( getFqNameIfPackageOrNonLocal() ?: error("Unexpected null for fully-qualified name of importable symbol") context(KtAnalysisSession) - private fun createPriorityForImportableSymbol(prioritizer: ImportPrioritizer, symbol: KtDeclarationSymbol): ImportPrioritizer.Priority = + private fun createPriorityForImportableSymbol( + prioritizer: ImportPrioritizer, + expressionImportWeigher: ExpressionImportWeigher, + symbol: KtDeclarationSymbol + ): ImportPrioritizer.Priority = prioritizer.Priority( declaration = symbol.psi, statisticsInfo = StatisticsInfo.EMPTY, isDeprecated = symbol.deprecationStatus != null, fqName = symbol.getFqName(), - expressionWeight = 0, + expressionWeight = expressionImportWeigher.weigh(symbol), ) fun KtAnalysisSession.createImportNameFix( diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt index dbe99a756c28..fe7700f7b4ad 100644 --- a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt @@ -2,6 +2,7 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.codeInspection.util.IntentionName +import com.intellij.openapi.roots.ProjectRootManager import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.parentOrNull @@ -75,4 +76,28 @@ object ImportFixHelper { KotlinBundle.message("fix.import") } } + + fun calculateWeightBasedOnFqName(fqName: FqName, sourceDeclaration: PsiElement?): Int { + val fqNameString = fqName.asString() + return when { + /** + * package rating calculation rule: + * - (highest) current project source + * - `kotlin.` and `kotlinx.` + * - `java.` + * - (lowest) all other 3rd party libs + */ + fqNameString.startsWith("kotlin.") -> 6 + fqNameString.startsWith("kotlinx.") -> 5 + fqNameString.startsWith("java.") -> 2 + sourceDeclaration != null -> { + val virtualFile = sourceDeclaration.containingFile?.virtualFile + val fileIndex = ProjectRootManager.getInstance(sourceDeclaration.project).fileIndex + // project source higher than libs + if (virtualFile != null && fileIndex.isInSourceContent(virtualFile)) 7 else 0 + } + + else -> 0 + } + } } \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/ExpressionWeigher.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/ExpressionWeigher.kt index 9db14e92a9f5..3751b0bddf3d 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/ExpressionWeigher.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/ExpressionWeigher.kt @@ -1,7 +1,6 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.actions -import com.intellij.openapi.roots.ProjectRootManager import com.intellij.psi.PsiElement import org.jetbrains.kotlin.backend.jvm.ir.psiElement import org.jetbrains.kotlin.descriptors.* @@ -11,6 +10,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.safeAnalyze import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.inspections.dfa.getArrayElementType import org.jetbrains.kotlin.idea.intentions.receiverType +import org.jetbrains.kotlin.idea.quickfix.ImportFixHelper import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfType @@ -24,6 +24,9 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections +/** + * Implementation in K2: [org.jetbrains.kotlin.idea.quickfix.fixes.ExpressionImportWeigher] + */ internal interface ExpressionWeigher { fun weigh(descriptor: DeclarationDescriptor): Int @@ -45,28 +48,8 @@ internal object EmptyExpressionWeigher: ExpressionWeigher { internal abstract class AbstractExpressionWeigher: ExpressionWeigher { override fun weigh(descriptor: DeclarationDescriptor): Int { - val base = descriptor.importableFqName?.asString()?.let { fqName -> - when { - /** - * package rating calculation rule: - * - (highest) current project source - * - `kotlin.` and `kotlinx.` - * - `java.` - * - (lowest) all other 3rd party libs - */ - fqName.startsWith("kotlin.") -> 6 - fqName.startsWith("kotlinx.") -> 5 - fqName.startsWith("java.") -> 2 - descriptor is DeclarationDescriptorWithSource -> run { - val psiElement = descriptor.psiElement - val virtualFile = psiElement?.containingFile?.virtualFile ?: return@run 0 - val fileIndex = ProjectRootManager.getInstance(psiElement.project).fileIndex - // project source higher than libs - if (fileIndex.isInSourceContent(virtualFile)) 7 else 0 - } - - else -> 0 - } + val base = descriptor.importableFqName?.let { fqName -> + ImportFixHelper.calculateWeightBasedOnFqName(fqName, (descriptor as? DeclarationDescriptorWithSource)?.psiElement) } ?: 0 return base + ownWeigh(descriptor) diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java index 5504bc42f8b9..fe41aa57114d 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java @@ -168,6 +168,11 @@ public class K1AddImportActionTestGenerated extends AbstractK1AddImportActionTes runTest("testData/idea/actions/kotlinAddImportAction/TypeAlias.kt"); } + @TestMetadata("VarargSpreadOperator.kt") + public void testVarargSpreadOperator() throws Exception { + runTest("testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt"); + } + @TestMetadata("Varargs.kt") public void testVarargs() throws Exception { runTest("testData/idea/actions/kotlinAddImportAction/Varargs.kt"); diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt index f8cf867dbb61..c1f2334771cb 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun kotlin.Int.sec(s: kotlin.String): kotlin.Unit defined in p2 in file ExtReceiver4.dependency1.kt" // EXPECT_VARIANT_IN_ORDER "public fun sec(s: kotlin.String): kotlin.Unit defined in p1 in file ExtReceiver4.dependency.kt" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt.after index 80876d736015..2455b1461628 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/ExtReceiver4.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON // WITH_STDLIB // EXPECT_VARIANT_IN_ORDER "public fun kotlin.Int.sec(s: kotlin.String): kotlin.Unit defined in p2 in file ExtReceiver4.dependency1.kt" // EXPECT_VARIANT_IN_ORDER "public fun sec(s: kotlin.String): kotlin.Unit defined in p1 in file ExtReceiver4.dependency.kt" diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt index 7ba5ed54fa6f..9dd81a4706d4 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "public fun ref(s: kotlin.String): kotlin.Unit defined in kotlinpackage.two.s2 in file MultipleMethodsAvailable2.dependency1.kt" // EXPECT_VARIANT_IN_ORDER "public fun ref(s: kotlin.Int): kotlin.Unit defined in kotlinpackage.two in file MultipleMethodsAvailable2.dependency.kt" package kotlinpackage.two.s1 diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt.after index 893607a97c0c..0148a7941d04 100644 --- a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt.after +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/MultipleMethodsAvailable2.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON // EXPECT_VARIANT_IN_ORDER "public fun ref(s: kotlin.String): kotlin.Unit defined in kotlinpackage.two.s2 in file MultipleMethodsAvailable2.dependency1.kt" // EXPECT_VARIANT_IN_ORDER "public fun ref(s: kotlin.Int): kotlin.Unit defined in kotlinpackage.two in file MultipleMethodsAvailable2.dependency.kt" package kotlinpackage.two.s1 diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.dependency1.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.dependency1.kt new file mode 100644 index 000000000000..5be394abaf5c --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.dependency1.kt @@ -0,0 +1,3 @@ +package pack1 + +fun foo(n: Int) {} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.dependency2.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.dependency2.kt new file mode 100644 index 000000000000..116c96e6f9cc --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.dependency2.kt @@ -0,0 +1,3 @@ +package pack2 + +fun foo(vararg n: Int) {} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt new file mode 100644 index 000000000000..ab67b89889ee --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt @@ -0,0 +1,9 @@ +// FIR_COMPARISON +// EXPECT_VARIANT_IN_ORDER "public fun foo(vararg n: kotlin.Int): kotlin.Unit defined in pack2 in file VarargSpreadOperator.dependency2.kt" +// EXPECT_VARIANT_IN_ORDER "public fun foo(n: kotlin.Int): kotlin.Unit defined in pack1 in file VarargSpreadOperator.dependency1.kt" +package root + +fun test() { + val a = intArrayOf(1, 1) + foo(*a) +} diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt.after new file mode 100644 index 000000000000..02ffe3005817 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/VarargSpreadOperator.kt.after @@ -0,0 +1,11 @@ +// FIR_COMPARISON +// EXPECT_VARIANT_IN_ORDER "public fun foo(vararg n: kotlin.Int): kotlin.Unit defined in pack2 in file VarargSpreadOperator.dependency2.kt" +// EXPECT_VARIANT_IN_ORDER "public fun foo(n: kotlin.Int): kotlin.Unit defined in pack1 in file VarargSpreadOperator.dependency1.kt" +package root + +import pack2.foo + +fun test() { + val a = intArrayOf(1, 1) + foo(*a) +} From f57c15afa94ab7779dae98e4b0a5f11076f7318e Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Thu, 22 Jun 2023 16:10:07 +0300 Subject: [PATCH 026/226] [kotlin k2] Import: prioritize elements which were used recently KTIJ-25990 GitOrigin-RevId: bde9e540b4f880be1e509ef3b70146fc46a5cf6a --- .../kotlin/idea/completion/Statisticians.kt | 3 ++ .../codeInsight/K2StatisticsInfoProvider.kt | 54 +++++++++++++++++++ .../idea/quickfix/fixes/ImportQuickFix.kt | 22 ++++---- .../K2AddImportActionTestGenerated.java | 5 ++ .../AbstractAddImportActionTestBase.kt | 24 +++++++-- .../K1AddImportActionTestGenerated.java | 5 ++ .../WithStatisticsInfo.dependency1.kt | 3 ++ .../WithStatisticsInfo.dependency2.kt | 3 ++ .../WithStatisticsInfo.kt | 9 ++++ .../WithStatisticsInfo.kt.after | 11 ++++ 10 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/codeInsight/K2StatisticsInfoProvider.kt create mode 100644 plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.dependency1.kt create mode 100644 plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.dependency2.kt create mode 100644 plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt create mode 100644 plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt.after diff --git a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/Statisticians.kt b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/Statisticians.kt index 511d319ab07d..e226c814e4f6 100644 --- a/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/Statisticians.kt +++ b/plugins/kotlin/completion/impl-k1/src/org/jetbrains/kotlin/idea/completion/Statisticians.kt @@ -43,6 +43,9 @@ class KotlinProximityStatistician : ProximityStatistician() { } } +/** + * Implementation in K2: [org.jetbrains.kotlin.idea.codeInsight.K2StatisticsInfoProvider] + */ object KotlinStatisticsInfo { private val SIGNATURE_RENDERER = DescriptorRenderer.withOptions { withDefinedIn = false diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/codeInsight/K2StatisticsInfoProvider.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/codeInsight/K2StatisticsInfoProvider.kt new file mode 100644 index 000000000000..ac843934e871 --- /dev/null +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/codeInsight/K2StatisticsInfoProvider.kt @@ -0,0 +1,54 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.codeInsight + +import com.intellij.psi.statistics.StatisticsInfo +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.renderer.base.KtKeywordsRenderer +import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnnotationsFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtCallableReturnTypeFilter +import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtDeclarationRenderer +import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource +import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.callables.KtCallableSignatureRenderer +import org.jetbrains.kotlin.analysis.api.symbols.* +import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter +import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint +import org.jetbrains.kotlin.lexer.KtKeywordToken + +/** + * Implementation in K1: [org.jetbrains.kotlin.idea.completion.KotlinStatisticsInfo] + */ +object K2StatisticsInfoProvider { + /** + * The renderer skips some features of a declaration to provide concise (but still unambiguous) description of the declaration. + */ + private val renderer = KtDeclarationRendererForSource.WITH_QUALIFIED_NAMES.with { + annotationRenderer = annotationRenderer.with { annotationFilter = KtRendererAnnotationsFilter.NONE } + modifiersRenderer = modifiersRenderer.with { keywordsRenderer = KtKeywordsRenderer.NONE } + + returnTypeFilter = object : KtCallableReturnTypeFilter { + context(KtAnalysisSession) + override fun shouldRenderReturnType(type: KtType, symbol: KtCallableSymbol): Boolean = symbol !is KtFunctionLikeSymbol + } + + callableSignatureRenderer = object : KtCallableSignatureRenderer { + context(KtAnalysisSession, KtDeclarationRenderer) + override fun renderCallableSignature(symbol: KtCallableSymbol, keyword: KtKeywordToken?, printer: PrettyPrinter) = + when (symbol) { + is KtValueParameterSymbol -> returnTypeRenderer.renderReturnType(symbol, printer) + else -> KtCallableSignatureRenderer.FOR_SOURCE.renderCallableSignature(symbol, keyword = null, printer) + } + } + } + + context(KtAnalysisSession) + fun forDeclarationSymbol(symbol: KtDeclarationSymbol, context: String = ""): StatisticsInfo = when (symbol) { + is KtClassLikeSymbol -> symbol.classIdIfNonLocal?.asFqNameString()?.let { StatisticsInfo(context, it) } + is KtCallableSymbol -> symbol.callableIdIfNonLocal?.let { callableId -> + val containerFqName = callableId.classId?.asFqNameString() ?: callableId.packageName + StatisticsInfo(context, "$containerFqName###${prettyPrint { renderer.renderDeclaration(symbol, this) }}") + } + + else -> null + } ?: StatisticsInfo.EMPTY +} diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt index ffb49bb8ff98..4985030f2ab3 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt @@ -17,6 +17,7 @@ import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.psi.* import com.intellij.psi.statistics.StatisticsInfo +import com.intellij.psi.statistics.StatisticsManager import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.parentsOfType import org.jetbrains.kotlin.analysis.api.KtAnalysisSession @@ -32,12 +33,13 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint import org.jetbrains.kotlin.idea.actions.KotlinAddImportActionInfo import org.jetbrains.kotlin.idea.base.analysis.api.utils.KtSymbolFromIndexProvider -import org.jetbrains.kotlin.idea.base.psi.imports.addImport import org.jetbrains.kotlin.idea.base.facet.platform.platform import org.jetbrains.kotlin.idea.base.projectStructure.compositeAnalysis.findAnalyzerServices import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings +import org.jetbrains.kotlin.idea.base.psi.imports.addImport import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.base.utils.fqname.isImported +import org.jetbrains.kotlin.idea.codeInsight.K2StatisticsInfoProvider import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.diagnosticFixFactory import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.QuickFixActionBase import org.jetbrains.kotlin.idea.codeinsight.utils.getFqNameIfPackageOrNonLocal @@ -58,7 +60,7 @@ class ImportQuickFix( @IntentionName private val text: String, private val importCandidates: List ) : QuickFixActionBase(element), HintAction { - data class ImportCandidate(val fqName: FqName, val renderedDeclaration: String) + data class ImportCandidate(val fqName: FqName, val renderedDeclaration: String, val statisticsInfo: StatisticsInfo) init { require(importCandidates.isNotEmpty()) @@ -149,7 +151,7 @@ class ImportQuickFix( KotlinAddImportActionInfo.executeListener?.onExecute(listOf(importCandidates.map { it.renderedDeclaration })) when (importCandidates.size) { 1 -> { - addImport(importCandidates.single().fqName) + addImport(importCandidates.single()) return true } @@ -159,7 +161,7 @@ class ImportQuickFix( else -> { if (ApplicationManager.getApplication().isUnitTestMode) { - addImport(importCandidates.first().fqName) + addImport(importCandidates.first()) return true } createImportSelectorPopup().showInBestPositionFor(editor) @@ -173,13 +175,15 @@ class ImportQuickFix( return JBPopupFactory.getInstance() .createPopupChooserBuilder(importCandidates) .setTitle(KotlinBundle.message("action.add.import.chooser.title")) - .setItemChosenCallback { selectedValue: ImportCandidate -> addImport(selectedValue.fqName) } + .setItemChosenCallback { selectedValue: ImportCandidate -> addImport(selectedValue) } .createPopup() } - private fun addImport(nameToImport: FqName) { + private fun addImport(importCandidate: ImportCandidate) { + StatisticsManager.getInstance().incUseCount(importCandidate.statisticsInfo) + project.executeWriteCommand(QuickFixBundle.message("add.import")) { - file.addImport(nameToImport) + file.addImport(importCandidate.fqName) } } } @@ -265,7 +269,7 @@ class ImportQuickFix( ) val sortedImportCandidates = sortedImportCandidateSymbolsWithPriorities - .map { (symbol, _) -> ImportCandidate(symbol.getFqName(), renderSymbol(symbol)) } + .map { (symbol, priority) -> ImportCandidate(symbol.getFqName(), renderSymbol(symbol), priority.statisticsInfo) } return ImportQuickFix(element, text, sortedImportCandidates) } @@ -310,7 +314,7 @@ class ImportQuickFix( ): ImportPrioritizer.Priority = prioritizer.Priority( declaration = symbol.psi, - statisticsInfo = StatisticsInfo.EMPTY, + statisticsInfo = K2StatisticsInfoProvider.forDeclarationSymbol(symbol), isDeprecated = symbol.deprecationStatus != null, fqName = symbol.getFqName(), expressionWeight = expressionImportWeigher.weigh(symbol), diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/K2AddImportActionTestGenerated.java b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/K2AddImportActionTestGenerated.java index 467c946e0b94..5a362a41465a 100644 --- a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/K2AddImportActionTestGenerated.java +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/actions/K2AddImportActionTestGenerated.java @@ -187,4 +187,9 @@ public class K2AddImportActionTestGenerated extends AbstractK2AddImportActionTes public void testVarargs3() throws Exception { runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/Varargs3.kt"); } + + @TestMetadata("WithStatisticsInfo.kt") + public void testWithStatisticsInfo() throws Exception { + runTest("../idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt"); + } } diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt index 1ef7fb8dea62..d623ccc9dc43 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt @@ -2,6 +2,9 @@ package org.jetbrains.kotlin.idea.actions import com.intellij.openapi.util.io.FileUtil +import com.intellij.psi.statistics.StatisticsInfo +import com.intellij.psi.statistics.StatisticsManager +import com.intellij.psi.statistics.impl.StatisticsManagerImpl import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import java.io.File @@ -34,13 +37,16 @@ abstract class AbstractAddImportActionTestBase : KotlinLightCodeInsightFixtureTe } KotlinAddImportActionInfo.setExecuteListener(testRootDisposable, executeListener) + (StatisticsManager.getInstance() as StatisticsManagerImpl).enableStatistics(myFixture.testRootDisposable) + increaseUseCountOf(InTextDirectivesUtils.findListWithPrefixes(fixture.file.text, INCREASE_USE_COUNT_DIRECTIVE)) + val importFix = myFixture.availableIntentions.singleOrNull { it.familyName == "Import" } ?: error("No import fix available") importFix.invoke(project, editor, file) assertNotNull(actualVariants) - val expectedVariantNames = InTextDirectivesUtils.findListWithPrefixes(fixture.file.text, "EXPECT_VARIANT_IN_ORDER") - val expectedAbsentVariantNames = InTextDirectivesUtils.findListWithPrefixes(fixture.file.text, "EXPECT_VARIANT_NOT_PRESENT") + val expectedVariantNames = InTextDirectivesUtils.findListWithPrefixes(fixture.file.text, EXPECT_VARIANT_IN_ORDER_DIRECTIVE) + val expectedAbsentVariantNames = InTextDirectivesUtils.findListWithPrefixes(fixture.file.text, EXPECT_VARIANT_NOT_PRESENT_DIRECTIVE) if (expectedVariantNames.isNotEmpty() || expectedAbsentVariantNames.isNotEmpty()) { val actualVariantNames = actualVariants!!.flatten() @@ -48,7 +54,7 @@ abstract class AbstractAddImportActionTestBase : KotlinLightCodeInsightFixtureTe for (i in expectedVariantNames.indices) { assertTrue( "mismatch at #$i: '${actualVariantNames[i]}' should start with '${expectedVariantNames[i]}'\nactual:\n${ - actualVariantNames.joinToString("\n") { "// EXPECT_VARIANT_IN_ORDER \"$it\"" } + actualVariantNames.joinToString("\n") { "// ${EXPECT_VARIANT_IN_ORDER_DIRECTIVE} \"$it\"" } }", actualVariantNames[i].contains(expectedVariantNames[i]) ) @@ -62,4 +68,16 @@ abstract class AbstractAddImportActionTestBase : KotlinLightCodeInsightFixtureTe myFixture.checkResultByFile("${fileName()}.after") } + + private fun increaseUseCountOf(statisticsInfoValues: List) { + statisticsInfoValues.forEach { value -> + StatisticsManager.getInstance().incUseCount(StatisticsInfo("", value)) + } + } + + companion object { + private const val EXPECT_VARIANT_IN_ORDER_DIRECTIVE: String = "EXPECT_VARIANT_IN_ORDER" + private const val EXPECT_VARIANT_NOT_PRESENT_DIRECTIVE: String = "EXPECT_VARIANT_NOT_PRESENT" + private const val INCREASE_USE_COUNT_DIRECTIVE: String = "INCREASE_USE_COUNT" + } } diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java index fe41aa57114d..84ddbe74b36d 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/K1AddImportActionTestGenerated.java @@ -187,4 +187,9 @@ public class K1AddImportActionTestGenerated extends AbstractK1AddImportActionTes public void testVarargs3() throws Exception { runTest("testData/idea/actions/kotlinAddImportAction/Varargs3.kt"); } + + @TestMetadata("WithStatisticsInfo.kt") + public void testWithStatisticsInfo() throws Exception { + runTest("testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt"); + } } diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.dependency1.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.dependency1.kt new file mode 100644 index 000000000000..738479bb8f70 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.dependency1.kt @@ -0,0 +1,3 @@ +package pack1 + +fun bar(n: Int) {} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.dependency2.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.dependency2.kt new file mode 100644 index 000000000000..d2b8a31dd4a8 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.dependency2.kt @@ -0,0 +1,3 @@ +package pack2 + +fun bar(n: Int) {} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt new file mode 100644 index 000000000000..c3b4ec5ba038 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt @@ -0,0 +1,9 @@ +// FIR_COMPARISON +// EXPECT_VARIANT_IN_ORDER "public fun bar(n: kotlin.Int): kotlin.Unit defined in pack2 in file WithStatisticsInfo.dependency2.kt" +// EXPECT_VARIANT_IN_ORDER "public fun bar(n: kotlin.Int): kotlin.Unit defined in pack1 in file WithStatisticsInfo.dependency1.kt" +// INCREASE_USE_COUNT pack2###bar(kotlin.Int) +package root + +fun test() { + bar(1) +} diff --git a/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt.after b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt.after new file mode 100644 index 000000000000..29c0093a24c8 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/idea/actions/kotlinAddImportAction/WithStatisticsInfo.kt.after @@ -0,0 +1,11 @@ +// FIR_COMPARISON +// EXPECT_VARIANT_IN_ORDER "public fun bar(n: kotlin.Int): kotlin.Unit defined in pack2 in file WithStatisticsInfo.dependency2.kt" +// EXPECT_VARIANT_IN_ORDER "public fun bar(n: kotlin.Int): kotlin.Unit defined in pack1 in file WithStatisticsInfo.dependency1.kt" +// INCREASE_USE_COUNT pack2###bar(kotlin.Int) +package root + +import pack2.bar + +fun test() { + bar(1) +} From 3bef8704f8dc1fec42ba11ac717761b58fbfde4e Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Mon, 26 Jun 2023 18:04:02 +0300 Subject: [PATCH 027/226] [kotlin k2] Import: move creation of import selector popup to frontend-independent module KTIJ-25990 GitOrigin-RevId: 904642a3870ae534e130dd335dba0fce4eeb2efe --- .../kotlin/idea/quickfix/AutoImportVariant.kt | 13 +++ .../kotlin/idea/quickfix/ImportFixHelper.kt | 78 +++++++++++++- .../idea/actions/KotlinAddImportAction.kt | 100 ++++-------------- 3 files changed, 110 insertions(+), 81 deletions(-) create mode 100644 plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AutoImportVariant.kt diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AutoImportVariant.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AutoImportVariant.kt new file mode 100644 index 000000000000..e4e9ce3e4595 --- /dev/null +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AutoImportVariant.kt @@ -0,0 +1,13 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.name.FqName +import javax.swing.Icon + +interface AutoImportVariant { + val hint: String + val icon: Icon? + val declarationToImport: PsiElement? + val fqName: FqName +} \ No newline at end of file diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt index fe7700f7b4ad..abb5b5abe1fd 100644 --- a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/ImportFixHelper.kt @@ -1,12 +1,23 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.quickfix +import com.intellij.codeInsight.daemon.impl.actions.AddImportAction import com.intellij.codeInspection.util.IntentionName +import com.intellij.ide.util.DefaultPsiElementCellRenderer +import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.ui.popup.JBPopupFactory +import com.intellij.openapi.ui.popup.ListPopup +import com.intellij.openapi.ui.popup.PopupStep +import com.intellij.openapi.ui.popup.util.BaseListPopupStep +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.parentOrNull +import java.awt.BorderLayout import java.util.* +import javax.swing.JPanel +import javax.swing.ListCellRenderer object ImportFixHelper { enum class ImportKind(private val key: String, val groupedByPackage: Boolean = false) { @@ -100,4 +111,69 @@ object ImportFixHelper { else -> 0 } } -} \ No newline at end of file + + fun createListPopupWithImportVariants( + project: Project, + variants: List, + addImport: (AutoImportVariant) -> Unit, + ): ListPopup = + JBPopupFactory.getInstance().createListPopup(project, getVariantSelectionPopup(project, variants, addImport)) { + val psiRenderer = DefaultPsiElementCellRenderer() + + ListCellRenderer { list, value, index, isSelected, cellHasFocus -> + JPanel(BorderLayout()).apply { + add( + psiRenderer.getListCellRendererComponent( + list, + value.declarationToImport, + index, + isSelected, + cellHasFocus + ) + ) + } + } + } + + private fun getVariantSelectionPopup( + project: Project, + variants: List, + addImport: (AutoImportVariant) -> Unit, + ): BaseListPopupStep { + return object : BaseListPopupStep(KotlinBundle.message("action.add.import.chooser.title"), variants) { + override fun isAutoSelectionEnabled(): Boolean = false + + override fun isSpeedSearchEnabled(): Boolean = true + + override fun onChosen(selectedValue: AutoImportVariant?, finalChoice: Boolean): PopupStep? { + if (selectedValue == null || project.isDisposed) return null + + if (finalChoice) { + addImport(selectedValue) + return null + } + + val toExclude = AddImportAction.getAllExcludableStrings(selectedValue.fqName.asString()) + + return object : BaseListPopupStep(null, toExclude) { + override fun getTextFor(value: String): String { + return KotlinBundle.message("fix.import.exclude", value) + } + + override fun onChosen(selectedValue: String, finalChoice: Boolean): PopupStep? { + if (finalChoice && !project.isDisposed) { + AddImportAction.excludeFromImport(project, selectedValue) + } + return null + } + } + } + + override fun hasSubstep(selectedValue: AutoImportVariant?) = true + override fun getTextFor(value: AutoImportVariant) = value.hint + override fun getIconFor(value: AutoImportVariant) = value.icon + } + } +} + + diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index 0005c023805f..3cbcca00ac4c 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -4,22 +4,14 @@ package org.jetbrains.kotlin.idea.actions import com.intellij.codeInsight.daemon.QuickFixBundle import com.intellij.codeInsight.daemon.impl.ShowAutoImportPass -import com.intellij.codeInsight.daemon.impl.actions.AddImportAction import com.intellij.codeInsight.hint.HintManager import com.intellij.codeInsight.hint.QuestionAction -import com.intellij.ide.util.DefaultPsiElementCellRenderer -import com.intellij.openapi.Disposable import com.intellij.openapi.application.runReadAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.popup.JBPopupFactory -import com.intellij.openapi.ui.popup.PopupStep -import com.intellij.openapi.ui.popup.util.BaseListPopupStep -import com.intellij.openapi.util.Disposer import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.statistics.StatisticsManager -import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PackageViewDescriptor @@ -32,7 +24,9 @@ import org.jetbrains.kotlin.idea.completion.KotlinStatisticsInfo import org.jetbrains.kotlin.idea.completion.isDeprecatedAtCallSite import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress import org.jetbrains.kotlin.idea.imports.importableFqName +import org.jetbrains.kotlin.idea.quickfix.AutoImportVariant import org.jetbrains.kotlin.idea.quickfix.ImportComparablePriority +import org.jetbrains.kotlin.idea.quickfix.ImportFixHelper import org.jetbrains.kotlin.idea.quickfix.ImportPrioritizer import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode import org.jetbrains.kotlin.idea.references.mainReference @@ -52,10 +46,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull -import java.awt.BorderLayout import javax.swing.Icon -import javax.swing.JPanel -import javax.swing.ListCellRenderer internal fun createSingleImportAction( project: Project, @@ -146,9 +137,9 @@ class KotlinAddImportAction internal constructor( private val element: KtElement, private val variants: Sequence ) : QuestionAction { - private var singleImportVariant: AutoImportVariant? = null + private var singleImportVariant: DescriptorBasedAutoImportVariant? = null - private fun variantsList(): List { + private fun variantsList(): List { if (singleImportVariant != null && !isUnitTestMode()) return listOf(singleImportVariant!!) val variantsList = { @@ -199,64 +190,14 @@ class KotlinAddImportAction internal constructor( return true } - JBPopupFactory.getInstance().createListPopup(project, getVariantSelectionPopup(variantsList)) { - val psiRenderer = DefaultPsiElementCellRenderer() - - ListCellRenderer { list, value, index, isSelected, cellHasFocus -> - JPanel(BorderLayout()).apply { - add( - psiRenderer.getListCellRendererComponent( - list, - value.declarationToImport, - index, - isSelected, - cellHasFocus - ) - ) - } - } - }.showInBestPositionFor(editor) + ImportFixHelper.createListPopupWithImportVariants(project, variantsList, ::addImport).showInBestPositionFor(editor) return true } - private fun getVariantSelectionPopup(variants: List): BaseListPopupStep { - return object : BaseListPopupStep(KotlinBundle.message("action.add.import.chooser.title"), variants) { - override fun isAutoSelectionEnabled() = false - - override fun isSpeedSearchEnabled() = true - - override fun onChosen(selectedValue: AutoImportVariant?, finalChoice: Boolean): PopupStep? { - if (selectedValue == null || project.isDisposed) return null - - if (finalChoice) { - addImport(selectedValue) - return null - } - - val toExclude = AddImportAction.getAllExcludableStrings(selectedValue.excludeFqNameCheck.asString()) - - return object : BaseListPopupStep(null, toExclude) { - override fun getTextFor(value: String): String { - return KotlinBundle.message("fix.import.exclude", value) - } - - override fun onChosen(selectedValue: String, finalChoice: Boolean): PopupStep? { - if (finalChoice && !project.isDisposed) { - AddImportAction.excludeFromImport(project, selectedValue) - } - return null - } - } - } - - override fun hasSubstep(selectedValue: AutoImportVariant?) = true - override fun getTextFor(value: AutoImportVariant) = value.hint - override fun getIconFor(value: AutoImportVariant) = value.icon - } - } - private fun addImport(variant: AutoImportVariant) { + require(variant is DescriptorBasedAutoImportVariant) + val psiDocumentManager = PsiDocumentManager.getInstance(project) psiDocumentManager.commitAllDocuments() @@ -318,7 +259,7 @@ class KotlinAddImportAction internal constructor( } } -internal data class VariantWithPriority(val variant: AutoImportVariant, val priority: ImportComparablePriority) +internal data class VariantWithPriority(val variant: DescriptorBasedAutoImportVariant, val priority: ImportComparablePriority) internal fun createPrioritizerForFile(file: KtFile, compareNames: Boolean = true): ImportPrioritizer { val isImportedByDefault = { fqName: FqName -> @@ -350,40 +291,39 @@ internal fun createDescriptorGroupPriority( ): ImportPrioritizer.GroupPriority = prioritizer.GroupPriority(descriptors.map { createDescriptorPriority(prioritizer, expressionWeigher, it) }) -internal abstract class AutoImportVariant( +internal abstract class DescriptorBasedAutoImportVariant( val descriptorsToImport: Collection, - val excludeFqNameCheck: FqName, + override val fqName: FqName, project: Project, -) { - abstract val hint: String - val declarationToImport: PsiElement? = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptorsToImport.first()) - val icon: Icon? = KotlinDescriptorIconProvider.getIcon(descriptorsToImport.first(), declarationToImport, 0) +): AutoImportVariant { + override val declarationToImport: PsiElement? = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptorsToImport.first()) + override val icon: Icon? = KotlinDescriptorIconProvider.getIcon(descriptorsToImport.first(), declarationToImport, 0) } private class GroupedImportVariant( val autoImportDescription: String, descriptors: Collection, project: Project -) : AutoImportVariant( +) : DescriptorBasedAutoImportVariant( descriptorsToImport = descriptors, - excludeFqNameCheck = descriptors.first().importableFqName!!.parent(), + fqName = descriptors.first().importableFqName!!.parent(), project = project, ) { - override val hint: String get() = KotlinBundle.message("0.from.1", autoImportDescription, excludeFqNameCheck) + override val hint: String get() = KotlinBundle.message("0.from.1", autoImportDescription, fqName) } private class SingleImportVariant( - excludeFqNameCheck: FqName, + fqName: FqName, descriptors: Collection, project: Project -) : AutoImportVariant( +) : DescriptorBasedAutoImportVariant( descriptorsToImport = listOf( descriptors.singleOrNull() ?: descriptors.minByOrNull { if (it is ClassDescriptor) 0 else 1 } ?: error("we create the class with not-empty descriptors always") ), - excludeFqNameCheck = excludeFqNameCheck, + fqName = fqName, project = project, ) { - override val hint: String get() = excludeFqNameCheck.asString() + override val hint: String get() = fqName.asString() } \ No newline at end of file From b88db662790e2d3ef21c7fd5c15b6bbdf6467595 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Tue, 27 Jun 2023 11:06:45 +0300 Subject: [PATCH 028/226] [kotlin k2] Import: use selector popup from K1 in K2 KTIJ-25990 GitOrigin-RevId: 8dd1526b23c8bd8a2cea30f999ad931045ffce9b --- .../idea/quickfix/fixes/ImportQuickFix.kt | 67 +++++++++++-------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt index 4985030f2ab3..d0d4a752105b 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt @@ -13,8 +13,6 @@ import com.intellij.lang.jvm.JvmModifier import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.popup.JBPopup -import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.psi.* import com.intellij.psi.statistics.StatisticsInfo import com.intellij.psi.statistics.StatisticsManager @@ -33,6 +31,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint import org.jetbrains.kotlin.idea.actions.KotlinAddImportActionInfo import org.jetbrains.kotlin.idea.base.analysis.api.utils.KtSymbolFromIndexProvider +import org.jetbrains.kotlin.idea.base.codeInsight.KotlinIconProvider.getIconFor import org.jetbrains.kotlin.idea.base.facet.platform.platform import org.jetbrains.kotlin.idea.base.projectStructure.compositeAnalysis.findAnalyzerServices import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings @@ -43,6 +42,7 @@ import org.jetbrains.kotlin.idea.codeInsight.K2StatisticsInfoProvider import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.diagnosticFixFactory import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.QuickFixActionBase import org.jetbrains.kotlin.idea.codeinsight.utils.getFqNameIfPackageOrNonLocal +import org.jetbrains.kotlin.idea.quickfix.AutoImportVariant import org.jetbrains.kotlin.idea.quickfix.ImportFixHelper import org.jetbrains.kotlin.idea.quickfix.ImportPrioritizer import org.jetbrains.kotlin.idea.util.application.executeWriteCommand @@ -54,16 +54,25 @@ import org.jetbrains.kotlin.psi.KtPsiUtil.isSelectorInQualified import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability import org.jetbrains.kotlin.resolve.ImportPath +import javax.swing.Icon class ImportQuickFix( element: KtElement, @IntentionName private val text: String, - private val importCandidates: List + private val importVariants: List ) : QuickFixActionBase(element), HintAction { - data class ImportCandidate(val fqName: FqName, val renderedDeclaration: String, val statisticsInfo: StatisticsInfo) + private data class SymbolBasedAutoImportVariant( + override val fqName: FqName, + override val declarationToImport: PsiElement?, + override val icon: Icon?, + val renderedDeclaration: String, + val statisticsInfo: StatisticsInfo + ) : AutoImportVariant { + override val hint: String = renderedDeclaration // TODO: fix after changing tests + } init { - require(importCandidates.isNotEmpty()) + require(importVariants.isNotEmpty()) } override fun getText(): String = text @@ -77,7 +86,7 @@ class ImportQuickFix( } private fun createAddImportAction(project: Project, editor: Editor, file: KtFile): QuestionAction { - return ImportQuestionAction(project, editor, file, importCandidates) + return ImportQuestionAction(project, editor, file, importVariants) } override fun showHint(editor: Editor): Boolean { @@ -93,7 +102,7 @@ class ImportQuickFix( val project = file.project val elementRange = element.textRange - val autoImportHintText = KotlinBundle.message("fix.import.question", importCandidates.first().fqName.asString()) + val autoImportHintText = KotlinBundle.message("fix.import.question", importVariants.first().fqName.asString()) HintManager.getInstance().showQuestionHint( editor, @@ -113,7 +122,7 @@ class ImportQuickFix( if (!ShowAutoImportPass.isAddUnambiguousImportsOnTheFlyEnabled(file)) return false val project = file.project val addImportAction = createAddImportAction(project, editor, file) - if (importCandidates.size == 1) { + if (importVariants.size == 1) { addImportAction.execute() return true } else { @@ -140,18 +149,18 @@ class ImportQuickFix( private val project: Project, private val editor: Editor, private val file: KtFile, - private val importCandidates: List + private val importVariants: List ) : QuestionAction { init { - require(importCandidates.isNotEmpty()) + require(importVariants.isNotEmpty()) } override fun execute(): Boolean { - KotlinAddImportActionInfo.executeListener?.onExecute(listOf(importCandidates.map { it.renderedDeclaration })) - when (importCandidates.size) { + KotlinAddImportActionInfo.executeListener?.onExecute(listOf(importVariants.map { it.hint })) + when (importVariants.size) { 1 -> { - addImport(importCandidates.single()) + addImport(importVariants.single()) return true } @@ -161,29 +170,23 @@ class ImportQuickFix( else -> { if (ApplicationManager.getApplication().isUnitTestMode) { - addImport(importCandidates.first()) + addImport(importVariants.first()) return true } - createImportSelectorPopup().showInBestPositionFor(editor) + ImportFixHelper.createListPopupWithImportVariants(project, importVariants, ::addImport).showInBestPositionFor(editor) return true } } } - private fun createImportSelectorPopup(): JBPopup { - return JBPopupFactory.getInstance() - .createPopupChooserBuilder(importCandidates) - .setTitle(KotlinBundle.message("action.add.import.chooser.title")) - .setItemChosenCallback { selectedValue: ImportCandidate -> addImport(selectedValue) } - .createPopup() - } + private fun addImport(importVariant: AutoImportVariant) { + require(importVariant is SymbolBasedAutoImportVariant) - private fun addImport(importCandidate: ImportCandidate) { - StatisticsManager.getInstance().incUseCount(importCandidate.statisticsInfo) + StatisticsManager.getInstance().incUseCount(importVariant.statisticsInfo) project.executeWriteCommand(QuickFixBundle.message("add.import")) { - file.addImport(importCandidate.fqName) + file.addImport(importVariant.fqName) } } } @@ -268,10 +271,18 @@ class ImportQuickFix( suggestions = sortedImportCandidateSymbolsWithPriorities.map { (symbol, _) -> symbol.getFqName() }.distinct() ) - val sortedImportCandidates = sortedImportCandidateSymbolsWithPriorities - .map { (symbol, priority) -> ImportCandidate(symbol.getFqName(), renderSymbol(symbol), priority.statisticsInfo) } + val sortedImportVariants = sortedImportCandidateSymbolsWithPriorities + .map { (symbol, priority) -> + SymbolBasedAutoImportVariant( + symbol.getFqName(), + symbol.psi, + getIconFor(symbol), + renderSymbol(symbol), + priority.statisticsInfo, + ) + } - return ImportQuickFix(element, text, sortedImportCandidates) + return ImportQuickFix(element, text, sortedImportVariants) } context(KtAnalysisSession) From 036868c300ceb990fd67dc1c79b29e394723de45 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Tue, 27 Jun 2023 11:31:01 +0300 Subject: [PATCH 029/226] [kotlin k2] Import: refactor `AbstractAddImportActionTestBase` Introduce property `debugRepresentation` and use `AutoImportVariant` in tests directly ^KTIJ-25990 Fixed GitOrigin-RevId: 2805d79c4b50975fac068828df93b5aa10875084 --- .../idea/quickfix/fixes/ImportQuickFix.kt | 6 +-- .../idea/actions/KotlinAddImportActionInfo.kt | 3 +- .../kotlin/idea/quickfix/AutoImportVariant.kt | 2 + .../idea/actions/KotlinAddImportAction.kt | 37 ++++++++++--------- .../AbstractAddImportActionTestBase.kt | 7 ++-- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt index d0d4a752105b..77bbdd765353 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt @@ -65,10 +65,10 @@ class ImportQuickFix( override val fqName: FqName, override val declarationToImport: PsiElement?, override val icon: Icon?, - val renderedDeclaration: String, + override val debugRepresentation: String, val statisticsInfo: StatisticsInfo ) : AutoImportVariant { - override val hint: String = renderedDeclaration // TODO: fix after changing tests + override val hint: String = fqName.asString() } init { @@ -157,7 +157,7 @@ class ImportQuickFix( } override fun execute(): Boolean { - KotlinAddImportActionInfo.executeListener?.onExecute(listOf(importVariants.map { it.hint })) + KotlinAddImportActionInfo.executeListener?.onExecute(importVariants) when (importVariants.size) { 1 -> { addImport(importVariants.single()) diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionInfo.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionInfo.kt index ac58b81e7381..45e0c3e8b111 100644 --- a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionInfo.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportActionInfo.kt @@ -4,11 +4,12 @@ package org.jetbrains.kotlin.idea.actions import com.intellij.openapi.Disposable import com.intellij.openapi.util.Disposer import org.jetbrains.annotations.TestOnly +import org.jetbrains.kotlin.idea.quickfix.AutoImportVariant /** Test hooks allowing inspection of data used for KotlinAddImportAction. **/ object KotlinAddImportActionInfo { interface ExecuteListener { - fun onExecute(variants: List>) + fun onExecute(variants: List) } @Volatile diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AutoImportVariant.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AutoImportVariant.kt index e4e9ce3e4595..a9887ea2a6be 100644 --- a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AutoImportVariant.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AutoImportVariant.kt @@ -10,4 +10,6 @@ interface AutoImportVariant { val icon: Icon? val declarationToImport: PsiElement? val fqName: FqName + + val debugRepresentation: String } \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index 3cbcca00ac4c..17ff8cdff859 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -179,9 +179,7 @@ class KotlinAddImportAction internal constructor( if (!element.isValid) return false val variantsList = variantsList() - KotlinAddImportActionInfo.executeListener?.onExecute(variantsList.map { - it.descriptorsToImport.map { descriptorToImport -> descriptorToImport.variantNameForDebug() }.toList() - }) + KotlinAddImportActionInfo.executeListener?.onExecute(variantsList) if (variantsList.isEmpty()) return false @@ -243,20 +241,6 @@ class KotlinAddImportAction internal constructor( } } } - - companion object { - private val debugRenderer = DescriptorRenderer.DEBUG_TEXT.withOptions { - annotationFilter = { false } - } - - private fun DeclarationDescriptor.variantNameForDebug() = when (this) { - is ClassDescriptor -> - fqNameOrNull()?.toString()?.let { "class $it" } ?: debugRenderer.render(this) - - else -> - debugRenderer.render(this) - } - } } internal data class VariantWithPriority(val variant: DescriptorBasedAutoImportVariant, val priority: ImportComparablePriority) @@ -295,9 +279,26 @@ internal abstract class DescriptorBasedAutoImportVariant( val descriptorsToImport: Collection, override val fqName: FqName, project: Project, -): AutoImportVariant { +) : AutoImportVariant { override val declarationToImport: PsiElement? = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptorsToImport.first()) override val icon: Icon? = KotlinDescriptorIconProvider.getIcon(descriptorsToImport.first(), declarationToImport, 0) + + override val debugRepresentation: String + get() = descriptorsToImport.first().variantNameForDebug() + + companion object { + private val debugRenderer = DescriptorRenderer.DEBUG_TEXT.withOptions { + annotationFilter = { false } + } + + private fun DeclarationDescriptor.variantNameForDebug() = when (this) { + is ClassDescriptor -> + fqNameOrNull()?.toString()?.let { "class $it" } ?: debugRenderer.render(this) + + else -> + debugRenderer.render(this) + } + } } private class GroupedImportVariant( diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt index d623ccc9dc43..20a000dfb85e 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/actions/AbstractAddImportActionTestBase.kt @@ -5,6 +5,7 @@ import com.intellij.openapi.util.io.FileUtil import com.intellij.psi.statistics.StatisticsInfo import com.intellij.psi.statistics.StatisticsManager import com.intellij.psi.statistics.impl.StatisticsManagerImpl +import org.jetbrains.kotlin.idea.quickfix.AutoImportVariant import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import java.io.File @@ -28,9 +29,9 @@ abstract class AbstractAddImportActionTestBase : KotlinLightCodeInsightFixtureTe fixture.configureByFile(fileName()) - var actualVariants: List>? = null + var actualVariants: List? = null val executeListener = object : KotlinAddImportActionInfo.ExecuteListener { - override fun onExecute(variants: List>) { + override fun onExecute(variants: List) { assertNull(actualVariants) actualVariants = variants } @@ -49,7 +50,7 @@ abstract class AbstractAddImportActionTestBase : KotlinLightCodeInsightFixtureTe val expectedAbsentVariantNames = InTextDirectivesUtils.findListWithPrefixes(fixture.file.text, EXPECT_VARIANT_NOT_PRESENT_DIRECTIVE) if (expectedVariantNames.isNotEmpty() || expectedAbsentVariantNames.isNotEmpty()) { - val actualVariantNames = actualVariants!!.flatten() + val actualVariantNames = actualVariants.orEmpty().map { it.debugRepresentation } for (i in expectedVariantNames.indices) { assertTrue( From 87dc922c90f2b4089acc8f29ae543537d3447c5e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 28 Jun 2023 13:14:35 +0200 Subject: [PATCH 030/226] [kotlin] k2: add tests to ensure that no decompilation happens during resolve in references in signatures ^ KTIJ-25979 GitOrigin-RevId: 3e3ae5cc5a1f5478c5f22f74fc01997dd8ee1468 --- ...stractFirInLibraryResolveEverythingTest.kt | 60 +++++++++++++++++++ ...LibraryResolveEverythingTestGenerated.java | 30 ++++++++++ .../compiled/_library/library/Qualifiers.kt | 8 +++ .../compiled/sources/QualifiedParts.kt | 3 + .../compiled/sources/QualifiedParts.kt.txt | 17 ++++++ .../fir/testGenerator/FirGenerateTests.kt | 4 ++ 6 files changed, 122 insertions(+) create mode 100644 plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/resolve/AbstractFirInLibraryResolveEverythingTest.kt create mode 100644 plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/resolve/FirInLibraryResolveEverythingTestGenerated.java create mode 100644 plugins/kotlin/idea/tests/testData/resolve/compiled/_library/library/Qualifiers.kt create mode 100644 plugins/kotlin/idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt create mode 100644 plugins/kotlin/idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt.txt diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/resolve/AbstractFirInLibraryResolveEverythingTest.kt b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/resolve/AbstractFirInLibraryResolveEverythingTest.kt new file mode 100644 index 000000000000..3abfd396fc75 --- /dev/null +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/resolve/AbstractFirInLibraryResolveEverythingTest.kt @@ -0,0 +1,60 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.fir.resolve + +import com.intellij.extapi.psi.StubBasedPsiElementBase +import com.intellij.psi.stubs.StubElement +import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.util.ThrowableRunnable +import org.jetbrains.kotlin.idea.fir.invalidateCaches +import org.jetbrains.kotlin.idea.test.* +import org.jetbrains.kotlin.psi.KtElement +import java.io.File + +abstract class AbstractFirInLibraryResolveEverythingTest : KotlinLightCodeInsightFixtureTestCase() { + private val mockLibraryFacility = MockLibraryFacility( + source = IDEA_TEST_DATA_DIR.resolve("resolve/compiled/_library"), + attachSources = false + ) + + override fun isFirPlugin(): Boolean { + return true + } + + override fun getProjectDescriptor(): LightProjectDescriptor = + KotlinWithJdkAndRuntimeLightProjectDescriptor.getInstance() + + override fun setUp() { + super.setUp() + mockLibraryFacility.setUp(module) + } + + fun doTest(filePath: String) { + myFixture.configureByFile(filePath) + val resolve = myFixture.getReferenceAtCaretPosition()!!.resolve() as KtElement + val ktFileStub = resolve.containingKtFile.stub!! + val builder = StringBuilder() + checkStubs(ktFileStub, builder) + KotlinTestUtils.assertEqualsToFile(File("$filePath.txt"), builder.toString()) + } + + private fun checkStubs(stubElement: StubElement<*>, builder: StringBuilder) { + stubElement.childrenStubs.forEach { stub -> + val psi = stub.psi as StubBasedPsiElementBase<*> + val reference = psi.reference + val resolve = reference?.resolve() + if (resolve != null) { + builder.append(resolve.toString()).append("\n") + } + assertNotNull(psi.stub) + checkStubs(stub, builder) + } + } + + override fun tearDown() { + runAll( + ThrowableRunnable { project.invalidateCaches() }, + ThrowableRunnable { mockLibraryFacility.tearDown(module) }, + ThrowableRunnable { super.tearDown() } + ) + } +} diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/resolve/FirInLibraryResolveEverythingTestGenerated.java b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/resolve/FirInLibraryResolveEverythingTestGenerated.java new file mode 100644 index 000000000000..378e20697801 --- /dev/null +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/resolve/FirInLibraryResolveEverythingTestGenerated.java @@ -0,0 +1,30 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +package org.jetbrains.kotlin.idea.fir.resolve; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.idea.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.jetbrains.kotlin.idea.base.test.TestRoot; +import org.junit.runner.RunWith; + +/** + * This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}. + * DO NOT MODIFY MANUALLY. + */ +@SuppressWarnings("all") +@TestRoot("fir") +@TestDataPath("$CONTENT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +@TestMetadata("../idea/tests/testData/resolve/compiled/sources") +public class FirInLibraryResolveEverythingTestGenerated extends AbstractFirInLibraryResolveEverythingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("QualifiedParts.kt") + public void testQualifiedParts() throws Exception { + runTest("../idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt"); + } +} diff --git a/plugins/kotlin/idea/tests/testData/resolve/compiled/_library/library/Qualifiers.kt b/plugins/kotlin/idea/tests/testData/resolve/compiled/_library/library/Qualifiers.kt new file mode 100644 index 000000000000..cbf0f1d319d9 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/resolve/compiled/_library/library/Qualifiers.kt @@ -0,0 +1,8 @@ +import java.util.List +import java.util.Set +import java.util.Map +import java.util.HashSet + +interface Qualifiers : List { + fun > foo(p: Map) : HashSet +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt b/plugins/kotlin/idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt new file mode 100644 index 000000000000..6c75b3f7559e --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt @@ -0,0 +1,3 @@ +import library.Qualifiers + +class QualifiedParts: Qualifiers {} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt.txt b/plugins/kotlin/idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt.txt new file mode 100644 index 000000000000..6eaeaee61ba2 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/resolve/compiled/sources/QualifiedParts.kt.txt @@ -0,0 +1,17 @@ +PsiPackage:java +PsiPackage:java.util +PsiClass:List +TYPE_PARAMETER +PsiPackage:java +PsiPackage:java.util +PsiClass:Set +TYPE_PARAMETER +PsiPackage:java +PsiPackage:java.util +PsiClass:Map +TYPE_PARAMETER +TYPE_PARAMETER +PsiPackage:java +PsiPackage:java.util +PsiClass:HashSet +TYPE_PARAMETER diff --git a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt index e3db73644965..245ebbbd48d1 100644 --- a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt +++ b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/FirGenerateTests.kt @@ -118,6 +118,10 @@ private fun assembleWorkspace(): TWorkspace = workspace { model("resolve/referenceInJava/binaryAndSource", pattern = JAVA) } + testClass { + model("resolve/compiled/sources") + } + testClass { model("navigation/gotoTypeDeclaration", pattern = TEST) } From b0be93d61ce4ec355b61b7511d970a3143bf423a Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 29 Jun 2023 16:23:54 +0200 Subject: [PATCH 031/226] [kotlin] add testcase for KTIJ-24132 ^KTIJ-24132 obsolete GitOrigin-RevId: fb2b3c174c90f5027c2a05a7fd03f73860fb5ffa --- .../K2HighlightingMetaInfoTestGenerated.java | 13 +++++++++++++ .../K1HighlightingMetaInfoTestGenerated.java | 13 +++++++++++++ .../diagnostics/mppIsNotEnabled.kt | 8 ++++++++ .../diagnostics/mppIsNotEnabled.kt.highlighting | 8 ++++++++ .../diagnostics/mppIsNotEnabled.kt.highlighting.fir | 8 ++++++++ 5 files changed, 50 insertions(+) create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt.highlighting create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt.highlighting.fir diff --git a/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java b/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java index 50dc8c468e0b..fac9a1610b0a 100644 --- a/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java +++ b/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java @@ -19,6 +19,19 @@ import org.junit.runner.RunWith; @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("../idea/tests/testData/highlighterMetaInfo") public abstract class K2HighlightingMetaInfoTestGenerated extends AbstractK2HighlightingMetaInfoTest { + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/highlighterMetaInfo/diagnostics") + public static class Diagnostics extends AbstractK2HighlightingMetaInfoTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("mppIsNotEnabled.kt") + public void testMppIsNotEnabled() throws Exception { + runTest("../idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt"); + } + } + @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("../idea/tests/testData/highlighterMetaInfo/dsl") public static class Dsl extends AbstractK2HighlightingMetaInfoTest { diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java index 777d24c32f72..42bb6600c241 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java @@ -19,6 +19,19 @@ import org.junit.runner.RunWith; @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("testData/highlighterMetaInfo") public abstract class K1HighlightingMetaInfoTestGenerated extends AbstractK1HighlightingMetaInfoTest { + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("testData/highlighterMetaInfo/diagnostics") + public static class Diagnostics extends AbstractK1HighlightingMetaInfoTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("mppIsNotEnabled.kt") + public void testMppIsNotEnabled() throws Exception { + runTest("testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt"); + } + } + @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("testData/highlighterMetaInfo/dsl") public static class Dsl extends AbstractK1HighlightingMetaInfoTest { diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt new file mode 100644 index 000000000000..3e2654e7909e --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt @@ -0,0 +1,8 @@ +// KTIJ-24132 +// ALLOW_ERRORS + +public expect interface CompletionHandler { + public operator fun invoke(cause: Throwable?) +} + +public actual typealias CompletionHandler = (cause: Throwable?) -> Unit \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt.highlighting b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt.highlighting new file mode 100644 index 000000000000..aafeff69c3b0 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt.highlighting @@ -0,0 +1,8 @@ +// KTIJ-24132 +// ALLOW_ERRORS + +public expect interface CompletionHandler { + public operator fun invoke(cause: Throwable?) +} + +public actual typealias CompletionHandler = (cause: Throwable?) -> Unit diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt.highlighting.fir b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt.highlighting.fir new file mode 100644 index 000000000000..17214e91a0b1 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt.highlighting.fir @@ -0,0 +1,8 @@ +// KTIJ-24132 +// ALLOW_ERRORS + +public expect interface CompletionHandler { + public operator fun invoke(cause: Throwable?) +} + + = Bar''")!>public actual typealias CompletionHandler = (cause: Throwable?) -> Unit From f6cb3ffb8b909f27dfb4e5c2efaadc3f124fc88b Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 29 Jun 2023 16:34:06 +0200 Subject: [PATCH 032/226] [kotlin] add testcase for KTIJ-24026 ^KTIJ-24026 obsolete GitOrigin-RevId: 50a4da318fa4876f6de92db94e5aa871661110ea --- .../highlighting/K2HighlightingMetaInfoTestGenerated.java | 5 +++++ .../highlighter/K1HighlightingMetaInfoTestGenerated.java | 5 +++++ .../highlighterMetaInfo/diagnostics/classRedeclaration.kt | 7 +++++++ .../diagnostics/classRedeclaration.kt.highlighting | 7 +++++++ .../diagnostics/classRedeclaration.kt.highlighting.fir | 7 +++++++ 5 files changed, 31 insertions(+) create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt.highlighting create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt.highlighting.fir diff --git a/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java b/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java index fac9a1610b0a..aa8109d5cc0b 100644 --- a/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java +++ b/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java @@ -26,6 +26,11 @@ public abstract class K2HighlightingMetaInfoTestGenerated extends AbstractK2High KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } + @TestMetadata("classRedeclaration.kt") + public void testClassRedeclaration() throws Exception { + runTest("../idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt"); + } + @TestMetadata("mppIsNotEnabled.kt") public void testMppIsNotEnabled() throws Exception { runTest("../idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java index 42bb6600c241..cfc847ea6303 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java @@ -26,6 +26,11 @@ public abstract class K1HighlightingMetaInfoTestGenerated extends AbstractK1High KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } + @TestMetadata("classRedeclaration.kt") + public void testClassRedeclaration() throws Exception { + runTest("testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt"); + } + @TestMetadata("mppIsNotEnabled.kt") public void testMppIsNotEnabled() throws Exception { runTest("testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt"); diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt new file mode 100644 index 000000000000..ed690af83201 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt @@ -0,0 +1,7 @@ +// KTIJ-24026 +// ALLOW_ERRORS + +class ClassB {} + +class ClassA: ClassB() {} +class ClassA: ClassB() {} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt.highlighting b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt.highlighting new file mode 100644 index 000000000000..608f7ad37f1a --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt.highlighting @@ -0,0 +1,7 @@ +// KTIJ-24026 +// ALLOW_ERRORS + +class ClassB {} + +class ClassA: ClassB() {} +class ClassA: ClassB() {} diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt.highlighting.fir b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt.highlighting.fir new file mode 100644 index 000000000000..3c953145e7ee --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt.highlighting.fir @@ -0,0 +1,7 @@ +// KTIJ-24026 +// ALLOW_ERRORS + +class ClassB {} + +class ClassA: ClassB() {} +class ClassA: ClassB() {} From a8ef981696bb9f6e024806060df66f14c39ea0a8 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 29 Jun 2023 16:38:12 +0200 Subject: [PATCH 033/226] [kotlin] add testcase for KTIJ-24099 ^KTIJ-24099 obsolete GitOrigin-RevId: 95da837a50031ed9ecf55f2dfab44484ac803d4a --- .../K2HighlightingMetaInfoTestGenerated.java | 5 +++++ .../highlighter/K1HighlightingMetaInfoTestGenerated.java | 5 +++++ .../diagnostics/javaCodeInKotlinFile1.kt | 9 +++++++++ .../diagnostics/javaCodeInKotlinFile1.kt.highlighting | 9 +++++++++ .../javaCodeInKotlinFile1.kt.highlighting.fir | 9 +++++++++ 5 files changed, 37 insertions(+) create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt.highlighting create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt.highlighting.fir diff --git a/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java b/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java index aa8109d5cc0b..93c351f26fd2 100644 --- a/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java +++ b/plugins/kotlin/highlighting/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java @@ -31,6 +31,11 @@ public abstract class K2HighlightingMetaInfoTestGenerated extends AbstractK2High runTest("../idea/tests/testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt"); } + @TestMetadata("javaCodeInKotlinFile1.kt") + public void testJavaCodeInKotlinFile1() throws Exception { + runTest("../idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt"); + } + @TestMetadata("mppIsNotEnabled.kt") public void testMppIsNotEnabled() throws Exception { runTest("../idea/tests/testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java index cfc847ea6303..cd2fb1fe82cf 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java @@ -31,6 +31,11 @@ public abstract class K1HighlightingMetaInfoTestGenerated extends AbstractK1High runTest("testData/highlighterMetaInfo/diagnostics/classRedeclaration.kt"); } + @TestMetadata("javaCodeInKotlinFile1.kt") + public void testJavaCodeInKotlinFile1() throws Exception { + runTest("testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt"); + } + @TestMetadata("mppIsNotEnabled.kt") public void testMppIsNotEnabled() throws Exception { runTest("testData/highlighterMetaInfo/diagnostics/mppIsNotEnabled.kt"); diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt new file mode 100644 index 000000000000..5d82cde2912e --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt @@ -0,0 +1,9 @@ +// KTIJ-24099 +// ALLOW_ERRORS + +public class Hierarchy extends KotlinOnlyClass { + void companionMembers() { + Custom companionlateinitVariable = KotlinOnlyClass.companionlateinitVariable; + Custom companionlateinitStaticVariable = KotlinOnlyClass.companionlateinitStaticVariable; + + } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt.highlighting b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt.highlighting new file mode 100644 index 000000000000..121e4b85f2e6 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt.highlighting @@ -0,0 +1,9 @@ +// KTIJ-24099 +// ALLOW_ERRORS + +public class Hierarchy extends KotlinOnlyClass { + void companionMembers() { + Custom companionlateinitVariable = KotlinOnlyClass.companionlateinitVariable; + Custom companionlateinitStaticVariable = KotlinOnlyClass.companionlateinitStaticVariable; + + } diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt.highlighting.fir b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt.highlighting.fir new file mode 100644 index 000000000000..7b6cb6187f1c --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/diagnostics/javaCodeInKotlinFile1.kt.highlighting.fir @@ -0,0 +1,9 @@ +// KTIJ-24099 +// ALLOW_ERRORS + +public class Hierarchy extends KotlinOnlyClass { + void companionMembers() { + Custom companionlateinitVariable = KotlinOnlyClass.companionlateinitVariable; + Custom companionlateinitStaticVariable = KotlinOnlyClass.companionlateinitStaticVariable; + + } From 42f570313b7dbf04ee7f7d0a0b17026707c4fe0e Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Sun, 25 Jun 2023 21:40:40 -0700 Subject: [PATCH 034/226] FIR UAST: avoid symbol retreival if possible ^KTIJ-26008 Fixed GitOrigin-RevId: f489a1e80340f8fcbbb5ee7022adcda11e3d40b2 --- .../kotlin/FirKotlinUastResolveProviderService.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt b/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt index df5897f1ae21..8634e2ea41f5 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt +++ b/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt @@ -395,12 +395,15 @@ interface FirKotlinUastResolveProviderService : BaseKotlinUastResolveProviderSer fun resolveToPsiClassOrEnumEntry(classOrObject: KtClassOrObject): PsiElement? { analyzeForUast(ktExpression) { val ktType = when (classOrObject) { - is KtEnumEntry -> - classOrObject.getEnumEntrySymbol().callableIdIfNonLocal?.classId?.let { enumClassId -> - buildClassType(enumClassId) - } - else -> - classOrObject.getClassOrObjectSymbol()?.let(::buildClassType) + is KtEnumEntry -> { + classOrObject.getEnumEntrySymbol().callableIdIfNonLocal?.classId?.let(::buildClassType) + } + else -> { + // NB: Avoid symbol creation/retrieval + classOrObject.getClassId()?.let(::buildClassType) + // Fallback option for local class + ?: classOrObject.getClassOrObjectSymbol()?.let(::buildClassType) + } } ?: return null val psiClass = toPsiClass(ktType, source = null, classOrObject, classOrObject.typeOwnerKind) return when (classOrObject) { From c46190ce25b490c92a4fe180ff4f76c00f5f1e41 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 21 Jun 2023 14:58:57 +0200 Subject: [PATCH 035/226] [kotlin] fix exception in K2 rename refactoring on companion rename ^KTIJ-25863 fixed GitOrigin-RevId: 27cdafc270dbc2a2aa1de5d89391190072b4ce11 --- .../rename/companionObject/companionObject.test | 3 ++- .../companionObjectWithDefaultName/companionObject.test | 3 ++- .../companionObject.test | 3 ++- .../k2/refactoring/rename/K2RenameRefactoringSupport.kt | 8 +++++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObject/companionObject.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObject/companionObject.test index 1b98ee318cbd..25fb85367544 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObject/companionObject.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObject/companionObject.test @@ -2,5 +2,6 @@ "type": "KOTLIN_CLASS", "classId": "/Foo.Bar", "newName": "Baz", - "mainFile": "toBeRenamed.kt" + "mainFile": "toBeRenamed.kt", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObjectWithDefaultName/companionObject.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObjectWithDefaultName/companionObject.test index 14e771ff5f7a..fdc001860e36 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObjectWithDefaultName/companionObject.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObjectWithDefaultName/companionObject.test @@ -2,5 +2,6 @@ "type": "KOTLIN_CLASS", "classId": "/Foo.Companion", "newName": "Baz", - "mainFile": "toBeRenamed.kt" + "mainFile": "toBeRenamed.kt", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObjectWithNameMatchingClass/companionObject.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObjectWithNameMatchingClass/companionObject.test index 898429766284..87b1a85ab20d 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObjectWithNameMatchingClass/companionObject.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/companionObjectWithNameMatchingClass/companionObject.test @@ -2,5 +2,6 @@ "type": "KOTLIN_CLASS", "classId": "/Foo.Foo", "newName": "Bar", - "mainFile": "toBeRenamed.kt" + "mainFile": "toBeRenamed.kt", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/refactorings/rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename/K2RenameRefactoringSupport.kt b/plugins/kotlin/refactorings/rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename/K2RenameRefactoringSupport.kt index bc95f9f93b1e..558f79471171 100644 --- a/plugins/kotlin/refactorings/rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename/K2RenameRefactoringSupport.kt +++ b/plugins/kotlin/refactorings/rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename/K2RenameRefactoringSupport.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.idea.parameterInfo.getJvmName import org.jetbrains.kotlin.idea.refactoring.rename.KotlinRenameRefactoringSupport +import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.searching.inheritors.findAllOverridings import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.NameUtils @@ -105,7 +106,12 @@ internal class K2RenameRefactoringSupport : KotlinRenameRefactoringSupport { } override fun isCompanionObjectClassReference(psiReference: PsiReference): Boolean { - notImplementedInK2() + if (psiReference !is KtSimpleNameReference) { + return false + } + return analyze(psiReference.element) { + psiReference.isImplicitReferenceToCompanion() + } } override fun shortenReferencesLater(element: KtElement) { From 023deef4cb714cb4e418637e1756e4a8c9b5ca9c Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 21 Jun 2023 16:58:21 +0200 Subject: [PATCH 036/226] [kotlin] support rename for implicit "it" parameters in K2 ^KTIJ-24324 fixed GitOrigin-RevId: e6b7ff1af9cdade77a4ca6f6ecbafa053e4db4fe --- .../utils/implicitLambdaParameterUtils.kt | 43 ++++++++++ ...KotlinHighlightImplicitItHandlerFactory.kt | 6 +- ...thExplicitFunctionLiteralParamIntention.kt | 20 +++-- .../RenameKotlinImplicitLambdaParameter.kt | 83 ------------------- .../FE10KotlinTargetElementEvaluator.kt | 4 +- .../idea/refactoring/InplaceRenameTest.kt | 2 +- .../resources/META-INF/refactorings.xml | 1 + .../resources/META-INF/refactorings-fe10.xml | 1 - .../kotlin.refactorings.common.iml | 1 + .../RenameKotlinImplicitLambdaParameter.kt | 75 +++++++++++++++++ 10 files changed, 140 insertions(+), 96 deletions(-) create mode 100644 plugins/kotlin/code-insight/utils/src/org/jetbrains/kotlin/idea/codeinsight/utils/implicitLambdaParameterUtils.kt delete mode 100644 plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinImplicitLambdaParameter.kt create mode 100644 plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameKotlinImplicitLambdaParameter.kt diff --git a/plugins/kotlin/code-insight/utils/src/org/jetbrains/kotlin/idea/codeinsight/utils/implicitLambdaParameterUtils.kt b/plugins/kotlin/code-insight/utils/src/org/jetbrains/kotlin/idea/codeinsight/utils/implicitLambdaParameterUtils.kt new file mode 100644 index 000000000000..b5c4e3bde9d6 --- /dev/null +++ b/plugins/kotlin/code-insight/utils/src/org/jetbrains/kotlin/idea/codeinsight/utils/implicitLambdaParameterUtils.kt @@ -0,0 +1,43 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.codeinsight.utils + +import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousFunctionSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol +import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.KtFunctionLiteral +import org.jetbrains.kotlin.psi.KtNameReferenceExpression + +fun KtNameReferenceExpression.isReferenceToImplicitLambdaParameter(): Boolean { + if (getReferencedNameAsName() != StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) return false + @OptIn(KtAllowAnalysisOnEdt::class) + allowAnalysisOnEdt { + analyze(this) { + return getImplicitLambdaParameterSymbol() != null + } + } +} + +fun KtNameReferenceExpression.getFunctionLiteralByImplicitLambdaParameter(): KtFunctionLiteral? { + if (getReferencedNameAsName() != StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) return null + @OptIn(KtAllowAnalysisOnEdt::class) + allowAnalysisOnEdt { + analyze(this) { + val implicitParameterSymbol = getImplicitLambdaParameterSymbol() ?: return null + val lambda = implicitParameterSymbol.getContainingSymbol() as? KtAnonymousFunctionSymbol ?: return null + return lambda.psi as? KtFunctionLiteral + } + } +} + + +context(KtAnalysisSession) +fun KtNameReferenceExpression.getImplicitLambdaParameterSymbol(): KtValueParameterSymbol? { + val parameterSymbol = mainReference.resolveToSymbol() as? KtValueParameterSymbol ?: return null + if (!parameterSymbol.isImplicitLambdaParameter) return null + return parameterSymbol +} diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt index 9040530d38c2..2aaa111d70bc 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt @@ -9,7 +9,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.util.Consumer -import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter.Companion.getLambdaByImplicitItReference +import org.jetbrains.kotlin.idea.codeinsight.utils.getFunctionLiteralByImplicitLambdaParameter import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression @@ -19,7 +19,7 @@ class KotlinHighlightImplicitItHandlerFactory : HighlightUsagesHandlerFactoryBas override fun createHighlightUsagesHandler(editor: Editor, file: PsiFile, target: PsiElement): HighlightUsagesHandlerBase<*>? { if (!(target is LeafPsiElement && target.elementType == KtTokens.IDENTIFIER)) return null val refExpr = target.parent as? KtNameReferenceExpression ?: return null - val lambda = getLambdaByImplicitItReference(refExpr) ?: return null + val lambda = refExpr.getFunctionLiteralByImplicitLambdaParameter() ?: return null return object : HighlightUsagesHandlerBase(editor, file) { override fun getTargets() = listOf(refExpr) @@ -32,7 +32,7 @@ class KotlinHighlightImplicitItHandlerFactory : HighlightUsagesHandlerFactoryBas lambda.accept( object : KtTreeVisitorVoid() { override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { - if (expression is KtNameReferenceExpression && getLambdaByImplicitItReference(expression) == lambda) { + if (expression is KtNameReferenceExpression && expression.getFunctionLiteralByImplicitLambdaParameter() == lambda) { addOccurrence(expression) } } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceItWithExplicitFunctionLiteralParamIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceItWithExplicitFunctionLiteralParamIntention.kt index 2a8095052e48..2b4b91927bb8 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceItWithExplicitFunctionLiteralParamIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceItWithExplicitFunctionLiteralParamIntention.kt @@ -3,27 +3,35 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.codeInsight.FileModificationService +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.editor.Editor import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.codeinsight.api.classic.intentions.SelfTargetingOffsetIndependentIntention -import org.jetbrains.kotlin.idea.refactoring.rename.KotlinVariableInplaceRenameHandler -import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter.Companion.convertImplicitItToExplicit -import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter.Companion.isAutoCreatedItUsage +import org.jetbrains.kotlin.idea.codeinsight.utils.isReferenceToImplicitLambdaParameter +import org.jetbrains.kotlin.idea.refactoring.rename.handlers.RenameKotlinImplicitLambdaParameter import org.jetbrains.kotlin.psi.KtNameReferenceExpression class ReplaceItWithExplicitFunctionLiteralParamIntention : SelfTargetingOffsetIndependentIntention( KtNameReferenceExpression::class.java, KotlinBundle.lazyMessage("replace.it.with.explicit.parameter") ) { - override fun isApplicableTo(element: KtNameReferenceExpression) = isAutoCreatedItUsage(element) + override fun isApplicableTo(element: KtNameReferenceExpression) = element.isReferenceToImplicitLambdaParameter() override fun startInWriteAction(): Boolean = false override fun applyTo(element: KtNameReferenceExpression, editor: Editor?) { if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return if (editor == null) throw IllegalArgumentException("This intention requires an editor") - val paramToRename = convertImplicitItToExplicit(element, editor) ?: return editor.caretModel.moveToOffset(element.textOffset) - KotlinVariableInplaceRenameHandler().doRename(paramToRename, editor, null) + val ktFile = element.containingKtFile + + val dataContext = DataContext { id -> + when { + CommonDataKeys.PSI_ELEMENT.`is`(id) -> element + else -> null + } + } + RenameKotlinImplicitLambdaParameter().invoke(ktFile.project, editor, ktFile, dataContext) } } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinImplicitLambdaParameter.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinImplicitLambdaParameter.kt deleted file mode 100644 index e0f6550a1880..000000000000 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinImplicitLambdaParameter.kt +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -package org.jetbrains.kotlin.idea.refactoring.rename - -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.application.runWriteAction -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.idea.base.resources.KotlinBundle -import org.jetbrains.kotlin.idea.caches.resolve.analyze -import org.jetbrains.kotlin.idea.caches.resolve.safeAnalyzeNonSourceRootCode -import org.jetbrains.kotlin.idea.references.mainReference -import org.jetbrains.kotlin.idea.references.resolveToDescriptors -import org.jetbrains.kotlin.idea.util.application.executeWriteCommand -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.resolve.source.getPsi - -class RenameKotlinImplicitLambdaParameter : KotlinVariableInplaceRenameHandler() { - override fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile): Boolean { - val nameExpression = findElementToRename(file, editor) - return nameExpression != null && isAutoCreatedItUsage(nameExpression) - } - - override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext) { - if (editor == null || file == null) return - val itExpression = findElementToRename(file, editor) ?: return - val explicitItParameter = project.executeWriteCommand( - KotlinBundle.message("text.convert._it_.to.explicit.lambda.parameter"), - groupId = null, - command = { convertImplicitItToExplicit(itExpression, editor) }, - ) ?: return - - doRename(explicitItParameter, editor, dataContext) - } - - private fun findElementToRename( - file: PsiFile, - editor: Editor, - ) = file.findElementForRename(editor.caretModel.offset) - - override fun invoke(project: Project, elements: Array, dataContext: DataContext) { - // Do nothing: this method is called not from editor - } - - companion object { - fun isAutoCreatedItUsage(expression: KtNameReferenceExpression) = resolveToAutoCreatedItDescriptor(expression) != null - fun convertImplicitItToExplicit(itExpression: KtNameReferenceExpression, editor: Editor): KtParameter? { - val target = itExpression.mainReference.resolveToDescriptors(itExpression.analyze()).single() - val containingDescriptor = target.containingDeclaration ?: return null - val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(containingDescriptor) as? KtFunctionLiteral ?: return null - val newExpr = KtPsiFactory(itExpression.project).createExpression("{ it -> }") as KtLambdaExpression - val arrow = newExpr.functionLiteral.arrow ?: return null - runWriteAction { - functionLiteral.addRangeAfter( - newExpr.functionLiteral.valueParameterList, - arrow, - functionLiteral.lBrace, - ) - } - - PsiDocumentManager.getInstance(itExpression.project).doPostponedOperationsAndUnblockDocument(editor.document) - - return functionLiteral.valueParameters.singleOrNull() - } - - fun getLambdaByImplicitItReference(expression: KtNameReferenceExpression) = - resolveToAutoCreatedItDescriptor(expression)?.containingDeclaration?.source?.getPsi() as? KtFunctionLiteral - - private fun resolveToAutoCreatedItDescriptor(expression: KtNameReferenceExpression): ValueParameterDescriptor? { - if (expression.getReferencedName() != "it") return null - val context = expression.safeAnalyzeNonSourceRootCode(BodyResolveMode.PARTIAL) - val target = expression.mainReference.resolveToDescriptors(context).singleOrNull() as? ValueParameterDescriptor ?: return null - return if (context[BindingContext.AUTO_CREATED_IT, target] == true) target else null - } - } -} diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/FE10KotlinTargetElementEvaluator.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/FE10KotlinTargetElementEvaluator.kt index 809cc451cc07..c78d5346dba3 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/FE10KotlinTargetElementEvaluator.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/FE10KotlinTargetElementEvaluator.kt @@ -8,13 +8,13 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiReference import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource -import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter.Companion.isAutoCreatedItUsage import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.source.getPsi +import org.jetbrains.kotlin.idea.codeinsight.utils.isReferenceToImplicitLambdaParameter class FE10KotlinTargetElementEvaluator : KotlinTargetElementEvaluator() { companion object { @@ -22,7 +22,7 @@ class FE10KotlinTargetElementEvaluator : KotlinTargetElementEvaluator() { val element: PsiElement = ref.element if (element.text != "it") return null - if (element !is KtNameReferenceExpression || !isAutoCreatedItUsage(element)) return null + if (element !is KtNameReferenceExpression || !element.isReferenceToImplicitLambdaParameter()) return null val itDescriptor = element.resolveMainReferenceToDescriptors().singleOrNull() ?: return null val descriptorWithSource = itDescriptor.containingDeclaration as? DeclarationDescriptorWithSource ?: return null diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/InplaceRenameTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/InplaceRenameTest.kt index aa83601c3f66..027a3ef766ad 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/InplaceRenameTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/InplaceRenameTest.kt @@ -13,8 +13,8 @@ import com.intellij.testFramework.fixtures.CodeInsightTestUtil import junit.framework.TestCase import org.jetbrains.kotlin.idea.refactoring.rename.KotlinMemberInplaceRenameHandler import org.jetbrains.kotlin.idea.refactoring.rename.KotlinVariableInplaceRenameHandler -import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename +import org.jetbrains.kotlin.idea.refactoring.rename.handlers.RenameKotlinImplicitLambdaParameter import org.jetbrains.kotlin.idea.test.IDEA_TEST_DATA_DIR import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.psi.KtNameReferenceExpression diff --git a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml index bcc4069e2535..28e38dc18fbf 100644 --- a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml +++ b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml @@ -53,5 +53,6 @@ + \ No newline at end of file diff --git a/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml b/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml index 12307d105494..f21fc695c6c8 100644 --- a/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml +++ b/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml @@ -151,7 +151,6 @@ - diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/kotlin.refactorings.common.iml b/plugins/kotlin/refactorings/kotlin.refactorings.common/kotlin.refactorings.common.iml index 838d0a045a1e..b7e41409b8a5 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.common/kotlin.refactorings.common.iml +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/kotlin.refactorings.common.iml @@ -27,5 +27,6 @@ + \ No newline at end of file diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameKotlinImplicitLambdaParameter.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameKotlinImplicitLambdaParameter.kt new file mode 100644 index 000000000000..da891e7f4ea4 --- /dev/null +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameKotlinImplicitLambdaParameter.kt @@ -0,0 +1,75 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package org.jetbrains.kotlin.idea.refactoring.rename.handlers + +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousFunctionSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.idea.codeinsight.utils.getFunctionLiteralByImplicitLambdaParameter +import org.jetbrains.kotlin.idea.codeinsight.utils.isReferenceToImplicitLambdaParameter +import org.jetbrains.kotlin.idea.refactoring.rename.KotlinVariableInplaceRenameHandler +import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.util.application.executeWriteCommand +import org.jetbrains.kotlin.psi.* + +class RenameKotlinImplicitLambdaParameter : KotlinVariableInplaceRenameHandler() { + @OptIn(KtAllowAnalysisOnEdt::class) + override fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile): Boolean { + val nameExpression = findElementToRename(file, editor) + return nameExpression != null && nameExpression.isReferenceToImplicitLambdaParameter() + } + + override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext) { + if (editor == null || file == null) return + val itExpression = findElementToRename(file, editor) ?: return + val explicitItParameter = project.executeWriteCommand( + KotlinBundle.message("text.convert._it_.to.explicit.lambda.parameter"), + groupId = null, + command = { itExpression.createExplicitLambdaParameterByImplicitOne(editor) }, + ) ?: return + + doRename(explicitItParameter, editor, dataContext) + } + + private fun findElementToRename( + file: PsiFile, + editor: Editor, + ) = file.findElementForRename(editor.caretModel.offset) + + override fun invoke(project: Project, elements: Array, dataContext: DataContext) { + // Do nothing: this method is called not from editor + } +} + + +private fun KtNameReferenceExpression.createExplicitLambdaParameterByImplicitOne(editor: Editor): KtParameter? { + if (getReferencedName() != "it") return null + val functionLiteral = getFunctionLiteralByImplicitLambdaParameter() ?: return null + + val project = project + + val newExpr = KtPsiFactory(project).createExpression("{ it -> }") as KtLambdaExpression + val arrow = newExpr.functionLiteral.arrow ?: return null + runWriteAction { + functionLiteral.addRangeAfter( + newExpr.functionLiteral.valueParameterList, + arrow, + functionLiteral.lBrace, + ) + } + + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document) + + return functionLiteral.valueParameters.singleOrNull() +} \ No newline at end of file From f3bab372f02a75afea2921e32d9cc11007e9409f Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 21 Jun 2023 12:12:22 +0200 Subject: [PATCH 037/226] [Kotlin] fix rename of internal abstract method ^KTIJ-25903 fixed GitOrigin-RevId: c5360ca215a544ad64efb048a447bc3c2c5641cf --- .../rename/K1KotlinRenameRefactoringSupport.kt | 4 ---- .../idea/refactoring/rename/RenameTestGenerated.java | 5 +++++ .../rename/abstractFunction/abstractFunction.test | 8 ++++++++ .../rename/abstractFunction/after/toBeRenamed.kt | 7 +++++++ .../rename/abstractFunction/before/toBeRenamed.kt | 7 +++++++ .../internalFunWithOverrides.test | 3 ++- .../internalFunWithOverrides.test | 3 ++- .../refactoring/rename/KotlinRenameRefactoringSupport.kt | 5 ++++- .../k2/refactoring/rename/K2RenameRefactoringSupport.kt | 4 ---- .../k2/refactoring/rename/FirRenameTestGenerated.java | 5 +++++ 10 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/abstractFunction.test create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/after/toBeRenamed.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/before/toBeRenamed.kt diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/K1KotlinRenameRefactoringSupport.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/K1KotlinRenameRefactoringSupport.kt index 113cc8734040..88f824db92d3 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/K1KotlinRenameRefactoringSupport.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/K1KotlinRenameRefactoringSupport.kt @@ -71,10 +71,6 @@ internal class K1RenameRefactoringSupport : KotlinRenameRefactoringSupport { return descriptor.overriddenDescriptors.mapNotNull { it.source.getPsi() } } - override fun getModuleNameSuffixForMangledName(mangledName: String): String? { - return KotlinTypeMapper.InternalNameMapper.getModuleNameSuffix(mangledName) - } - override fun mangleInternalName(name: String, moduleName: String): String { return KotlinTypeMapper.InternalNameMapper.mangleInternalName(name, moduleName) } diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java index 1c99dff06c0a..e6d950ed7e95 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java @@ -23,6 +23,11 @@ public class RenameTestGenerated extends AbstractRenameTest { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } + @TestMetadata("abstractFunction/abstractFunction.test") + public void testAbstractFunction_AbstractFunction() throws Exception { + runTest("testData/refactoring/rename/abstractFunction/abstractFunction.test"); + } + @TestMetadata("ambiguousClassFunImportRenameClass/ambiguousClassFunImportRenameClass.test") public void testAmbiguousClassFunImportRenameClass_AmbiguousClassFunImportRenameClass() throws Exception { runTest("testData/refactoring/rename/ambiguousClassFunImportRenameClass/ambiguousClassFunImportRenameClass.test"); diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/abstractFunction.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/abstractFunction.test new file mode 100644 index 000000000000..cd8c516d4141 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/abstractFunction.test @@ -0,0 +1,8 @@ +{ + "type": "KOTLIN_FUNCTION", + "classId": "/A.B", + "oldName": "absFun", + "newName": "absFun2", + "mainFile": "toBeRenamed.kt", + "enabledInK2": true +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/after/toBeRenamed.kt b/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/after/toBeRenamed.kt new file mode 100644 index 000000000000..2bddea685918 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/after/toBeRenamed.kt @@ -0,0 +1,7 @@ +sealed class A { + internal abstract fun absFun2(x:Int): Int + + abstract class B : A() { + override fun absFun2(x: Int): Int = 1 + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/before/toBeRenamed.kt b/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/before/toBeRenamed.kt new file mode 100644 index 000000000000..d1565e34898b --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/abstractFunction/before/toBeRenamed.kt @@ -0,0 +1,7 @@ +sealed class A { + internal abstract fun absFun(x:Int): Int + + abstract class B : A() { + override fun absFun(x: Int): Int = 1 + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/internalFunWithOverrides/internalFunWithOverrides.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/internalFunWithOverrides/internalFunWithOverrides.test index eaf15b1ef731..d8456e7b985c 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/internalFunWithOverrides/internalFunWithOverrides.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/internalFunWithOverrides/internalFunWithOverrides.test @@ -1,5 +1,6 @@ { "type": "MARKED_ELEMENT", "mainFile": "test.kt", - "newName": "newOverridableMethod" + "newName": "newOverridableMethod", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/internalVarWithOverrides/internalFunWithOverrides.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/internalVarWithOverrides/internalFunWithOverrides.test index 0d430d008746..c047f9ca4120 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/internalVarWithOverrides/internalFunWithOverrides.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/internalVarWithOverrides/internalFunWithOverrides.test @@ -1,5 +1,6 @@ { "type": "MARKED_ELEMENT", "mainFile": "test.kt", - "newName": "newOverridableVar" + "newName": "newOverridableVar", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/KotlinRenameRefactoringSupport.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/KotlinRenameRefactoringSupport.kt index 152a69a8b976..e0d98a773643 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/KotlinRenameRefactoringSupport.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/KotlinRenameRefactoringSupport.kt @@ -54,7 +54,10 @@ interface KotlinRenameRefactoringSupport { fun getAllOverridenFunctions(function: KtNamedFunction): List - fun getModuleNameSuffixForMangledName(mangledName: String): String? + fun getModuleNameSuffixForMangledName(mangledName: String): String? { + val indexOfDollar = mangledName.indexOf('$') + return if (indexOfDollar >= 0) mangledName.substring(indexOfDollar + 1) else null + } fun mangleInternalName(name: String, moduleName: String): String diff --git a/plugins/kotlin/refactorings/rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename/K2RenameRefactoringSupport.kt b/plugins/kotlin/refactorings/rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename/K2RenameRefactoringSupport.kt index 558f79471171..d403fb436d3b 100644 --- a/plugins/kotlin/refactorings/rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename/K2RenameRefactoringSupport.kt +++ b/plugins/kotlin/refactorings/rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename/K2RenameRefactoringSupport.kt @@ -76,10 +76,6 @@ internal class K2RenameRefactoringSupport : KotlinRenameRefactoringSupport { } } - override fun getModuleNameSuffixForMangledName(mangledName: String): String? { - notImplementedInK2() - } - override fun mangleInternalName(name: String, moduleName: String): String { return name + "$" + NameUtils.sanitizeAsJavaIdentifier(moduleName) } diff --git a/plugins/kotlin/refactorings/rename.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/rename/FirRenameTestGenerated.java b/plugins/kotlin/refactorings/rename.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/rename/FirRenameTestGenerated.java index de9bf2521842..8e38681712d4 100644 --- a/plugins/kotlin/refactorings/rename.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/rename/FirRenameTestGenerated.java +++ b/plugins/kotlin/refactorings/rename.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/rename/FirRenameTestGenerated.java @@ -23,6 +23,11 @@ public class FirRenameTestGenerated extends AbstractFirRenameTest { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } + @TestMetadata("abstractFunction/abstractFunction.test") + public void testAbstractFunction_AbstractFunction() throws Exception { + runTest("../../idea/tests/testData/refactoring/rename/abstractFunction/abstractFunction.test"); + } + @TestMetadata("ambiguousClassFunImportRenameClass/ambiguousClassFunImportRenameClass.test") public void testAmbiguousClassFunImportRenameClass_AmbiguousClassFunImportRenameClass() throws Exception { runTest("../../idea/tests/testData/refactoring/rename/ambiguousClassFunImportRenameClass/ambiguousClassFunImportRenameClass.test"); From ae2e54a54648739594e079c037c8069de9537b27 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 22 Jun 2023 16:39:36 +0200 Subject: [PATCH 038/226] [Kotlin] forbid renaming of synthetic members in K2 ^KTIJ-25919 fixed GitOrigin-RevId: 0c3b14aa09913b26959717e84f3838b130c1fd5f --- ...eSyntheticDeclarationByReferenceHandler.kt | 45 ---------------- .../dataClassComponentN.test | 3 +- .../rename/dataClassCopy/dataClassCopy.test | 3 +- .../rename/enumValueOf/enumValueOf.test | 3 +- .../javaEnumValueOf/javaEnumValueOf.test | 3 +- .../resources/META-INF/refactorings.xml | 1 + .../resources/META-INF/refactorings-fe10.xml | 1 - ...eSyntheticDeclarationByReferenceHandler.kt | 51 +++++++++++++++++++ 8 files changed, 60 insertions(+), 50 deletions(-) delete mode 100644 plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameSyntheticDeclarationByReferenceHandler.kt create mode 100644 plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameSyntheticDeclarationByReferenceHandler.kt diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameSyntheticDeclarationByReferenceHandler.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameSyntheticDeclarationByReferenceHandler.kt deleted file mode 100644 index eb4e85e94327..000000000000 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameSyntheticDeclarationByReferenceHandler.kt +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -package org.jetbrains.kotlin.idea.refactoring.rename - -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.refactoring.RefactoringBundle -import com.intellij.refactoring.rename.RenameHandler -import com.intellij.refactoring.util.CommonRefactoringUtil -import org.jetbrains.kotlin.idea.base.resources.KotlinBundle -import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall -import org.jetbrains.kotlin.psi.KtSimpleNameExpression -import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized -import org.jetbrains.kotlin.resolve.sam.SamConstructorDescriptor - -class RenameSyntheticDeclarationByReferenceHandler : RenameHandler { - override fun isAvailableOnDataContext(dataContext: DataContext): Boolean { - val file = CommonDataKeys.PSI_FILE.getData(dataContext) ?: return false - val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return false - val refExpression = file.findElementForRename(editor.caretModel.offset) ?: return false - val descriptor = refExpression.resolveToCall()?.resultingDescriptor ?: return false - // SamConstructorDescriptor is synthetic but it can be renamed - return descriptor !is SamConstructorDescriptor && descriptor.isSynthesized - } - - override fun isRenaming(dataContext: DataContext) = isAvailableOnDataContext(dataContext) - - override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) { - CommonRefactoringUtil.showErrorHint( - project, - editor, - KotlinBundle.message("text.rename.is.not.applicable.to.synthetic.declarations"), - RefactoringBundle.message("rename.title"), - null - ) - } - - override fun invoke(project: Project, elements: Array, dataContext: DataContext?) { - // Do nothing: this method is not called from editor - } -} diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/dataClassComponentN/dataClassComponentN.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/dataClassComponentN/dataClassComponentN.test index 136def502e0c..f1e4e3fb64a6 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/dataClassComponentN/dataClassComponentN.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/dataClassComponentN/dataClassComponentN.test @@ -3,5 +3,6 @@ "mainFile": "test.kt", "newName": "component123", "withRuntime": "true", - "hint": "Rename is not applicable to synthetic declaration" + "hint": "Rename is not applicable to synthetic declaration", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/dataClassCopy/dataClassCopy.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/dataClassCopy/dataClassCopy.test index 0d6c55fab1ba..cb9cc7c83647 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/dataClassCopy/dataClassCopy.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/dataClassCopy/dataClassCopy.test @@ -3,5 +3,6 @@ "mainFile": "test.kt", "newName": "copyNew", "withRuntime": "true", - "hint": "Rename is not applicable to synthetic declaration" + "hint": "Rename is not applicable to synthetic declaration", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/enumValueOf/enumValueOf.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/enumValueOf/enumValueOf.test index 81a1a57cb22a..a319638e0c39 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/enumValueOf/enumValueOf.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/enumValueOf/enumValueOf.test @@ -3,5 +3,6 @@ "mainFile": "test.kt", "newName": "valueOfNew", "withRuntime": "true", - "hint": "Rename is not applicable to synthetic declaration" + "hint": "Rename is not applicable to synthetic declaration", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/rename/javaEnumValueOf/javaEnumValueOf.test b/plugins/kotlin/idea/tests/testData/refactoring/rename/javaEnumValueOf/javaEnumValueOf.test index 81a1a57cb22a..8cd61d3dfd0c 100644 --- a/plugins/kotlin/idea/tests/testData/refactoring/rename/javaEnumValueOf/javaEnumValueOf.test +++ b/plugins/kotlin/idea/tests/testData/refactoring/rename/javaEnumValueOf/javaEnumValueOf.test @@ -3,5 +3,6 @@ "mainFile": "test.kt", "newName": "valueOfNew", "withRuntime": "true", - "hint": "Rename is not applicable to synthetic declaration" + "hint": "Rename is not applicable to synthetic declaration", + "enabledInK2": true } \ No newline at end of file diff --git a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml index 28e38dc18fbf..293c66cbfd1f 100644 --- a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml +++ b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml @@ -54,5 +54,6 @@ + \ No newline at end of file diff --git a/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml b/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml index f21fc695c6c8..0c1cf38cf4a7 100644 --- a/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml +++ b/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml @@ -154,7 +154,6 @@ - diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameSyntheticDeclarationByReferenceHandler.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameSyntheticDeclarationByReferenceHandler.kt new file mode 100644 index 000000000000..a403ba58e24a --- /dev/null +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameSyntheticDeclarationByReferenceHandler.kt @@ -0,0 +1,51 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.refactoring.rename.handlers + +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.refactoring.RefactoringBundle +import com.intellij.refactoring.rename.RenameHandler +import com.intellij.refactoring.util.CommonRefactoringUtil +import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.KtSimpleNameExpression + +class RenameSyntheticDeclarationByReferenceHandler : RenameHandler { + override fun isAvailableOnDataContext(dataContext: DataContext): Boolean { + val file = CommonDataKeys.PSI_FILE.getData(dataContext) ?: return false + val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return false + val refExpression = file.findElementForRename(editor.caretModel.offset) ?: return false + @OptIn(KtAllowAnalysisOnEdt::class) + allowAnalysisOnEdt { + analyze(refExpression) { + val target = refExpression.mainReference.resolveToSymbol() ?: return false + return target.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED + } + } + } + + override fun isRenaming(dataContext: DataContext) = isAvailableOnDataContext(dataContext) + + override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) { + CommonRefactoringUtil.showErrorHint( + project, + editor, + KotlinBundle.message("text.rename.is.not.applicable.to.synthetic.declarations"), + RefactoringBundle.message("rename.title"), + null + ) + } + + override fun invoke(project: Project, elements: Array, dataContext: DataContext?) { + // Do nothing: this method is not called from editor + } +} From 0f7ee4e8048439bf9f04715275c69610e68a1574 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 22 Jun 2023 16:52:10 +0200 Subject: [PATCH 039/226] [Kotlin] forbid renaming of property field in K2 ^KTIJ-25887 fixed GitOrigin-RevId: 4ddd8aa95f1599ac0a37a19b43b62aa5af8849dd --- .../RenameBackingFieldReferenceHandler.kt | 39 --------------- .../resources/META-INF/refactorings.xml | 1 + .../resources/META-INF/refactorings-fe10.xml | 1 - .../RenameBackingFieldReferenceHandler.kt | 49 +++++++++++++++++++ 4 files changed, 50 insertions(+), 40 deletions(-) delete mode 100644 plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameBackingFieldReferenceHandler.kt create mode 100644 plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameBackingFieldReferenceHandler.kt diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameBackingFieldReferenceHandler.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameBackingFieldReferenceHandler.kt deleted file mode 100644 index 7ef24924bf53..000000000000 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameBackingFieldReferenceHandler.kt +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -package org.jetbrains.kotlin.idea.refactoring.rename - -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.refactoring.RefactoringBundle -import com.intellij.refactoring.util.CommonRefactoringUtil -import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor -import org.jetbrains.kotlin.idea.base.resources.KotlinBundle -import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall -import org.jetbrains.kotlin.psi.KtSimpleNameExpression - -class RenameBackingFieldReferenceHandler : KotlinVariableInplaceRenameHandler() { - override fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile): Boolean { - val refExpression = file.findElementForRename(editor.caretModel.offset) ?: return false - if (refExpression.text != "field") return false - return refExpression.resolveToCall()?.resultingDescriptor is SyntheticFieldDescriptor - } - - override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext) { - editor?.let { - CommonRefactoringUtil.showErrorHint( - project, - editor, - KotlinBundle.message("text.rename.not.applicable.to.backing.field.reference"), - RefactoringBundle.message("rename.title"), - null - ) - } - } - - override fun invoke(project: Project, elements: Array, dataContext: DataContext) { - // Do nothing: this method is called not from editor - } -} diff --git a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml index 293c66cbfd1f..74a265aacbea 100644 --- a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml +++ b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml @@ -55,5 +55,6 @@ + \ No newline at end of file diff --git a/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml b/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml index 0c1cf38cf4a7..bdc32b4a451e 100644 --- a/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml +++ b/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml @@ -156,7 +156,6 @@ - diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameBackingFieldReferenceHandler.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameBackingFieldReferenceHandler.kt new file mode 100644 index 000000000000..f3be22191316 --- /dev/null +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameBackingFieldReferenceHandler.kt @@ -0,0 +1,49 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.refactoring.rename.handlers + +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.refactoring.RefactoringBundle +import com.intellij.refactoring.util.CommonRefactoringUtil +import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.symbols.KtBackingFieldSymbol +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.idea.refactoring.rename.KotlinVariableInplaceRenameHandler +import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.KtSimpleNameExpression + +class RenameBackingFieldReferenceHandler : KotlinVariableInplaceRenameHandler() { + override fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile): Boolean { + val refExpression = file.findElementForRename(editor.caretModel.offset) ?: return false + if (refExpression.text != "field") return false + @OptIn(KtAllowAnalysisOnEdt::class) + allowAnalysisOnEdt { + analyze(refExpression) { + val target = refExpression.mainReference.resolveToSymbol() ?: return false + return target is KtBackingFieldSymbol + } + } + } + + override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext) { + editor?.let { + CommonRefactoringUtil.showErrorHint( + project, + editor, + KotlinBundle.message("text.rename.not.applicable.to.backing.field.reference"), + RefactoringBundle.message("rename.title"), + null + ) + } + } + + override fun invoke(project: Project, elements: Array, dataContext: DataContext) { + // Do nothing: this method is called not from editor + } +} From c5403965b7cdc18b0a3aad35c164d5d8f84bb4fc Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 22 Jun 2023 17:01:27 +0200 Subject: [PATCH 040/226] [Kotlin] forbid renaming of secondary constructors in K2 GitOrigin-RevId: 0fa2deaa68f8338c03e77a7a207f5080a051f62d --- .../RenameOnSecondaryConstructorHandler.kt | 52 ----------------- .../resources/META-INF/refactorings.xml | 1 + .../resources/META-INF/refactorings-fe10.xml | 1 - .../RenameOnSecondaryConstructorHandler.kt | 58 +++++++++++++++++++ 4 files changed, 59 insertions(+), 53 deletions(-) delete mode 100644 plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameOnSecondaryConstructorHandler.kt create mode 100644 plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameOnSecondaryConstructorHandler.kt diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameOnSecondaryConstructorHandler.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameOnSecondaryConstructorHandler.kt deleted file mode 100644 index c99bbf0a3267..000000000000 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameOnSecondaryConstructorHandler.kt +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -package org.jetbrains.kotlin.idea.refactoring.rename - -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.psi.util.PsiTreeUtil -import com.intellij.refactoring.RefactoringBundle -import com.intellij.refactoring.rename.RenameHandler -import com.intellij.refactoring.util.CommonRefactoringUtil -import org.jetbrains.kotlin.idea.base.resources.KotlinBundle -import org.jetbrains.kotlin.psi.* - - -class RenameOnSecondaryConstructorHandler : RenameHandler { - override fun isAvailableOnDataContext(dataContext: DataContext): Boolean { - val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return false - val file = CommonDataKeys.PSI_FILE.getData(dataContext) ?: return false - - val element = PsiTreeUtil.findElementOfClassAtOffsetWithStopSet( - file, - editor.caretModel.offset, - KtSecondaryConstructor::class.java, - false, - KtBlockExpression::class.java, - KtValueArgumentList::class.java, - KtParameterList::class.java, - KtConstructorDelegationCall::class.java - ) - return element != null - } - - override fun isRenaming(dataContext: DataContext): Boolean = isAvailableOnDataContext(dataContext) - - override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) { - CommonRefactoringUtil.showErrorHint( - project, - editor, - KotlinBundle.message("text.rename.is.not.applicable.to.secondary.constructors"), - RefactoringBundle.message("rename.title"), - null - ) - } - - override fun invoke(project: Project, elements: Array, dataContext: DataContext?) { - // Do nothing: this method is called not from editor - } -} diff --git a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml index 74a265aacbea..37898a15b0a3 100644 --- a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml +++ b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml @@ -56,5 +56,6 @@ + \ No newline at end of file diff --git a/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml b/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml index bdc32b4a451e..922e1c149a2c 100644 --- a/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml +++ b/plugins/kotlin/plugin/k1/resources/META-INF/refactorings-fe10.xml @@ -152,7 +152,6 @@ - diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameOnSecondaryConstructorHandler.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameOnSecondaryConstructorHandler.kt new file mode 100644 index 000000000000..24c899555232 --- /dev/null +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameOnSecondaryConstructorHandler.kt @@ -0,0 +1,58 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.refactoring.rename.handlers + + +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.refactoring.RefactoringBundle +import com.intellij.refactoring.rename.RenameHandler +import com.intellij.refactoring.util.CommonRefactoringUtil +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.psi.* + + +class RenameOnSecondaryConstructorHandler : RenameHandler { + override fun isAvailableOnDataContext(dataContext: DataContext): Boolean { + val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return false + val file = CommonDataKeys.PSI_FILE.getData(dataContext) ?: return false + + val element = PsiTreeUtil.findElementOfClassAtOffsetWithStopSet( + file, + editor.caretModel.offset, + KtSecondaryConstructor::class.java, + /* strictStart = */ false, + KtBlockExpression::class.java, + KtValueArgumentList::class.java, + KtParameterList::class.java, + KtConstructorDelegationCall::class.java + ) + return element != null + } + + override fun isRenaming(dataContext: DataContext): Boolean = isAvailableOnDataContext(dataContext) + + override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) { + CommonRefactoringUtil.showErrorHint( + project, + editor, + KotlinBundle.message("text.rename.is.not.applicable.to.secondary.constructors"), + RefactoringBundle.message("rename.title"), + null + ) + } + + override fun invoke(project: Project, elements: Array, dataContext: DataContext?) { + // Do nothing: this method is called not from editor + } +} + +class A { + constructor() { + + } +} \ No newline at end of file From 0a145a17324cc9bfd10851927f04816827378a15 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 26 Jun 2023 16:43:58 +0200 Subject: [PATCH 041/226] [kotlin] changes usages of hardcoded "it" parameter to StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME GitOrigin-RevId: c33aafb26a5264d11793452d92ebb28d6ce9cf70 --- .../inspections/EqualsOrHashCodeInspection.kt | 3 ++- .../intentions/ConvertForEachToForLoopIntention.kt | 3 ++- .../kotlin/idea/quickDoc/KotlinDocumentationTarget.kt | 3 ++- .../quickfix/fixes/WrapWithSafeLetCallFixFactories.kt | 5 +++-- .../jetbrains/kotlin/idea/KotlinDocumentationProvider.kt | 5 +++-- .../generate/KotlinGenerateEqualsAndHashcodeAction.kt | 3 ++- .../kotlin/idea/codeInliner/CodeToInlineBuilder.kt | 3 ++- .../jetbrains/kotlin/idea/codeInliner/introduceValue.kt | 5 +++-- .../similarity/KotlinSimilarityFeaturesExtractor.kt | 3 ++- .../kotlin/idea/highlighter/KotlinRainbowVisitor.kt | 3 ++- .../NestedLambdaShadowedImplicitParameterInspection.kt | 7 ++++--- .../idea/inspections/RedundantLambdaArrowInspection.kt | 7 ++++--- .../kotlin/idea/inspections/RedundantLetInspection.kt | 3 ++- .../inspections/ScopeFunctionConversionInspection.kt | 9 +++++---- .../SimplifyNestedEachInScopeFunctionInspection.kt | 5 +++-- .../collections/SimplifiableCallInspection.kt | 3 ++- .../kotlin/idea/inspections/dfa/KtVariableDescriptor.kt | 3 ++- .../idea/intentions/ConvertForEachToForLoopIntention.kt | 3 ++- .../ConvertFunctionTypeReceiverToParameterIntention.kt | 3 ++- .../idea/intentions/ConvertReferenceToLambdaIntention.kt | 3 ++- .../intentions/ConvertToIndexedFunctionCallIntention.kt | 5 +++-- .../kotlin/idea/intentions/ConvertToScopeIntention.kt | 3 ++- .../kotlin/idea/intentions/DestructureIntention.kt | 3 ++- ...ReplaceExplicitFunctionLiteralParamWithItIntention.kt | 5 +++-- .../intentions/branchedTransformations/IfThenUtils.kt | 3 ++- .../kotlin/idea/intentions/loopToCallChain/utils.kt | 5 +++-- .../kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt | 3 ++- .../kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt | 3 ++- .../ideaExtensions/FE10KotlinTargetElementEvaluator.kt | 3 ++- .../src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt | 5 +++-- .../kotlin/nj2k/conversions/BuiltinMembersConversion.kt | 2 +- .../org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt | 3 ++- .../handlers/RenameKotlinImplicitLambdaParameter.kt | 3 ++- 33 files changed, 80 insertions(+), 48 deletions(-) diff --git a/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/EqualsOrHashCodeInspection.kt b/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/EqualsOrHashCodeInspection.kt index 635121274035..375726ef96af 100644 --- a/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/EqualsOrHashCodeInspection.kt +++ b/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/EqualsOrHashCodeInspection.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.Modality @@ -286,7 +287,7 @@ class EqualsOrHashCodeInspection : AbstractKotlinInspection() { type.isArrayOrPrimitiveArray() -> { val canUseArrayContentFunctions = targetClass.canUseArrayContentFunctions() val shouldWrapInLet = isNullable && !canUseArrayContentFunctions - val hashCodeArg = if (shouldWrapInLet) "it" else ref + val hashCodeArg = if (shouldWrapInLet) StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier else ref val hashCodeCall = generateArrayHashCodeCall(type, canUseArrayContentFunctions, hashCodeArg) if (shouldWrapInLet) "$ref?.let { $hashCodeCall }" else hashCodeCall } diff --git a/plugins/kotlin/code-insight/intentions-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/intentions/ConvertForEachToForLoopIntention.kt b/plugins/kotlin/code-insight/intentions-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/intentions/ConvertForEachToForLoopIntention.kt index 520657d5c42c..9be4023251bf 100644 --- a/plugins/kotlin/code-insight/intentions-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/intentions/ConvertForEachToForLoopIntention.kt +++ b/plugins/kotlin/code-insight/intentions-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/intentions/ConvertForEachToForLoopIntention.kt @@ -6,6 +6,7 @@ import com.intellij.openapi.project.Project import com.intellij.psi.SmartPsiElementPointer import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.codeinsight.api.applicable.intentions.AbstractKotlinApplicableIntentionWithContext import org.jetbrains.kotlin.idea.codeinsight.api.applicators.KotlinApplicabilityRange @@ -164,7 +165,7 @@ internal class ConvertForEachToForLoopIntention } else { factory.createExpressionByPattern( "for($0 in $1){ $2 }", - parameters.singleOrNull() ?: "it", + parameters.singleOrNull() ?: StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier, loopRange, body.allChildren ) diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickDoc/KotlinDocumentationTarget.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickDoc/KotlinDocumentationTarget.kt index e1234b62a816..6a00bf886f91 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickDoc/KotlinDocumentationTarget.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickDoc/KotlinDocumentationTarget.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.idea.KotlinIcons import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.kdoc.* @@ -83,7 +84,7 @@ internal class KotlinDocumentationTarget(val element: PsiElement, private val or private fun computeLocalDocumentation(element: PsiElement, originalElement: PsiElement?, quickNavigation: Boolean): String? { when { element is KtFunctionLiteral -> { - val itElement = findElementWithText(originalElement, "it") + val itElement = findElementWithText(originalElement, StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier) val itReference = itElement?.getParentOfType(false) if (itReference != null) { return buildString { diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/WrapWithSafeLetCallFixFactories.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/WrapWithSafeLetCallFixFactories.kt index eb51ccb26242..c58cf50d5150 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/WrapWithSafeLetCallFixFactories.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/WrapWithSafeLetCallFixFactories.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.analysis.api.calls.* import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KtFirDiagnostic import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.receiverType +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.codeinsight.api.applicators.KotlinApplicator import org.jetbrains.kotlin.idea.codeinsight.api.applicators.KotlinApplicatorInput @@ -76,7 +77,7 @@ object WrapWithSafeLetCallFixFactories { fun getNewExpression(nullableExpressionText: String, expressionUnderLetText: String): KtExpression { return when (suggestedVariableName) { - "it" -> psiFactory.createExpressionByPattern("$0?.let { $1 }", nullableExpressionText, expressionUnderLetText) + StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier -> psiFactory.createExpressionByPattern("$0?.let { $1 }", nullableExpressionText, expressionUnderLetText) else -> psiFactory.createExpressionByPattern( "$0?.let { $1 -> $2 }", nullableExpressionText, @@ -211,7 +212,7 @@ object WrapWithSafeLetCallFixFactories { // Note, the order of the candidate matters. We would prefer the default `it` so the generated code won't need to declare the // variable explicitly. - val candidateNames = listOfNotNull("it", getDeclaredParameterNameForArgument(nullableExpression)) + val candidateNames = listOfNotNull(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier, getDeclaredParameterNameForArgument(nullableExpression)) val suggestedName = FirKotlinNameSuggester.suggestNameByMultipleNames(candidateNames) { it !in existingNames } return listOf( KotlinApplicatorBasedQuickFix( diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProvider.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProvider.kt index 956c968abffe..f55131d30edc 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProvider.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProvider.kt @@ -28,6 +28,7 @@ import com.intellij.util.io.HttpRequests import org.jetbrains.annotations.Nls import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.base.util.KotlinPlatformUtils @@ -337,7 +338,7 @@ class KotlinDocumentationProvider : AbstractDocumentationProvider(), ExternalDoc @Nls private fun getTextImpl(element: PsiElement, originalElement: PsiElement?, quickNavigation: Boolean): String? { if (element is PsiWhiteSpace) { - val itElement = findElementWithText(originalElement, "it") + val itElement = findElementWithText(originalElement, StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier) val itReference = itElement?.getParentOfType(false) if (itReference != null) { return getTextImpl(itReference, originalElement, quickNavigation) @@ -377,7 +378,7 @@ class KotlinDocumentationProvider : AbstractDocumentationProvider(), ExternalDoc } } else if (element is KtDeclaration) { return renderKotlinDeclaration(element, quickNavigation) - } else if (element is KtNameReferenceExpression && element.getReferencedName() == "it") { + } else if (element is KtNameReferenceExpression && element.getReferencedNameAsName() == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) { return renderKotlinImplicitLambdaParameter(element, quickNavigation) } else if (element is KtLightDeclaration<*, *>) { val origin = element.kotlinOrigin ?: return null diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/generate/KotlinGenerateEqualsAndHashcodeAction.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/generate/KotlinGenerateEqualsAndHashcodeAction.kt index d1f08cdf2a61..14f5460f9da8 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/generate/KotlinGenerateEqualsAndHashcodeAction.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/generate/KotlinGenerateEqualsAndHashcodeAction.kt @@ -10,6 +10,7 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassDescriptor @@ -267,7 +268,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase { val canUseArrayContentFunctions = targetClass.canUseArrayContentFunctions() val shouldWrapInLet = isNullable && !canUseArrayContentFunctions - val hashCodeArg = if (shouldWrapInLet) "it" else ref + val hashCodeArg = if (shouldWrapInLet) StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier else ref val hashCodeCall = generateArrayHashCodeCall(this, canUseArrayContentFunctions, hashCodeArg) if (shouldWrapInLet) "$ref?.let { $hashCodeCall }" else hashCodeCall } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt index 3f0bc192f26c..076c393e18bf 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.idea.codeInliner import com.intellij.psi.util.elementType +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors @@ -225,7 +226,7 @@ class CodeToInlineBuilder( last = KtFunctionLiteral::class ) val hasUnresolvedItOrThis = factory == Errors.UNRESOLVED_REFERENCE && - element.text == "it" && + element.text == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier && element.getStrictParentOfType() == functionLiteral hasCantInferParameter || hasUnresolvedItOrThis diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/codeInliner/introduceValue.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/codeInliner/introduceValue.kt index 8b0959ed4807..0b7f26bab887 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/codeInliner/introduceValue.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/codeInliner/introduceValue.kt @@ -2,6 +2,7 @@ package org.jetbrains.kotlin.idea.codeInliner +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.idea.base.fe10.codeInsight.newDeclaration.Fe10KotlinNameSuggester import org.jetbrains.kotlin.idea.caches.resolve.computeTypeInContext @@ -94,8 +95,8 @@ internal fun MutableCodeToInline.introduceValue( statementsBefore.add(0, value) } } else { - val useIt = !isNameUsed("it") - val name = if (useIt) Name.identifier("it") else suggestName { !isNameUsed(it) } + val useIt = !isNameUsed(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier) + val name = if (useIt) StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME else suggestName { !isNameUsed(it) } replaceUsages(name) mainExpression = psiFactory.buildExpression { diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/findUsages/similarity/KotlinSimilarityFeaturesExtractor.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/findUsages/similarity/KotlinSimilarityFeaturesExtractor.kt index e76299a356f6..c85f43440822 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/findUsages/similarity/KotlinSimilarityFeaturesExtractor.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/findUsages/similarity/KotlinSimilarityFeaturesExtractor.kt @@ -6,6 +6,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.usages.similarity.bag.Bag import com.intellij.usages.similarity.features.UsageSimilarityFeaturesRecorder +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.psi.* class KotlinSimilarityFeaturesExtractor(element: PsiElement, private val context: PsiElement) : KtTreeVisitorVoid() { @@ -127,7 +128,7 @@ class KotlinSimilarityFeaturesExtractor(element: PsiElement, private val context private fun collectFunctionParametersNames(function: KtFunction) { if (function is KtFunctionLiteral) { - variableNames += "it" + variableNames += StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier } for (valueParameter in function.valueParameters) { diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowVisitor.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowVisitor.kt index 74a89a06bf7c..65070ca8dfed 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowVisitor.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowVisitor.kt @@ -8,6 +8,7 @@ import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.* import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.search.ideaExtensions.FE10KotlinTargetElementEvaluator @@ -47,7 +48,7 @@ class KotlinRainbowVisitor : RainbowVisitor() { if (targetElement.isRainbowDeclaration()) { addRainbowHighlight(targetElement, element) } - } else if (element.getReferencedName() == "it") { + } else if (element.getReferencedNameAsName() == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) { val itTargetElement = KOTLIN_TARGET_ELEMENT_EVALUATOR.getElementByReference(reference, TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/NestedLambdaShadowedImplicitParameterInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/NestedLambdaShadowedImplicitParameterInspection.kt index e95885fa91b7..17cd343b8db6 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/NestedLambdaShadowedImplicitParameterInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/NestedLambdaShadowedImplicitParameterInspection.kt @@ -6,6 +6,7 @@ import com.intellij.codeInspection.* import com.intellij.openapi.project.Project import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze @@ -46,7 +47,7 @@ class NestedLambdaShadowedImplicitParameterInspection : AbstractKotlinInspection if (qualifiedExpression != null) { val receiver = qualifiedExpression.receiverExpression val call = qualifiedExpression.callExpression - if (receiver.text == "it" && call?.isCalling(scopeFunctions, context) == true) return + if (receiver.text == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier && call?.isCalling(scopeFunctions, context) == true) return } val containingFile = lambda.containingFile @@ -74,7 +75,7 @@ class NestedLambdaShadowedImplicitParameterInspection : AbstractKotlinInspection val lambda = implicitParameterReference.getStrictParentOfType() ?: return val parentLambda = lambda.getParentImplicitParameterLambda() ?: return val parameter = parentLambda.functionLiteral.getOrCreateParameterList().addParameterBefore( - KtPsiFactory(project).createLambdaParameterList("it").parameters.first(), null + KtPsiFactory(project).createLambdaParameterList(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier).parameters.first(), null ) val editor = parentLambda.findExistingEditor() ?: return PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document) @@ -103,7 +104,7 @@ private fun KtNameReferenceExpression.isImplicitParameterReference( implicitParameter: ValueParameterDescriptor, context: BindingContext ): Boolean { - return text == "it" + return text == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier && getStrictParentOfType() == lambda && getResolvedCall(context)?.resultingDescriptor == implicitParameter } \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantLambdaArrowInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantLambdaArrowInspection.kt index 6b00bde45a6e..8f259c270b02 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantLambdaArrowInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantLambdaArrowInspection.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall +import org.jetbrains.kotlin.builtins.StandardNames class RedundantLambdaArrowInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { @@ -32,7 +33,7 @@ class RedundantLambdaArrowInspection : AbstractKotlinInspection() { val parameters = functionLiteral.valueParameters val singleParameter = parameters.singleOrNull() if (singleParameter?.typeReference != null) return - if (parameters.isNotEmpty() && singleParameter?.name != "it") { + if (parameters.isNotEmpty() && singleParameter?.nameAsName != StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) { return } @@ -42,7 +43,7 @@ class RedundantLambdaArrowInspection : AbstractKotlinInspection() { val callExpression = lambdaExpression.parent?.parent as? KtCallExpression if (callExpression != null) { val callee = callExpression.calleeExpression as? KtNameReferenceExpression - if (callee != null && callee.getReferencedName() == "forEach" && singleParameter?.name != "it") return + if (callee != null && callee.getReferencedName() == "forEach" && singleParameter?.nameAsName != StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) return } val lambdaContext = lambdaExpression.analyze() @@ -55,7 +56,7 @@ class RedundantLambdaArrowInspection : AbstractKotlinInspection() { val functionLiteralDescriptor = functionLiteral.descriptor if (functionLiteralDescriptor != null) { if (functionLiteral.anyDescendantOfType { - it.text == "it" && it.resolveToCall()?.resultingDescriptor?.containingDeclaration != functionLiteralDescriptor + it.text == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier && it.resolveToCall()?.resultingDescriptor?.containingDeclaration != functionLiteralDescriptor }) return } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantLetInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantLetInspection.kt index 8d98845a142d..3ffea90dc45e 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantLetInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantLetInspection.kt @@ -6,6 +6,7 @@ import com.intellij.codeInspection.ProblemHighlightType import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.idea.base.psi.isMultiLine @@ -227,7 +228,7 @@ private fun KtDotQualifiedExpression.hasLambdaExpression() = selectorExpression? private fun KtLambdaExpression.getParameterName(): String? { val parameters = valueParameters if (parameters.size > 1) return null - return if (parameters.size == 1) parameters[0].text else "it" + return if (parameters.size == 1) parameters[0].text else StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier } private fun KtExpression.nameUsed(name: String, except: KtNameReferenceExpression? = null): Boolean = diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ScopeFunctionConversionInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ScopeFunctionConversionInspection.kt index b0f8ed1ccc46..eefbb7a13bce 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ScopeFunctionConversionInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ScopeFunctionConversionInspection.kt @@ -9,6 +9,7 @@ import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor import com.intellij.psi.SmartPsiElementPointer +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.idea.base.resources.KotlinBundle @@ -188,7 +189,7 @@ class ConvertScopeFunctionToParameter(counterpartName: String) : ConvertScopeFun val lambdaExtensionReceiver = lambdaDescriptor.extensionReceiverParameter val lambdaDispatchReceiver = lambdaDescriptor.dispatchReceiverParameter - var parameterName = "it" + var parameterName = StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier val scopes = mutableSetOf() if (functionLiteral != null && needUniqueNameForParameter(lambda, scopes)) { val parameterType = lambdaExtensionReceiver?.type ?: lambdaDispatchReceiver?.type @@ -255,7 +256,7 @@ class ConvertScopeFunctionToParameter(counterpartName: String) : ConvertScopeFun val resolutionScope = lambdaArgument.getResolutionScope() scopes.add(resolutionScope) var needUniqueName = false - if (resolutionScope.findVariable(Name.identifier("it"), NoLookupLocation.FROM_IDE) != null) { + if (resolutionScope.findVariable(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME, NoLookupLocation.FROM_IDE) != null) { needUniqueName = true // Don't return here - we still need to gather the list of nested scopes } @@ -274,7 +275,7 @@ class ConvertScopeFunctionToParameter(counterpartName: String) : ConvertScopeFun private fun checkNeedUniqueName(dcl: KtElement) { val nestedResolutionScope = dcl.getResolutionScope() scopes.add(nestedResolutionScope) - if (nestedResolutionScope.findVariable(Name.identifier("it"), NoLookupLocation.FROM_IDE) != null) { + if (nestedResolutionScope.findVariable(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME, NoLookupLocation.FROM_IDE) != null) { needUniqueName = true } } @@ -310,7 +311,7 @@ class ConvertScopeFunctionToReceiver(counterpartName: String) : ConvertScopeFunc lambda.accept(object : KtTreeVisitorVoid() { override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { super.visitSimpleNameExpression(expression) - if (expression.getReferencedName() == "it") { + if (expression.getReferencedNameAsName() == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) { val result = expression.resolveMainReferenceToDescriptors().singleOrNull() if (result is ValueParameterDescriptor && result.containingDeclaration == lambdaDescriptor) { replacements.add(expression) { createThisExpression() } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/SimplifyNestedEachInScopeFunctionInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/SimplifyNestedEachInScopeFunctionInspection.kt index 74f7dc07fcf0..bf0c9abb800f 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/SimplifyNestedEachInScopeFunctionInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/SimplifyNestedEachInScopeFunctionInspection.kt @@ -7,6 +7,7 @@ import com.intellij.codeInspection.ProblemDescriptor import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.idea.base.resources.KotlinBundle @@ -133,10 +134,10 @@ class SimplifyNestedEachInScopeFunctionInspection : AbstractKotlinInspection() { if (innerExpression !is KtDotQualifiedExpression) return val receiverExpression = innerExpression.receiverExpression if (receiverExpression !is KtReferenceExpression) return - val parameterName = lambdaExpression.valueParameters.singleOrNull()?.name ?: "it" + val parameterName = lambdaExpression.valueParameters.singleOrNull()?.name ?: StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier if (!receiverExpression.textMatches(parameterName)) return - if (forEachLambda != null && (forEachLambda.valueParameters.singleOrNull()?.name ?: "it") == parameterName) { + if (forEachLambda != null && (forEachLambda.valueParameters.singleOrNull()?.name ?: StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier) == parameterName) { null // Parameter from outer lambda is shadowed } else { val lambdaDescriptor = lambdaExpression.descriptor(context) ?: return diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/collections/SimplifiableCallInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/collections/SimplifiableCallInspection.kt index 5d6fb906d9d4..7e710044db5b 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/collections/SimplifiableCallInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/collections/SimplifiableCallInspection.kt @@ -10,6 +10,7 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isArray import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveArray +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall @@ -143,7 +144,7 @@ private fun KtLambdaExpression.singleStatement(): KtExpression? = bodyExpression private fun KtLambdaExpression.singleLambdaParameterName(): String? { val lambdaParameters = valueParameters - return if (lambdaParameters.isNotEmpty()) lambdaParameters.singleOrNull()?.name else "it" + return if (lambdaParameters.isNotEmpty()) lambdaParameters.singleOrNull()?.name else StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier } private fun KtExpression.isNameReferenceTo(name: String): Boolean = diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/dfa/KtVariableDescriptor.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/dfa/KtVariableDescriptor.kt index 527e6428b23f..890b3d5068e5 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/dfa/KtVariableDescriptor.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/dfa/KtVariableDescriptor.kt @@ -8,6 +8,7 @@ import com.intellij.codeInspection.dataFlow.value.DfaVariableValue import com.intellij.psi.PsiElement import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor @@ -151,7 +152,7 @@ class KtVariableDescriptor(val variable: KtCallableDeclaration) : JvmVariableDes } } } - if (expr.textMatches("it")) { + if (expr.textMatches(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier)) { val descriptor = expr.resolveMainReferenceToDescriptors().singleOrNull() if (descriptor is ValueParameterDescriptor) { val fn = (descriptor.containingDeclaration.toSourceElement as? KotlinSourceElement)?.psi diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertForEachToForLoopIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertForEachToForLoopIntention.kt index 8b08ad304ed1..e20ed1d9ccb9 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertForEachToForLoopIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertForEachToForLoopIntention.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.openapi.editor.Editor +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.codeinsight.api.classic.intentions.SelfTargetingOffsetIndependentIntention @@ -120,7 +121,7 @@ class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIntention } else { psiFactory.createExpressionByPattern( "for($0 in $1){ $2 }", - parameters.singleOrNull() ?: "it", + parameters.singleOrNull() ?: StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier, loopRange, body.allChildren ) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertFunctionTypeReceiverToParameterIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertFunctionTypeReceiverToParameterIntention.kt index 7b925c9ff6a6..5961394080d5 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertFunctionTypeReceiverToParameterIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertFunctionTypeReceiverToParameterIntention.kt @@ -13,6 +13,7 @@ import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.refactoring.util.RefactoringUIUtil import com.intellij.util.containers.MultiMap +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic @@ -155,7 +156,7 @@ class ConvertFunctionTypeReceiverToParameterIntention : SelfTargetingRangeIntent val lambdaParameterList = lambda.getOrCreateParameterList() if (lambda.valueParameters.isEmpty() && lambdaDescriptor.valueParameters.isNotEmpty()) { - val parameterToAdd = psiFactory.createLambdaParameterList("it").parameters.first() + val parameterToAdd = psiFactory.createLambdaParameterList(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier).parameters.first() lambdaParameterList.addParameterBefore(parameterToAdd, lambdaParameterList.parameters.firstOrNull()) } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertReferenceToLambdaIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertReferenceToLambdaIntention.kt index 35683dbf6728..539251af5ab9 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertReferenceToLambdaIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertReferenceToLambdaIntention.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.openapi.editor.Editor import com.intellij.psi.util.elementType import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames.KOTLIN_REFLECT_FQ_NAME import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor @@ -110,7 +111,7 @@ class ConvertReferenceToLambdaIntention : SelfTargetingOffsetIndependentIntentio val lambdaExpression = if (valueArgumentParent != null && lambdaParameterNamesAndTypes.size == 1 && - receiverExpression?.text != "it" + receiverExpression?.text != StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier ) { val body = if (acceptsReceiverAsParameter) { if (targetDescriptor is PropertyDescriptor) "it.$targetName" diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToIndexedFunctionCallIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToIndexedFunctionCallIntention.kt index e70af7749b70..cf5fafca5d13 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToIndexedFunctionCallIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToIndexedFunctionCallIntention.kt @@ -5,10 +5,11 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.openapi.editor.Editor import com.intellij.openapi.util.TextRange import com.intellij.psi.codeStyle.CodeStyleManager +import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.base.codeInsight.KotlinNameSuggestionProvider import org.jetbrains.kotlin.idea.base.fe10.codeInsight.newDeclaration.Fe10KotlinNameSuggester import org.jetbrains.kotlin.idea.base.fe10.codeInsight.newDeclaration.Fe10KotlinNewDeclarationNameValidator -import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.codeinsight.api.classic.intentions.SelfTargetingRangeIntention import org.jetbrains.kotlin.idea.core.CollectingNameValidator @@ -66,7 +67,7 @@ class ConvertToIndexedFunctionCallIntention : SelfTargetingRangeIntention declaration.nameAsName is KtVariableDeclaration -> declaration.nameAsName - else -> Name.identifier("it") + else -> StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME } ?: return null // Note: list should contain properties in order to create destructuring declaration diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceExplicitFunctionLiteralParamWithItIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceExplicitFunctionLiteralParamWithItIntention.kt index 2b31a57844f3..8fcb34f331e8 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceExplicitFunctionLiteralParamWithItIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceExplicitFunctionLiteralParamWithItIntention.kt @@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.refactoring.rename.RenameProcessor import com.intellij.usageView.UsageInfo +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.idea.base.resources.KotlinBundle @@ -35,7 +36,7 @@ class ReplaceExplicitFunctionLiteralParamWithItIntention : PsiElementBaseIntenti if (parameter.destructuringDeclaration != null) return false if (functionLiteral.anyDescendantOfType { literal -> - literal.usesName(element.text) && (!literal.hasParameterSpecification() || literal.usesName("it")) + literal.usesName(element.text) && (!literal.hasParameterSpecification() || literal.usesName(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier)) }) return false val lambda = functionLiteral.parent as? KtLambdaExpression ?: return false @@ -93,7 +94,7 @@ class ReplaceExplicitFunctionLiteralParamWithItIntention : PsiElementBaseIntenti ) : RenameProcessor( editor.project!!, functionLiteral.valueParameters.single(), - "it", + StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier, false, false ) { diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt index 1b84c049d2ce..074674f91b14 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.ReferencesSearch import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.idea.base.fe10.codeInsight.newDeclaration.Fe10KotlinNameSuggester @@ -287,7 +288,7 @@ data class IfThenToSelectData( receiver: KtExpression, factory: KtPsiFactory ): KtExpression { - val needExplicitParameter = valueArguments.any { it.getArgumentExpression()?.text == "it" } + val needExplicitParameter = valueArguments.any { it.getArgumentExpression()?.text == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier } val parameterName = if (needExplicitParameter) { val scope = getResolutionScope() Fe10KotlinNameSuggester.suggestNameByName("it") { scope.findVariable(Name.identifier(it), NoLookupLocation.FROM_IDE) == null } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt index cf48207a6467..59a55e6240d0 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.intentions.loopToCallChain import com.intellij.openapi.util.Key import com.intellij.openapi.util.UserDataHolderBase import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor @@ -40,14 +41,14 @@ fun generateLambda(inputVariable: KtCallableDeclaration, expression: KtExpressio ) as KtLambdaExpression val isItUsedInside = expression.anyDescendantOfType { - it.getQualifiedExpressionForSelector() == null && it.getReferencedName() == "it" + it.getQualifiedExpressionForSelector() == null && it.getReferencedNameAsName() == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME } if (isItUsedInside) return lambdaExpression val usages = lambdaExpression.findParameterUsages(lambdaExpression.valueParameters.single(), inputVariable) - val itExpr = psiFactory.createSimpleName("it") + val itExpr = psiFactory.createSimpleName(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier) for (usage in usages) { val replaced = usage.replaced(itExpr) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt index 0499a6dbf710..d334692d0fcb 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED import org.jetbrains.kotlin.descriptors.ConstructorDescriptor @@ -69,7 +70,7 @@ abstract class ChangeFunctionSignatureFix( } private fun isSpecialName(name: String): Boolean { - return name == "it" || name == "field" + return name == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier || name == "field" } companion object : KotlinSingleIntentionActionFactoryWithDelegate() { diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt index fd86a580817b..af598c9d11d6 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt @@ -6,6 +6,7 @@ import com.intellij.codeInsight.intention.HighPriorityAction import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.base.resources.KotlinBundle @@ -51,7 +52,7 @@ class WrapWithSafeLetCallFix( nullableExpression, KotlinNameSuggestionProvider.ValidatorTarget.PARAMETER ) - val name = Fe10KotlinNameSuggester.suggestNameByName("it", validator) + val name = Fe10KotlinNameSuggester.suggestNameByName(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier, validator) nullableExpression.replace(psiFactory.createExpression(name)) val underLetExpression = when { diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/FE10KotlinTargetElementEvaluator.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/FE10KotlinTargetElementEvaluator.kt index c78d5346dba3..a1879bd5f3ba 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/FE10KotlinTargetElementEvaluator.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/FE10KotlinTargetElementEvaluator.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.search.ideaExtensions import com.intellij.psi.PsiElement import com.intellij.psi.PsiReference +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors @@ -20,7 +21,7 @@ class FE10KotlinTargetElementEvaluator : KotlinTargetElementEvaluator() { companion object { fun findLambdaOpenLBraceForGeneratedIt(ref: PsiReference): PsiElement? { val element: PsiElement = ref.element - if (element.text != "it") return null + if (element.text != StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier) return null if (element !is KtNameReferenceExpression || !element.isReferenceToImplicitLambdaParameter()) return null diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt index 67100f673743..e75695dc3047 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt @@ -9,6 +9,7 @@ import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.slicer.SliceUsage import com.intellij.usageView.UsageInfo import com.intellij.util.Processor +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* @@ -231,7 +232,7 @@ class InflowSlicer( is ValueParameterDescriptor -> { if (accessedDeclaration == null) { val anonymousFunction = accessedDescriptor.containingDeclaration as? AnonymousFunctionDescriptor - if (anonymousFunction != null && accessedDescriptor.name.asString() == "it") { + if (anonymousFunction != null && accessedDescriptor.name == StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) { val functionLiteral = anonymousFunction.source.getPsi() as KtFunctionLiteral val parameterDescriptor = anonymousFunction.valueParameters.first() processCalls(functionLiteral, false, ArgumentSliceProducer(parameterDescriptor)) @@ -379,7 +380,7 @@ class InflowSlicer( private fun KtFunctionLiteral.implicitItUsages(): Collection { return collectDescendantsOfType(fun(expression: KtSimpleNameExpression): Boolean { - if (expression.getQualifiedExpressionForSelector() != null || expression.getReferencedName() != "it") return false + if (expression.getQualifiedExpressionForSelector() != null || expression.getReferencedNameAsName() != StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) return false val lBrace = FE10KotlinTargetElementEvaluator.findLambdaOpenLBraceForGeneratedIt(expression.mainReference) ?: return false return lBrace == this.lBrace.node.treeNext.psi }) diff --git a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/conversions/BuiltinMembersConversion.kt b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/conversions/BuiltinMembersConversion.kt index 1226a8a878f9..02e7299ef0af 100644 --- a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/conversions/BuiltinMembersConversion.kt +++ b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/conversions/BuiltinMembersConversion.kt @@ -553,7 +553,7 @@ private class ConversionsHolder(private val symbolProvider: JKSymbolProvider, pr JKExpressionStatement( JKBinaryExpression( //TODO replace with `it` parameter - JKFieldAccessExpression(JKUnresolvedField("it", typeFactory)), + JKFieldAccessExpression(JKUnresolvedField(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier, typeFactory)), JKLiteralExpression("' '", JKLiteralExpression.LiteralType.CHAR), JKKtOperatorImpl(JKOperatorToken.LTEQ, typeFactory.types.boolean) ) diff --git a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt index b070d18e3438..1349df507f67 100644 --- a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt +++ b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt @@ -2,6 +2,7 @@ package org.jetbrains.kotlin.nj2k.printing +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.nj2k.* import org.jetbrains.kotlin.nj2k.printing.JKPrinterBase.ParenthesisKind import org.jetbrains.kotlin.nj2k.symbols.getDisplayFqName @@ -572,7 +573,7 @@ internal class JKCodeBuilder(context: NewJ2kConverterContext) { } override fun visitKtItExpressionRaw(ktItExpression: JKKtItExpression) { - printer.print("it") + printer.print(StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME.identifier) } override fun visitClassBodyRaw(classBody: JKClassBody) { diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameKotlinImplicitLambdaParameter.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameKotlinImplicitLambdaParameter.kt index da891e7f4ea4..385395350b57 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameKotlinImplicitLambdaParameter.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameKotlinImplicitLambdaParameter.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.analysis.api.analyze import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousFunctionSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.codeinsight.utils.getFunctionLiteralByImplicitLambdaParameter import org.jetbrains.kotlin.idea.codeinsight.utils.isReferenceToImplicitLambdaParameter @@ -54,7 +55,7 @@ class RenameKotlinImplicitLambdaParameter : KotlinVariableInplaceRenameHandler() private fun KtNameReferenceExpression.createExplicitLambdaParameterByImplicitOne(editor: Editor): KtParameter? { - if (getReferencedName() != "it") return null + if (getReferencedNameAsName() != StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME) return null val functionLiteral = getFunctionLiteralByImplicitLambdaParameter() ?: return null val project = project From 7bc2814cc3dc643e8fdb5eed80e039da9f641333 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Tue, 27 Jun 2023 12:26:29 +0200 Subject: [PATCH 042/226] [kotlin] refactoring, extract the base part of RenameSyntheticDeclarationByReferenceHandler to abstract class GitOrigin-RevId: fb1bf506fd2964dc28fba707d327d230b962ce2a --- .../kotlin.refactorings.common.iml | 16 +++++ ...tForbidRenamingSymbolByReferenceHandler.kt | 59 +++++++++++++++++++ ...eSyntheticDeclarationByReferenceHandler.kt | 52 ++++------------ 3 files changed, 85 insertions(+), 42 deletions(-) create mode 100644 plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/AbstractForbidRenamingSymbolByReferenceHandler.kt diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/kotlin.refactorings.common.iml b/plugins/kotlin/refactorings/kotlin.refactorings.common/kotlin.refactorings.common.iml index b7e41409b8a5..c8669bb14b17 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.common/kotlin.refactorings.common.iml +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/kotlin.refactorings.common.iml @@ -1,5 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/AbstractForbidRenamingSymbolByReferenceHandler.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/AbstractForbidRenamingSymbolByReferenceHandler.kt new file mode 100644 index 000000000000..80876d1a8e2b --- /dev/null +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/AbstractForbidRenamingSymbolByReferenceHandler.kt @@ -0,0 +1,59 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.refactoring.rename.handlers + +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.NlsContexts.DialogMessage +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.refactoring.RefactoringBundle +import com.intellij.refactoring.rename.RenameHandler +import com.intellij.refactoring.util.CommonRefactoringUtil +import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.KtSimpleNameExpression + +internal abstract class AbstractForbidRenamingSymbolByReferenceHandler : RenameHandler { + override fun isAvailableOnDataContext(dataContext: DataContext): Boolean { + val file = CommonDataKeys.PSI_FILE.getData(dataContext) ?: return false + val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return false + val refExpression = file.findElementForRename(editor.caretModel.offset) ?: return false + @OptIn(KtAllowAnalysisOnEdt::class) + allowAnalysisOnEdt { + analyze(refExpression) { + val target = refExpression.mainReference.resolveToSymbol() ?: return false + return shouldForbidRenaming(target) + } + } + } + + context(KtAnalysisSession) + abstract fun shouldForbidRenaming(symbol: KtSymbol): Boolean + + abstract fun getErrorMessage(): @DialogMessage String + + override fun isRenaming(dataContext: DataContext) = isAvailableOnDataContext(dataContext) + + override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) { + CommonRefactoringUtil.showErrorHint( + project, + editor, + getErrorMessage(), + RefactoringBundle.message("rename.title"), + null + ) + } + + override fun invoke(project: Project, elements: Array, dataContext: DataContext?) { + // Do nothing: this method is not called from editor + } +} diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameSyntheticDeclarationByReferenceHandler.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameSyntheticDeclarationByReferenceHandler.kt index a403ba58e24a..350df0b8698d 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameSyntheticDeclarationByReferenceHandler.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameSyntheticDeclarationByReferenceHandler.kt @@ -1,51 +1,19 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.refactoring.rename.handlers -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.refactoring.RefactoringBundle -import com.intellij.refactoring.rename.RenameHandler -import com.intellij.refactoring.util.CommonRefactoringUtil -import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt -import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt +import com.intellij.openapi.util.NlsContexts.DialogMessage +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin import org.jetbrains.kotlin.idea.base.resources.KotlinBundle -import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename -import org.jetbrains.kotlin.idea.references.mainReference -import org.jetbrains.kotlin.psi.KtSimpleNameExpression -class RenameSyntheticDeclarationByReferenceHandler : RenameHandler { - override fun isAvailableOnDataContext(dataContext: DataContext): Boolean { - val file = CommonDataKeys.PSI_FILE.getData(dataContext) ?: return false - val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return false - val refExpression = file.findElementForRename(editor.caretModel.offset) ?: return false - @OptIn(KtAllowAnalysisOnEdt::class) - allowAnalysisOnEdt { - analyze(refExpression) { - val target = refExpression.mainReference.resolveToSymbol() ?: return false - return target.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED - } +internal class RenameSyntheticDeclarationByReferenceHandler : AbstractForbidRenamingSymbolByReferenceHandler() { + context(KtAnalysisSession) + override fun shouldForbidRenaming(symbol: KtSymbol): Boolean { + return symbol.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED } - } - override fun isRenaming(dataContext: DataContext) = isAvailableOnDataContext(dataContext) - - override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) { - CommonRefactoringUtil.showErrorHint( - project, - editor, - KotlinBundle.message("text.rename.is.not.applicable.to.synthetic.declarations"), - RefactoringBundle.message("rename.title"), - null - ) - } - - override fun invoke(project: Project, elements: Array, dataContext: DataContext?) { - // Do nothing: this method is not called from editor - } + override fun getErrorMessage(): @DialogMessage String { + return KotlinBundle.message("text.rename.is.not.applicable.to.synthetic.declarations") + } } From 6b8344e9eccea3b05c1c853736668cc059739e2d Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Tue, 27 Jun 2023 12:29:12 +0200 Subject: [PATCH 043/226] [kotlin] forbid renaming declarations generated by compiler plugin GitOrigin-RevId: c5dfafd964c1a4bf2dfeba6a2a72a60cb5cc6e58 --- .../messages/KotlinBundle.properties | 1 + .../resources/META-INF/refactorings.xml | 1 + ...ilerPluginDeclarationByReferenceHandler.kt | 19 +++++++++++++++++++ .../RenameOnSecondaryConstructorHandler.kt | 5 ----- 4 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameCompilerPluginDeclarationByReferenceHandler.kt diff --git a/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties b/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties index 8d89b669570b..3ad0ed7c597d 100644 --- a/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties +++ b/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties @@ -951,6 +951,7 @@ text.remove=remove text.rename.as.part.of.phrase=rename text.rename.is.not.applicable.to.secondary.constructors=Rename is not applicable to secondary constructors text.rename.is.not.applicable.to.synthetic.declarations=Rename is not applicable to synthetic declaration +text.rename.is.not.applicable.to.compiler.plugin.generated.declarations=Rename is not applicable to compiler plugin-generated declaration text.rename.not.applicable.to.backing.field.reference=Rename is not applicable to backing field reference text.rename.not.applicable.to.dynamically.invoked.methods=Rename is not applicable to dynamically invoked members text.rename.overloads.title=Rename Overloads diff --git a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml index 37898a15b0a3..51f2ec4cf4ba 100644 --- a/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml +++ b/plugins/kotlin/plugin/common/resources/META-INF/refactorings.xml @@ -55,6 +55,7 @@ + diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameCompilerPluginDeclarationByReferenceHandler.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameCompilerPluginDeclarationByReferenceHandler.kt new file mode 100644 index 000000000000..b6a990095fed --- /dev/null +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameCompilerPluginDeclarationByReferenceHandler.kt @@ -0,0 +1,19 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.refactoring.rename.handlers + +import com.intellij.openapi.util.NlsContexts.DialogMessage +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle + +internal class RenameCompilerPluginDeclarationByReferenceHandler : AbstractForbidRenamingSymbolByReferenceHandler() { + context(KtAnalysisSession) + override fun shouldForbidRenaming(symbol: KtSymbol): Boolean { + return symbol.origin == KtSymbolOrigin.PLUGIN + } + + override fun getErrorMessage(): @DialogMessage String { + return KotlinBundle.message("text.rename.is.not.applicable.to.compiler.plugin.generated.declarations") + } +} diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameOnSecondaryConstructorHandler.kt b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameOnSecondaryConstructorHandler.kt index 24c899555232..0500263a56fa 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameOnSecondaryConstructorHandler.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.common/src/org/jetbrains/kotlin/idea/refactoring/rename/handlers/RenameOnSecondaryConstructorHandler.kt @@ -51,8 +51,3 @@ class RenameOnSecondaryConstructorHandler : RenameHandler { } } -class A { - constructor() { - - } -} \ No newline at end of file From ac7953e2198123ac089104ad381d8f69bdab3418 Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Thu, 29 Jun 2023 11:14:56 +0400 Subject: [PATCH 044/226] [kotlin] J2K: fix file name It was renamed by mistake in f0253db7f55afba3c26f8525a8382956fb3b3a57 GitOrigin-RevId: aa4662b9c320c117824f0b1988eb9d1379083385 --- ...roovyDeclarationHighlightingPassFactory.kt => declarations.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/tree/{GroovyDeclarationHighlightingPassFactory.kt => declarations.kt} (100%) diff --git a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/tree/GroovyDeclarationHighlightingPassFactory.kt b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/tree/declarations.kt similarity index 100% rename from plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/tree/GroovyDeclarationHighlightingPassFactory.kt rename to plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/tree/declarations.kt From 3fc847074b36c743445daf6b6f0a177c0fe396d0 Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Thu, 29 Jun 2023 13:12:51 +0400 Subject: [PATCH 045/226] [kotlin] J2K: remove second invocation of CanBeValInspectionBasedProcessing This is an expensive processing, because it uses `ReferencesSearch.search`, and looks like one invocation is enough (no tests are affected). GitOrigin-RevId: cdfb45965b76219422ac6285748fd005a249acc1 --- .../kotlin/idea/j2k/post/processing/J2kPostProcessor.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt index 60c6f8fa7ca4..020ed28f9c9b 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt @@ -201,7 +201,6 @@ private val inspectionLikePostProcessingGroup = JavaObjectEqualsToEqOperatorProcessing(), RemoveExplicitPropertyTypeProcessing(), RemoveRedundantNullabilityProcessing(), - CanBeValInspectionBasedProcessing(), inspectionBasedProcessing(FoldInitializerAndIfToElvisInspection(), writeActionNeeded = false), inspectionBasedProcessing(JavaMapForEachInspection()), intentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() }, From f34395a6d50d04c126505fef10854e38120336cf Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Thu, 29 Jun 2023 13:34:08 +0400 Subject: [PATCH 046/226] [kotlin] J2K: cleanup test GitOrigin-RevId: 5d71101be7327e78d4f1a3e186feabba42e7acaa --- .../testData/copyPastePlainText/MembersIntoClass.expected.kt | 2 +- .../copyPastePlainText/MembersIntoClass.to.kt.expected | 3 --- .../new/tests/testData/copyPastePlainText/MembersIntoClass.txt | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.to.kt.expected diff --git a/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.expected.kt b/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.expected.kt index 7d8a9aa2da86..37b88fe20109 100644 --- a/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.expected.kt +++ b/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.expected.kt @@ -1,7 +1,7 @@ class A { fun foo() { val list = ArrayList() - list.add(1) + list.add("1") } fun bar() {} diff --git a/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.to.kt.expected b/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.to.kt.expected deleted file mode 100644 index 9515b31e1d97..000000000000 --- a/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.to.kt.expected +++ /dev/null @@ -1,3 +0,0 @@ -class A { - -} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.txt b/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.txt index b028b2d8735b..9c186610212e 100644 --- a/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.txt +++ b/plugins/kotlin/j2k/new/tests/testData/copyPastePlainText/MembersIntoClass.txt @@ -1,6 +1,6 @@ void foo() { ArrayList list = new ArrayList(); - list.add(1); + list.add("1"); } void bar() { From 94fe30af7d71aa23095a1bdb845fb2c6e4197aa5 Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Thu, 29 Jun 2023 15:45:15 +0400 Subject: [PATCH 047/226] [kotlin] J2K: don't apply inspection-based processing in information level mode If it is not highlighted as a warning in the editor, don't convert it automatically. IfThenToSafeAccessInspection IfThenToElvisInspection GitOrigin-RevId: dd81f19eca90f08520b51352879ba1f487add217 --- .../intentions/branchedTransformations/IfThenUtils.kt | 2 +- .../newJ2k/nullability/MethodResultComparedWithNull2.kt | 6 ++++-- .../newJ2k/nullability/MethodResultComparedWithNull3.kt | 6 ++++-- .../newJ2k/nullability/MethodResultComparedWithNull4.kt | 6 ++++-- .../newJ2k/nullability/ParameterComparedWithNull.kt | 6 ++++-- .../newJ2k/nullability/VariableComparedWithNull.kt | 6 ++++-- .../kotlin/idea/j2k/post/processing/J2kPostProcessor.kt | 9 +++++++-- 7 files changed, 28 insertions(+), 13 deletions(-) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt index 1b84c049d2ce..66060f0eb841 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt @@ -352,7 +352,7 @@ internal fun KtIfExpression.buildSelectTransformationData(): IfThenToSelectData? internal fun KtExpression?.isClauseTransformableToLetOnly(receiver: KtExpression?) = this is KtCallExpression && (resolveToCall()?.getImplicitReceiverValue() == null || receiver !is KtThisExpression) -internal fun KtIfExpression.shouldBeTransformed(): Boolean = when (val condition = condition) { +fun KtIfExpression.shouldBeTransformed(): Boolean = when (val condition = condition) { is KtBinaryExpression -> { val baseClause = (if (condition.operationToken == KtTokens.EQEQ) `else` else then)?.unwrapBlockOrParenthesis() !baseClause.isClauseTransformableToLetOnly(condition.checkedExpression()) diff --git a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull2.kt b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull2.kt index 030e81cd44fd..fd82538dbd58 100644 --- a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull2.kt +++ b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull2.kt @@ -5,6 +5,8 @@ internal interface I { internal class C { fun foo(i: I) { val result = i.string - result?.let { print(it) } + if (result != null) { + print(result) + } } -} \ No newline at end of file +} diff --git a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull3.kt b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull3.kt index 030e81cd44fd..fd82538dbd58 100644 --- a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull3.kt +++ b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull3.kt @@ -5,6 +5,8 @@ internal interface I { internal class C { fun foo(i: I) { val result = i.string - result?.let { print(it) } + if (result != null) { + print(result) + } } -} \ No newline at end of file +} diff --git a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull4.kt b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull4.kt index 5dd087d712e6..b0deb74e5312 100644 --- a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull4.kt +++ b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/MethodResultComparedWithNull4.kt @@ -6,6 +6,8 @@ internal class C { fun foo(i: I, b: Boolean) { var result = i.string if (b) result = null - result?.let { print(it) } + if (result != null) { + print(result) + } } -} \ No newline at end of file +} diff --git a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/ParameterComparedWithNull.kt b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/ParameterComparedWithNull.kt index 3fc71b3e365e..36220527aa42 100644 --- a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/ParameterComparedWithNull.kt +++ b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/ParameterComparedWithNull.kt @@ -1,3 +1,5 @@ fun foo(s: String?) { - s?.let { zoo(it) } -} \ No newline at end of file + if (s != null) { + zoo(s) + } +} diff --git a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/VariableComparedWithNull.kt b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/VariableComparedWithNull.kt index e04b405c60ff..bbd47b6f3c71 100644 --- a/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/VariableComparedWithNull.kt +++ b/plugins/kotlin/j2k/new/tests/testData/newJ2k/nullability/VariableComparedWithNull.kt @@ -5,5 +5,7 @@ fun bar(): String? { fun foo() { val s: String? = bar() - s?.let { zoo(it) } -} \ No newline at end of file + if (s != null) { + zoo(s) + } +} diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt index 020ed28f9c9b..b6178244fc42 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.idea.intentions.* import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnAsymmetricallyIntention import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnIntention import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isTrivialStatementBody +import org.jetbrains.kotlin.idea.intentions.branchedTransformations.shouldBeTransformed import org.jetbrains.kotlin.idea.j2k.post.processing.processings.* import org.jetbrains.kotlin.idea.quickfix.* import org.jetbrains.kotlin.idea.util.ImportInsertHelper @@ -209,8 +210,12 @@ private val inspectionLikePostProcessingGroup = it ) as KtReturnExpression).returnedExpression.isTrivialStatementBody() }, - inspectionBasedProcessing(IfThenToSafeAccessInspection(inlineWithPrompt = false), writeActionNeeded = false), - inspectionBasedProcessing(IfThenToElvisInspection(highlightStatement = true, inlineWithPrompt = false), writeActionNeeded = false), + inspectionBasedProcessing(IfThenToSafeAccessInspection(inlineWithPrompt = false), writeActionNeeded = false) { + it.shouldBeTransformed() + }, + inspectionBasedProcessing(IfThenToElvisInspection(highlightStatement = true, inlineWithPrompt = false), writeActionNeeded = false) { + it.shouldBeTransformed() + }, inspectionBasedProcessing(KotlinInspectionFacade.instance.simplifyNegatedBinaryExpression) { it.canBeSimplifiedWithoutChangingSemantics() }, From 6f90a53a2a1ea3c995b84c9e16f2f089cdbcad4b Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Thu, 29 Jun 2023 15:58:04 +0400 Subject: [PATCH 048/226] [kotlin] J2K: clarify var-to-val processing names One is for private non-local properties, the other is for locals only. GitOrigin-RevId: 83e956733f10130b6125907bb912588be31f63d9 --- .../kotlin/idea/j2k/post/processing/J2kPostProcessor.kt | 6 +++--- .../processing/processings/inspectionLikeProcessings.kt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt index b6178244fc42..d920e291f85b 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt @@ -250,8 +250,8 @@ private val processings: List = listOf( listOf( InspectionLikeProcessingGroup( processings = listOf( - VarToValProcessing(), - CanBeValInspectionBasedProcessing() + PrivateVarToValProcessing(), + LocalVarToValInspectionBasedProcessing() ), runSingleTime = true ), @@ -263,7 +263,7 @@ private val processings: List = listOf( NamedPostProcessingGroup( KotlinNJ2KServicesBundle.message("processing.step.cleaning.up.code"), listOf( - InspectionLikeProcessingGroup(VarToValProcessing()), + InspectionLikeProcessingGroup(PrivateVarToValProcessing()), ConvertGettersAndSettersToPropertyProcessing(), InspectionLikeProcessingGroup(RemoveExplicitAccessorInspectionBasedProcessing()), MergePropertyWithConstructorParameterProcessing(), diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/inspectionLikeProcessings.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/inspectionLikeProcessings.kt index f63bbad175e1..5d64a3a79def 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/inspectionLikeProcessings.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/inspectionLikeProcessings.kt @@ -230,7 +230,7 @@ internal class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessi } } -internal class VarToValProcessing : InspectionLikeProcessingForElement(KtProperty::class.java) { +internal class PrivateVarToValProcessing : InspectionLikeProcessingForElement(KtProperty::class.java) { companion object { private val JPA_COLUMN_ANNOTATIONS: Set = setOf( FqName("javax.persistence.Column"), @@ -332,7 +332,7 @@ internal class RemoveRedundantVisibilityModifierProcessing : InspectionLikeProce } } -internal class CanBeValInspectionBasedProcessing : InspectionLikeProcessingForElement(KtDeclaration::class.java) { +internal class LocalVarToValInspectionBasedProcessing : InspectionLikeProcessingForElement(KtDeclaration::class.java) { override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean = CanBeValInspection.canBeVal(element, ignoreNotUsedVals = false) From 6c4d0cd5e1c58eed6e10a8a98bb150d22f6b74fc Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Thu, 29 Jun 2023 16:28:38 +0400 Subject: [PATCH 049/226] [kotlin] J2K: Don't destructure regular variables It will lose the original variable name and may hurt code readability. ^KTIJ-21653 Fixed GitOrigin-RevId: 4325583db173588b6c25fcb489fec1e00789967c --- .../NewJavaToKotlinConverterMultiFileTestGenerated.java | 5 +++++ .../multiFile/NoDestructuringForPlainVariables/Main.java | 9 +++++++++ .../multiFile/NoDestructuringForPlainVariables/Main.kt | 8 ++++++++ .../NoDestructuringForPlainVariables/external/A.kt | 1 + .../external/A.kt.expected | 1 + .../kotlin/idea/j2k/post/processing/J2kPostProcessor.kt | 5 ++++- 6 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/Main.java create mode 100644 plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/Main.kt create mode 100644 plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/external/A.kt create mode 100644 plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/external/A.kt.expected diff --git a/plugins/kotlin/j2k/new/tests/test/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java b/plugins/kotlin/j2k/new/tests/test/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java index ac79a7bf0924..308343d8bd34 100644 --- a/plugins/kotlin/j2k/new/tests/test/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java +++ b/plugins/kotlin/j2k/new/tests/test/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java @@ -88,6 +88,11 @@ public class NewJavaToKotlinConverterMultiFileTestGenerated extends AbstractNewJ runTest("testData/multiFile/KT11952/"); } + @TestMetadata("NoDestructuringForPlainVariables") + public void testNoDestructuringForPlainVariables() throws Exception { + runTest("testData/multiFile/NoDestructuringForPlainVariables/"); + } + @TestMetadata("NullabilityByDFa") public void testNullabilityByDFa() throws Exception { runTest("testData/multiFile/NullabilityByDFa/"); diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/Main.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/Main.java new file mode 100644 index 000000000000..6511af670aa9 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/Main.java @@ -0,0 +1,9 @@ +public class J { + public void test() { + Pojo pojo = new Pojo("a", "b"); + doSomething(pojo.getFieldB()); + } + + private void doSomething(String myString) { + } +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/Main.kt b/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/Main.kt new file mode 100644 index 000000000000..b2e2322645ac --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/Main.kt @@ -0,0 +1,8 @@ +class J { + fun test() { + val pojo = Pojo("a", "b") + doSomething(pojo.fieldB) + } + + private fun doSomething(myString: String) {} +} diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/external/A.kt b/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/external/A.kt new file mode 100644 index 000000000000..3d3c51915034 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/external/A.kt @@ -0,0 +1 @@ +data class Pojo(val fieldA: String, val fieldB: String) \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/external/A.kt.expected b/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/external/A.kt.expected new file mode 100644 index 000000000000..3d3c51915034 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/NoDestructuringForPlainVariables/external/A.kt.expected @@ -0,0 +1 @@ +data class Pojo(val fieldA: String, val fieldB: String) \ No newline at end of file diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt index d920e291f85b..331caa4b26e9 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt @@ -222,7 +222,10 @@ private val inspectionLikePostProcessingGroup = inspectionBasedProcessing(ReplaceGetOrSetInspection()), intentionBasedProcessing(ObjectLiteralToLambdaIntention(), writeActionNeeded = true), intentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()), - intentionBasedProcessing(DestructureIntention(), writeActionNeeded = false), + intentionBasedProcessing(DestructureIntention(), writeActionNeeded = false) { + // Don't destructure regular variables, it will lose the original variable name and may hurt code readability + it.parent is KtForExpression + }, inspectionBasedProcessing(SimplifyAssertNotNullInspection()), LiftReturnInspectionBasedProcessing(), LiftAssignmentInspectionBasedProcessing(), From a8fbcc1b760fe1e4ac3395168f27fd91df1cd59e Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Fri, 30 Jun 2023 11:02:57 +0400 Subject: [PATCH 050/226] [kotlin] J2K: specialize and optimize destructure post-processing The post-processing went from 2500ms to 250ms on the J2K test suite, thanks to avoiding analysis for regular variables in the intention applicability check. ^KTIJ-21653 GitOrigin-RevId: d41af933911c8c79ce78c8a0d0834a12e0b19cea --- .../idea/intentions/DestructureIntention.kt | 173 +++++++++--------- .../j2k/post/processing/J2kPostProcessor.kt | 5 +- .../processings/inspectionLikeProcessings.kt | 16 +- 3 files changed, 104 insertions(+), 90 deletions(-) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/DestructureIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/DestructureIntention.kt index c8b5cc91235c..4a7737006c4e 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/DestructureIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/DestructureIntention.kt @@ -54,92 +54,101 @@ class DestructureIntention : SelfTargetingRangeIntention( KotlinBundle.lazyMessage("use.destructuring.declaration") ) { override fun applyTo(element: KtDeclaration, editor: Editor?) { - val (usagesToRemove, removeSelectorInLoopRange) = collectUsagesToRemove(element) ?: return - val psiFactory = KtPsiFactory(element.project) - val parent = element.parent - val (container, anchor) = if (parent is KtParameterList) parent.parent to null else parent to element - val validator = Fe10KotlinNewDeclarationNameValidator( - container = container, anchor = anchor, target = KotlinNameSuggestionProvider.ValidatorTarget.VARIABLE, - excludedDeclarations = usagesToRemove.map { - (it.declarationToDrop as? KtDestructuringDeclaration)?.entries ?: listOfNotNull(it.declarationToDrop) - }.flatten() - ) - - val names = ArrayList() - val underscoreSupported = element.languageVersionSettings.supportsFeature(LanguageFeature.SingleUnderscoreForParameterName) - // For all unused we generate normal names, not underscores - val allUnused = usagesToRemove.all { (_, usagesToReplace, variableToDrop) -> - usagesToReplace.isEmpty() && variableToDrop == null - } - - usagesToRemove.forEach { (descriptor, usagesToReplace, variableToDrop, name) -> - val suggestedName = - if (usagesToReplace.isEmpty() && variableToDrop == null && underscoreSupported && !allUnused) { - "_" - } else { - Fe10KotlinNameSuggester.suggestNameByName(name ?: descriptor.name.asString(), validator) - } - - runWriteActionIfPhysical(element) { - variableToDrop?.delete() - usagesToReplace.forEach { - it.replace(psiFactory.createExpression(suggestedName)) - } - } - names.add(suggestedName) - } - - val joinedNames = names.joinToString() - when (element) { - is KtParameter -> { - val loopRange = (element.parent as? KtForExpression)?.loopRange - runWriteActionIfPhysical(element) { - val type = element.typeReference?.let { ": ${it.text}" } ?: "" - element.replace(psiFactory.createDestructuringParameter("($joinedNames)$type")) - if (removeSelectorInLoopRange && loopRange is KtDotQualifiedExpression) { - loopRange.replace(loopRange.receiverExpression) - } - } - } - - is KtFunctionLiteral -> { - val lambda = element.parent as KtLambdaExpression - SpecifyExplicitLambdaSignatureIntention().applyTo(lambda, editor) - runWriteActionIfPhysical(element) { - lambda.functionLiteral.valueParameters.singleOrNull()?.replace( - psiFactory.createDestructuringParameter("($joinedNames)") - ) - } - } - - is KtVariableDeclaration -> { - val rangeAfterEq = PsiChildRange(element.initializer, element.lastChild) - val modifierList = element.modifierList?.copied() - runWriteActionIfPhysical(element) { - val result = element.replace( - psiFactory.createDestructuringDeclarationByPattern( - "val ($joinedNames) = $0", rangeAfterEq - ) - ) as KtModifierListOwner - - if (modifierList != null) { - result.setModifierList(modifierList) - } - } - } - } + Holder.applyTo(element, editor) } - override fun applicabilityRange(element: KtDeclaration): TextRange? { - if (!element.isSuitableDeclaration()) return null + override fun applicabilityRange(element: KtDeclaration): TextRange? = + Holder.applicabilityRange(element) - val usagesToRemove = collectUsagesToRemove(element)?.data ?: return null - if (usagesToRemove.isEmpty()) return null + object Holder { + fun applicabilityRange(element: KtDeclaration): TextRange? { + if (!element.isSuitableDeclaration()) return null - return when (element) { - is KtFunctionLiteral -> element.lBrace.textRange - is KtNamedDeclaration -> element.nameIdentifier?.textRange - else -> null + val usagesToRemove = collectUsagesToRemove(element)?.data ?: return null + if (usagesToRemove.isEmpty()) return null + + return when (element) { + is KtFunctionLiteral -> element.lBrace.textRange + is KtNamedDeclaration -> element.nameIdentifier?.textRange + else -> null + } + } + + fun applyTo(element: KtDeclaration, editor: Editor? = null) { + val (usagesToRemove, removeSelectorInLoopRange) = collectUsagesToRemove(element) ?: return + val psiFactory = KtPsiFactory(element.project) + val parent = element.parent + val (container, anchor) = if (parent is KtParameterList) parent.parent to null else parent to element + val validator = Fe10KotlinNewDeclarationNameValidator( + container = container, anchor = anchor, target = KotlinNameSuggestionProvider.ValidatorTarget.VARIABLE, + excludedDeclarations = usagesToRemove.map { + (it.declarationToDrop as? KtDestructuringDeclaration)?.entries ?: listOfNotNull(it.declarationToDrop) + }.flatten() + ) + + val names = ArrayList() + val underscoreSupported = element.languageVersionSettings.supportsFeature(LanguageFeature.SingleUnderscoreForParameterName) + // For all unused we generate normal names, not underscores + val allUnused = usagesToRemove.all { (_, usagesToReplace, variableToDrop) -> + usagesToReplace.isEmpty() && variableToDrop == null + } + + usagesToRemove.forEach { (descriptor, usagesToReplace, variableToDrop, name) -> + val suggestedName = + if (usagesToReplace.isEmpty() && variableToDrop == null && underscoreSupported && !allUnused) { + "_" + } else { + Fe10KotlinNameSuggester.suggestNameByName(name ?: descriptor.name.asString(), validator) + } + + runWriteActionIfPhysical(element) { + variableToDrop?.delete() + usagesToReplace.forEach { + it.replace(psiFactory.createExpression(suggestedName)) + } + } + names.add(suggestedName) + } + + val joinedNames = names.joinToString() + when (element) { + is KtParameter -> { + val loopRange = (element.parent as? KtForExpression)?.loopRange + runWriteActionIfPhysical(element) { + val type = element.typeReference?.let { ": ${it.text}" } ?: "" + element.replace(psiFactory.createDestructuringParameter("($joinedNames)$type")) + if (removeSelectorInLoopRange && loopRange is KtDotQualifiedExpression) { + loopRange.replace(loopRange.receiverExpression) + } + } + } + + is KtFunctionLiteral -> { + val lambda = element.parent as KtLambdaExpression + SpecifyExplicitLambdaSignatureIntention().applyTo(lambda, editor) + runWriteActionIfPhysical(element) { + lambda.functionLiteral.valueParameters.singleOrNull()?.replace( + psiFactory.createDestructuringParameter("($joinedNames)") + ) + } + } + + is KtVariableDeclaration -> { + val rangeAfterEq = PsiChildRange(element.initializer, element.lastChild) + val modifierList = element.modifierList?.copied() + runWriteActionIfPhysical(element) { + val result = element.replace( + psiFactory.createDestructuringDeclarationByPattern( + "val ($joinedNames) = $0", rangeAfterEq + ) + ) as KtModifierListOwner + + if (modifierList != null) { + result.setModifierList(modifierList) + } + } + } + } } } } diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt index 331caa4b26e9..fade1be18d03 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt @@ -222,10 +222,7 @@ private val inspectionLikePostProcessingGroup = inspectionBasedProcessing(ReplaceGetOrSetInspection()), intentionBasedProcessing(ObjectLiteralToLambdaIntention(), writeActionNeeded = true), intentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()), - intentionBasedProcessing(DestructureIntention(), writeActionNeeded = false) { - // Don't destructure regular variables, it will lose the original variable name and may hurt code readability - it.parent is KtForExpression - }, + DestructureForLoopParameterProcessing(), inspectionBasedProcessing(SimplifyAssertNotNullInspection()), LiftReturnInspectionBasedProcessing(), LiftAssignmentInspectionBasedProcessing(), diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/inspectionLikeProcessings.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/inspectionLikeProcessings.kt index 5d64a3a79def..416742be9549 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/inspectionLikeProcessings.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/inspectionLikeProcessings.kt @@ -12,13 +12,11 @@ import org.jetbrains.kotlin.idea.base.psi.replaced import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyzeInContext import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny -import org.jetbrains.kotlin.idea.codeinsight.utils.isRedundantGetter -import org.jetbrains.kotlin.idea.codeinsight.utils.isRedundantSetter -import org.jetbrains.kotlin.idea.codeinsight.utils.removeRedundantGetter -import org.jetbrains.kotlin.idea.codeinsight.utils.removeRedundantSetter +import org.jetbrains.kotlin.idea.codeinsight.utils.* import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.inspections.* import org.jetbrains.kotlin.idea.inspections.collections.isCalling +import org.jetbrains.kotlin.idea.intentions.DestructureIntention import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention import org.jetbrains.kotlin.idea.intentions.branchedTransformations.BranchedFoldingUtils import org.jetbrains.kotlin.idea.j2k.post.processing.InspectionLikeProcessingForElement @@ -413,4 +411,14 @@ internal class MoveLambdaOutsideParenthesesProcessing : override fun apply(element: KtCallExpression) { element.moveFunctionLiteralOutsideParentheses() } +} + +// Don't destructure regular variables, it will lose the original variable name and may hurt code readability +internal class DestructureForLoopParameterProcessing : InspectionLikeProcessingForElement(KtParameter::class.java) { + override fun isApplicableTo(element: KtParameter, settings: ConverterSettings?): Boolean = + element.parent is KtForExpression && DestructureIntention.Holder.applicabilityRange(element) != null + + override fun apply(element: KtParameter) { + DestructureIntention.Holder.applyTo(element) + } } \ No newline at end of file From 4d76f7f35229175b2beb3ae129fbf3f2208dad32 Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Fri, 30 Jun 2023 12:08:26 +0400 Subject: [PATCH 051/226] [kotlin] RemoveEmptyPrimaryConstructorIntention cleanup GitOrigin-RevId: 6a50f8e5c2ef31d7ca587f8d4571324ffea18935 --- .../RemoveEmptyPrimaryConstructorIntention.kt | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveEmptyPrimaryConstructorIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveEmptyPrimaryConstructorIntention.kt index effea3e3dc81..42a8ad7577e4 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveEmptyPrimaryConstructorIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveEmptyPrimaryConstructorIntention.kt @@ -22,15 +22,20 @@ class RemoveEmptyPrimaryConstructorIntention : SelfTargetingOffsetIndependentInt KotlinBundle.lazyMessage("remove.empty.primary.constructor") ) { - override fun applyTo(element: KtPrimaryConstructor, editor: Editor?) = element.delete() + override fun applyTo(element: KtPrimaryConstructor, editor: Editor?) { + element.delete() + } - override fun isApplicableTo(element: KtPrimaryConstructor) = when { - element.containingClass()?.mustHaveNonEmptyPrimaryConstructor() == true -> false - element.valueParameters.isNotEmpty() -> false - element.annotations.isNotEmpty() -> false - element.modifierList?.text?.isBlank() == false -> false - element.containingClass()?.secondaryConstructors?.isNotEmpty() == true -> false - element.isExpectDeclaration() -> false - else -> true + override fun isApplicableTo(element: KtPrimaryConstructor): Boolean { + val containingClass = element.containingClass() ?: return false + return when { + element.valueParameters.isNotEmpty() -> false + element.annotations.isNotEmpty() -> false + element.modifierList?.text?.isBlank() == false -> false + element.isExpectDeclaration() -> false + containingClass.mustHaveNonEmptyPrimaryConstructor() -> false + containingClass.secondaryConstructors.isNotEmpty() -> false + else -> true + } } } From 3a1fcd0bef49bcd82124da3569656ef396591d8a Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Fri, 30 Jun 2023 14:05:40 +0400 Subject: [PATCH 052/226] [kotlin] J2K: don't apply Kotlin inspections that are disabled in current inspection profile Extend the fix to post-processings that are based on inspections but are not exactly `inspectionBasedProcessing`. ^KTIJ-25980 GitOrigin-RevId: 10a299641036d1f11484baa6b91eaa258dc0bcca --- .../inspectionLikePostProcessings.kt | 23 ++-- .../processings/inspectionLikeProcessings.kt | 102 +++++++++++------- 2 files changed, 74 insertions(+), 51 deletions(-) diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/inspectionLikePostProcessings.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/inspectionLikePostProcessings.kt index 9a6b24f6def4..0ed0b8630dcd 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/inspectionLikePostProcessings.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/inspectionLikePostProcessings.kt @@ -11,6 +11,7 @@ import com.intellij.profile.codeInspection.InspectionProfileManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiRecursiveElementVisitor import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractApplicabilityBasedInspection +import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection import org.jetbrains.kotlin.idea.codeinsight.api.classic.intentions.SelfTargetingRangeIntention import org.jetbrains.kotlin.idea.util.application.isUnitTestMode import org.jetbrains.kotlin.j2k.ConverterSettings @@ -166,17 +167,7 @@ internal inline fun Boolean = { true } ) = object : InspectionLikeProcessingForElement(E::class.java) { override fun isApplicableTo(element: E, settings: ConverterSettings?): Boolean = - isInspectionEnabledInCurrentProfile(element.project) && inspection.isApplicable(element) && additionalChecker(element) - - private fun isInspectionEnabledInCurrentProfile(project: Project): Boolean { - if (isUnitTestMode()) { - // there is no real inspection profile in J2K tests, consider all inspections to be enabled in tests - return true - } - val inspectionProfile = InspectionProfileManager.getInstance(project).getCurrentProfile() - val highlightDisplayKey = HighlightDisplayKey.findById(inspection.getID()) - return inspectionProfile.isToolEnabled(highlightDisplayKey) - } + isInspectionEnabledInCurrentProfile(inspection, element.project) && inspection.isApplicable(element) && additionalChecker(element) override fun apply(element: E) { inspection.applyTo(element) @@ -184,3 +175,13 @@ internal inline fun (KtProperty::class.java) { override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean { if (element.isMember && !element.isPrivate()) return false @@ -174,12 +185,14 @@ internal class RemoveRedundantCastToNullableProcessing : } } -internal class RemoveRedundantSamAdaptersProcessing : - InspectionLikeProcessingForElement(KtCallExpression::class.java) { +internal class RemoveRedundantSamAdaptersProcessing : InspectionLikeProcessingForElement(KtCallExpression::class.java) { + private val inspection = RedundantSamConstructorInspection() + override val writeActionNeeded = false override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean = - RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element).isNotEmpty() + isInspectionEnabledInCurrentProfile(inspection, element.project) && + RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element).isNotEmpty() override fun apply(element: KtCallExpression) { val callsToBeConverted = RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element) @@ -291,7 +304,6 @@ internal class JavaObjectEqualsToEqOperatorProcessing : InspectionLikeProcessing } } - internal class RemoveForExpressionLoopParameterTypeProcessing : InspectionLikeProcessingForElement(KtForExpression::class.java) { override fun isApplicableTo(element: KtForExpression, settings: ConverterSettings?): Boolean { @@ -320,10 +332,12 @@ internal class RemoveRedundantModalityModifierProcessing : InspectionLikeProcess } } - internal class RemoveRedundantVisibilityModifierProcessing : InspectionLikeProcessingForElement(KtDeclaration::class.java) { + private val inspection = RedundantVisibilityModifierInspection() + override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean = - RedundantVisibilityModifierInspection.Holder.getRedundantVisibility(element) != null + isInspectionEnabledInCurrentProfile(inspection, element.project) && + RedundantVisibilityModifierInspection.Holder.getRedundantVisibility(element) != null override fun apply(element: KtDeclaration) { element.visibilityModifierType()?.let { element.removeModifier(it) } @@ -331,8 +345,11 @@ internal class RemoveRedundantVisibilityModifierProcessing : InspectionLikeProce } internal class LocalVarToValInspectionBasedProcessing : InspectionLikeProcessingForElement(KtDeclaration::class.java) { + private val inspection = CanBeValInspection() + override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean = - CanBeValInspection.canBeVal(element, ignoreNotUsedVals = false) + isInspectionEnabledInCurrentProfile(inspection, element.project) && + CanBeValInspection.canBeVal(element, ignoreNotUsedVals = false) override fun apply(element: KtDeclaration) { val project = element.project @@ -341,14 +358,14 @@ internal class LocalVarToValInspectionBasedProcessing : InspectionLikeProcessing } } - internal class MayBeConstantInspectionBasedProcessing : InspectionLikeProcessingForElement(KtProperty::class.java) { - override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean = - with(MayBeConstantInspection) { - val status = element.getStatus() - status == MayBeConstantInspection.Status.MIGHT_BE_CONST - || status == MayBeConstantInspection.Status.JVM_FIELD_MIGHT_BE_CONST - } + private val inspection = MayBeConstantInspection() + + override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean { + if (!isInspectionEnabledInCurrentProfile(inspection, element.project)) return false + val status = element.getStatus() + return status == MIGHT_BE_CONST || status == JVM_FIELD_MIGHT_BE_CONST + } override fun apply(element: KtProperty) { AddConstModifierFix.addConstModifier(element) @@ -365,48 +382,53 @@ internal class RemoveExplicitAccessorInspectionBasedProcessing : } } -internal class ExplicitThisInspectionBasedProcessing : - InspectionLikeProcessingForElement(KtExpression::class.java) { +internal class ExplicitThisInspectionBasedProcessing : InspectionLikeProcessingForElement(KtExpression::class.java) { + private val inspection = ExplicitThisInspection() + override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = - ExplicitThisInspection.hasExplicitThis(element) + isInspectionEnabledInCurrentProfile(inspection, element.project) && + ExplicitThisInspection.hasExplicitThis(element) override fun apply(element: KtExpression) { - ExplicitThisExpressionFix.removeExplicitThisExpression( - with(ExplicitThisInspection) { - element.thisAsReceiverOrNull() ?: return - } - ) + val thisExpression = element.thisAsReceiverOrNull() ?: return + ExplicitThisExpressionFix.removeExplicitThisExpression(thisExpression) } } -internal class LiftReturnInspectionBasedProcessing : - InspectionLikeProcessingForElement(KtExpression::class.java) { - override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = - LiftReturnOrAssignmentInspection.getState(element, false)?.any { - it.liftType == LiftReturnOrAssignmentInspection.Companion.LiftType.LIFT_RETURN_OUT - } ?: false +internal class LiftReturnInspectionBasedProcessing : InspectionLikeProcessingForElement(KtExpression::class.java) { + private val inspection = LiftReturnOrAssignmentInspection() + + override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean { + if (!isInspectionEnabledInCurrentProfile(inspection, element.project)) return false + val state = LiftReturnOrAssignmentInspection.getState(element, skipLongExpressions = false) ?: return false + return state.any { it.liftType == LIFT_RETURN_OUT } + } override fun apply(element: KtExpression) { BranchedFoldingUtils.foldToReturn(element) } } -internal class LiftAssignmentInspectionBasedProcessing : - InspectionLikeProcessingForElement(KtExpression::class.java) { - override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = - LiftReturnOrAssignmentInspection.getState(element, false)?.any { - it.liftType == LiftReturnOrAssignmentInspection.Companion.LiftType.LIFT_ASSIGNMENT_OUT - } ?: false +internal class LiftAssignmentInspectionBasedProcessing : InspectionLikeProcessingForElement(KtExpression::class.java) { + private val inspection = LiftReturnOrAssignmentInspection() + + override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean { + if (!isInspectionEnabledInCurrentProfile(inspection, element.project)) return false + val state = LiftReturnOrAssignmentInspection.getState(element, skipLongExpressions = false) ?: return false + return state.any { it.liftType == LIFT_ASSIGNMENT_OUT } + } override fun apply(element: KtExpression) { BranchedFoldingUtils.tryFoldToAssignment(element) } } -internal class MoveLambdaOutsideParenthesesProcessing : - InspectionLikeProcessingForElement(KtCallExpression::class.java) { +internal class MoveLambdaOutsideParenthesesProcessing : InspectionLikeProcessingForElement(KtCallExpression::class.java) { + private val inspection = MoveLambdaOutsideParenthesesInspection() + override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean = - element.canMoveLambdaOutsideParentheses() + isInspectionEnabledInCurrentProfile(inspection, element.project) && + element.canMoveLambdaOutsideParentheses() override fun apply(element: KtCallExpression) { element.moveFunctionLiteralOutsideParentheses() From 7556753696bc8844325e09f432fc272aac40918e Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Fri, 30 Jun 2023 15:20:48 +0400 Subject: [PATCH 053/226] [kotlin] J2K: drop ReplaceMapGetOrDefaultIntention post-processing This is a code style-dependent intention that should not be applied automatically. GitOrigin-RevId: 9be8b69fb4b1ffdf1b262b1c8db0e83dacd2e227 --- .../tests/testData/newJ2k/postProcessing/MapGetOrDefault.kt | 4 ++-- .../kotlin/idea/j2k/post/processing/J2kPostProcessor.kt | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/kotlin/j2k/new/tests/testData/newJ2k/postProcessing/MapGetOrDefault.kt b/plugins/kotlin/j2k/new/tests/testData/newJ2k/postProcessing/MapGetOrDefault.kt index 0fe19f7ce37f..9a70124ea876 100644 --- a/plugins/kotlin/j2k/new/tests/testData/newJ2k/postProcessing/MapGetOrDefault.kt +++ b/plugins/kotlin/j2k/new/tests/testData/newJ2k/postProcessing/MapGetOrDefault.kt @@ -1,5 +1,5 @@ internal class C { private fun foo(map: Map): String { - return map[1] ?: "bar" + return map.getOrDefault(1, "bar") } -} \ No newline at end of file +} diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt index fade1be18d03..9305002a9f4f 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt @@ -229,7 +229,6 @@ private val inspectionLikePostProcessingGroup = intentionBasedProcessing(RemoveEmptyPrimaryConstructorIntention()), MayBeConstantInspectionBasedProcessing(), RemoveForExpressionLoopParameterTypeProcessing(), - intentionBasedProcessing(ReplaceMapGetOrDefaultIntention()), inspectionBasedProcessing(ReplaceGuardClauseWithFunctionCallInspection()), inspectionBasedProcessing(KotlinInspectionFacade.instance.sortModifiers), intentionBasedProcessing(ConvertToRawStringTemplateIntention(), additionalChecker = ::shouldConvertToRawString), From af394ab1f26d08282e9f76264e898f246da840cc Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Fri, 30 Jun 2023 15:41:19 +0400 Subject: [PATCH 054/226] [kotlin] J2K: remove second invocation of PrivateVarToValProcessing This is an expensive processing, because it uses `ReferencesSearch.search`, and looks like one invocation is enough (no tests are affected). GitOrigin-RevId: c498b2c3996fe931c1005596cd1fef3e5daf3a0b --- .../kotlin/idea/j2k/post/processing/J2kPostProcessor.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt index 9305002a9f4f..c3f35dc8855d 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt @@ -262,7 +262,6 @@ private val processings: List = listOf( NamedPostProcessingGroup( KotlinNJ2KServicesBundle.message("processing.step.cleaning.up.code"), listOf( - InspectionLikeProcessingGroup(PrivateVarToValProcessing()), ConvertGettersAndSettersToPropertyProcessing(), InspectionLikeProcessingGroup(RemoveExplicitAccessorInspectionBasedProcessing()), MergePropertyWithConstructorParameterProcessing(), From a728902fc7a5ca8842dcee0c4b3d16fc25f481e0 Mon Sep 17 00:00:00 2001 From: Alexey Belkov Date: Fri, 30 Jun 2023 16:15:20 +0400 Subject: [PATCH 055/226] [kotlin] J2K: drop AddOperatorModifierInspection post-processing This is an information-level inspection. We can't automatically determine if it is appropriate to add 'operator' modifier to any particular function. Actually, the affected test `kt-19340.kt` is a perfect illustration of this: the function `set` doesn't have the semantics of an operator function in Kotlin's sense. It uses its two parameters differently: indexed access doesn't make sense in this case. GitOrigin-RevId: 41c252f3b7e64ec768265166525c41bc3eb13ef7 --- .../kotlin/j2k/new/tests/testData/newJ2k/issues/kt-19340.kt | 4 ++-- .../new/tests/testData/newJ2k/postProcessing/GetOperator.kt | 6 +++--- .../kotlin/idea/j2k/post/processing/J2kPostProcessor.kt | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/plugins/kotlin/j2k/new/tests/testData/newJ2k/issues/kt-19340.kt b/plugins/kotlin/j2k/new/tests/testData/newJ2k/issues/kt-19340.kt index 53d2490189fc..40091722e81d 100644 --- a/plugins/kotlin/j2k/new/tests/testData/newJ2k/issues/kt-19340.kt +++ b/plugins/kotlin/j2k/new/tests/testData/newJ2k/issues/kt-19340.kt @@ -3,7 +3,7 @@ package test.nullabilityOnClassBoundaries class Item { private var s1: String? = null private var s2: String? = null - operator fun set(s1: String?, s2: String?) { + fun set(s1: String?, s2: String?) { this.s1 = s1 this.s2 = s2 } @@ -12,7 +12,7 @@ class Item { class Reader { fun readItem(n: Int): Item { val item = Item() - item[readString(n)] = null + item.set(readString(n), null) return item } diff --git a/plugins/kotlin/j2k/new/tests/testData/newJ2k/postProcessing/GetOperator.kt b/plugins/kotlin/j2k/new/tests/testData/newJ2k/postProcessing/GetOperator.kt index e4fbe0708122..b04b9e0ac007 100644 --- a/plugins/kotlin/j2k/new/tests/testData/newJ2k/postProcessing/GetOperator.kt +++ b/plugins/kotlin/j2k/new/tests/testData/newJ2k/postProcessing/GetOperator.kt @@ -2,7 +2,7 @@ import javaApi.JavaClass import kotlinApi.KotlinClass internal class X { - operator fun get(index: Int): Int { + fun get(index: Int): Int { return 0 } } @@ -13,7 +13,7 @@ internal class C { } fun foo(x: X): Int { - return x[0] + return x.get(0) } fun foo(kotlinClass: KotlinClass): Int { @@ -23,4 +23,4 @@ internal class C { fun foo(javaClass: JavaClass): Int { return javaClass[0] } -} \ No newline at end of file +} diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt index c3f35dc8855d..f57f54f3964d 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/J2kPostProcessor.kt @@ -172,7 +172,6 @@ private val addOrRemoveModifiersProcessingGroup = processings = listOf( RemoveRedundantVisibilityModifierProcessing(), RemoveRedundantModalityModifierProcessing(), - inspectionBasedProcessing(AddOperatorModifierInspection(), writeActionNeeded = false), ) ) From cf1b76b782a1de283b1b03e0589d6824e5d709f7 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Fri, 30 Jun 2023 16:53:20 +0200 Subject: [PATCH 056/226] [kotlin] update kotlin compiler version used as analyzer to `1.9.20-dev-5455` As weekly kotlin compiler update GitOrigin-RevId: f8fddf033e67f2a61ee5154a3afd457983d97fd5 --- .../kotlinc_allopen_compiler_plugin.xml | 6 +++--- .../kotlinc_analysis_api_providers.xml | 6 +++--- .../kotlinc_analysis_project_structure.xml | 6 +++--- ...linc_android_extensions_compiler_plugin.xml | 6 +++--- .../kotlinc_assignment_compiler_plugin.xml | 6 +++--- .idea/libraries/kotlinc_high_level_api.xml | 6 +++--- .../libraries/kotlinc_high_level_api_fe10.xml | 6 +++--- .idea/libraries/kotlinc_high_level_api_fir.xml | 6 +++--- .../kotlinc_high_level_api_fir_tests.xml | 6 +++--- .../kotlinc_high_level_api_impl_base.xml | 6 +++--- .../kotlinc_high_level_api_impl_base_tests.xml | 6 +++--- ...linc_incremental_compilation_impl_tests.xml | 6 +++--- .../kotlinc_kotlin_build_common_tests.xml | 6 +++--- .../libraries/kotlinc_kotlin_compiler_cli.xml | 6 +++--- .../kotlinc_kotlin_compiler_common.xml | 6 +++--- .../libraries/kotlinc_kotlin_compiler_fe10.xml | 6 +++--- .../libraries/kotlinc_kotlin_compiler_fir.xml | 6 +++--- .idea/libraries/kotlinc_kotlin_compiler_ir.xml | 6 +++--- .../kotlinc_kotlin_compiler_tests.xml | 6 +++--- .../kotlinc_kotlin_gradle_statistics.xml | 6 +++--- .idea/libraries/kotlinc_kotlin_jps_common.xml | 6 +++--- .../kotlinc_kotlin_script_runtime.xml | 6 +++--- .../kotlinc_kotlin_scripting_common.xml | 6 +++--- .../kotlinc_kotlin_scripting_compiler_impl.xml | 6 +++--- .../libraries/kotlinc_kotlin_scripting_jvm.xml | 6 +++--- .idea/libraries/kotlinc_kotlin_stdlib.xml | 18 +++++++++--------- .../kotlinc_kotlin_stdlib_minimal_for_test.xml | 6 +++--- ...c_kotlinx_serialization_compiler_plugin.xml | 6 +++--- .../kotlinc_lombok_compiler_plugin.xml | 6 +++--- .idea/libraries/kotlinc_low_level_api_fir.xml | 6 +++--- .../kotlinc_noarg_compiler_plugin.xml | 6 +++--- .../kotlinc_parcelize_compiler_plugin.xml | 6 +++--- ...tlinc_sam_with_receiver_compiler_plugin.xml | 6 +++--- .../kotlinc_scripting_compiler_plugin.xml | 6 +++--- .../libraries/kotlinc_symbol_light_classes.xml | 6 +++--- .../resources/model.properties | 2 +- 36 files changed, 112 insertions(+), 112 deletions(-) diff --git a/.idea/libraries/kotlinc_allopen_compiler_plugin.xml b/.idea/libraries/kotlinc_allopen_compiler_plugin.xml index 7aa23c481922..68583421dd72 100644 --- a/.idea/libraries/kotlinc_allopen_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_allopen_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_analysis_api_providers.xml b/.idea/libraries/kotlinc_analysis_api_providers.xml index 80f327dc7f19..4336f8328c66 100644 --- a/.idea/libraries/kotlinc_analysis_api_providers.xml +++ b/.idea/libraries/kotlinc_analysis_api_providers.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_analysis_project_structure.xml b/.idea/libraries/kotlinc_analysis_project_structure.xml index 13ed5dd73907..84cb7c2e1326 100644 --- a/.idea/libraries/kotlinc_analysis_project_structure.xml +++ b/.idea/libraries/kotlinc_analysis_project_structure.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_android_extensions_compiler_plugin.xml b/.idea/libraries/kotlinc_android_extensions_compiler_plugin.xml index 204449116884..3bcd682c5d9d 100644 --- a/.idea/libraries/kotlinc_android_extensions_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_android_extensions_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_assignment_compiler_plugin.xml b/.idea/libraries/kotlinc_assignment_compiler_plugin.xml index 09bb1f00ce59..18ba85c2d079 100644 --- a/.idea/libraries/kotlinc_assignment_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_assignment_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api.xml b/.idea/libraries/kotlinc_high_level_api.xml index aa74b92eac0f..72487137c4aa 100644 --- a/.idea/libraries/kotlinc_high_level_api.xml +++ b/.idea/libraries/kotlinc_high_level_api.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_fe10.xml b/.idea/libraries/kotlinc_high_level_api_fe10.xml index 854c3f382a25..0e610dea4fc0 100644 --- a/.idea/libraries/kotlinc_high_level_api_fe10.xml +++ b/.idea/libraries/kotlinc_high_level_api_fe10.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_fir.xml b/.idea/libraries/kotlinc_high_level_api_fir.xml index 33cc21ac4fd1..c94a6653b028 100644 --- a/.idea/libraries/kotlinc_high_level_api_fir.xml +++ b/.idea/libraries/kotlinc_high_level_api_fir.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_fir_tests.xml b/.idea/libraries/kotlinc_high_level_api_fir_tests.xml index a74cb6316fb5..68bfbfef602c 100644 --- a/.idea/libraries/kotlinc_high_level_api_fir_tests.xml +++ b/.idea/libraries/kotlinc_high_level_api_fir_tests.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_impl_base.xml b/.idea/libraries/kotlinc_high_level_api_impl_base.xml index 936b2649f0a6..a5b9a9f14fad 100644 --- a/.idea/libraries/kotlinc_high_level_api_impl_base.xml +++ b/.idea/libraries/kotlinc_high_level_api_impl_base.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_high_level_api_impl_base_tests.xml b/.idea/libraries/kotlinc_high_level_api_impl_base_tests.xml index 3ee2c1f93a6a..31927f533109 100644 --- a/.idea/libraries/kotlinc_high_level_api_impl_base_tests.xml +++ b/.idea/libraries/kotlinc_high_level_api_impl_base_tests.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_incremental_compilation_impl_tests.xml b/.idea/libraries/kotlinc_incremental_compilation_impl_tests.xml index 7f636a1c2f7d..938a59868e93 100644 --- a/.idea/libraries/kotlinc_incremental_compilation_impl_tests.xml +++ b/.idea/libraries/kotlinc_incremental_compilation_impl_tests.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_build_common_tests.xml b/.idea/libraries/kotlinc_kotlin_build_common_tests.xml index 85604bf3a2f2..10ea7785667f 100644 --- a/.idea/libraries/kotlinc_kotlin_build_common_tests.xml +++ b/.idea/libraries/kotlinc_kotlin_build_common_tests.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_cli.xml b/.idea/libraries/kotlinc_kotlin_compiler_cli.xml index 577d368c21ae..96cb57c24310 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_cli.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_cli.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_common.xml b/.idea/libraries/kotlinc_kotlin_compiler_common.xml index cc3b0dcb5584..2e93ef7f037a 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_common.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_common.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_fe10.xml b/.idea/libraries/kotlinc_kotlin_compiler_fe10.xml index 2d016a9019d4..7f3454a154d0 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_fe10.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_fe10.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_fir.xml b/.idea/libraries/kotlinc_kotlin_compiler_fir.xml index 4c22a671bbb3..a8a461da2d2c 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_fir.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_fir.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_ir.xml b/.idea/libraries/kotlinc_kotlin_compiler_ir.xml index bf2badc4fd62..935b0e7d3e57 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_ir.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_ir.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_compiler_tests.xml b/.idea/libraries/kotlinc_kotlin_compiler_tests.xml index 02bbf51dabed..c781b05787b6 100644 --- a/.idea/libraries/kotlinc_kotlin_compiler_tests.xml +++ b/.idea/libraries/kotlinc_kotlin_compiler_tests.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_gradle_statistics.xml b/.idea/libraries/kotlinc_kotlin_gradle_statistics.xml index e317550b04c7..28260e035b4b 100644 --- a/.idea/libraries/kotlinc_kotlin_gradle_statistics.xml +++ b/.idea/libraries/kotlinc_kotlin_gradle_statistics.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_jps_common.xml b/.idea/libraries/kotlinc_kotlin_jps_common.xml index 6a5cfb013dc2..f590c5954c4c 100644 --- a/.idea/libraries/kotlinc_kotlin_jps_common.xml +++ b/.idea/libraries/kotlinc_kotlin_jps_common.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_script_runtime.xml b/.idea/libraries/kotlinc_kotlin_script_runtime.xml index a9456b3cbaae..ce1b4c7feedb 100644 --- a/.idea/libraries/kotlinc_kotlin_script_runtime.xml +++ b/.idea/libraries/kotlinc_kotlin_script_runtime.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_scripting_common.xml b/.idea/libraries/kotlinc_kotlin_scripting_common.xml index a43c9d8a0785..19735db1d76e 100644 --- a/.idea/libraries/kotlinc_kotlin_scripting_common.xml +++ b/.idea/libraries/kotlinc_kotlin_scripting_common.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_scripting_compiler_impl.xml b/.idea/libraries/kotlinc_kotlin_scripting_compiler_impl.xml index ebc7ae7f1530..3ef14ff8885a 100644 --- a/.idea/libraries/kotlinc_kotlin_scripting_compiler_impl.xml +++ b/.idea/libraries/kotlinc_kotlin_scripting_compiler_impl.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_scripting_jvm.xml b/.idea/libraries/kotlinc_kotlin_scripting_jvm.xml index 632009d36428..998df63d9d5d 100644 --- a/.idea/libraries/kotlinc_kotlin_scripting_jvm.xml +++ b/.idea/libraries/kotlinc_kotlin_scripting_jvm.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_stdlib.xml b/.idea/libraries/kotlinc_kotlin_stdlib.xml index cd57486e8d27..4072de63271c 100644 --- a/.idea/libraries/kotlinc_kotlin_stdlib.xml +++ b/.idea/libraries/kotlinc_kotlin_stdlib.xml @@ -1,6 +1,6 @@ - + @@ -9,17 +9,17 @@ - - - - + + + + - - - - + + + + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlin_stdlib_minimal_for_test.xml b/.idea/libraries/kotlinc_kotlin_stdlib_minimal_for_test.xml index 73ecca995b36..20f1119b3b85 100644 --- a/.idea/libraries/kotlinc_kotlin_stdlib_minimal_for_test.xml +++ b/.idea/libraries/kotlinc_kotlin_stdlib_minimal_for_test.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_kotlinx_serialization_compiler_plugin.xml b/.idea/libraries/kotlinc_kotlinx_serialization_compiler_plugin.xml index e70b7e91bb2c..6602864a7290 100644 --- a/.idea/libraries/kotlinc_kotlinx_serialization_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_kotlinx_serialization_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_lombok_compiler_plugin.xml b/.idea/libraries/kotlinc_lombok_compiler_plugin.xml index 5015783151e7..00ba1b43bcc8 100644 --- a/.idea/libraries/kotlinc_lombok_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_lombok_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_low_level_api_fir.xml b/.idea/libraries/kotlinc_low_level_api_fir.xml index d4ba528fa926..2025e0f5b706 100644 --- a/.idea/libraries/kotlinc_low_level_api_fir.xml +++ b/.idea/libraries/kotlinc_low_level_api_fir.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_noarg_compiler_plugin.xml b/.idea/libraries/kotlinc_noarg_compiler_plugin.xml index f293be5c3df4..78cd391cd279 100644 --- a/.idea/libraries/kotlinc_noarg_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_noarg_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_parcelize_compiler_plugin.xml b/.idea/libraries/kotlinc_parcelize_compiler_plugin.xml index 9aa15c304e29..ca959bce3a9f 100644 --- a/.idea/libraries/kotlinc_parcelize_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_parcelize_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_sam_with_receiver_compiler_plugin.xml b/.idea/libraries/kotlinc_sam_with_receiver_compiler_plugin.xml index 346ba70a74ec..641eddeab4a5 100644 --- a/.idea/libraries/kotlinc_sam_with_receiver_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_sam_with_receiver_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_scripting_compiler_plugin.xml b/.idea/libraries/kotlinc_scripting_compiler_plugin.xml index 2f254fc4e874..f13027791cdc 100644 --- a/.idea/libraries/kotlinc_scripting_compiler_plugin.xml +++ b/.idea/libraries/kotlinc_scripting_compiler_plugin.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/kotlinc_symbol_light_classes.xml b/.idea/libraries/kotlinc_symbol_light_classes.xml index 6870481c8f55..91cff0a81d44 100644 --- a/.idea/libraries/kotlinc_symbol_light_classes.xml +++ b/.idea/libraries/kotlinc_symbol_light_classes.xml @@ -1,12 +1,12 @@ - + - + - + \ No newline at end of file diff --git a/plugins/kotlin/util/project-model-updater/resources/model.properties b/plugins/kotlin/util/project-model-updater/resources/model.properties index f2732e70cfed..b2d4b6b5265c 100644 --- a/plugins/kotlin/util/project-model-updater/resources/model.properties +++ b/plugins/kotlin/util/project-model-updater/resources/model.properties @@ -1,4 +1,4 @@ -kotlincVersion=1.9.20-dev-4794 +kotlincVersion=1.9.20-dev-5455 kotlincArtifactsMode=MAVEN jpsPluginVersion=1.8.21-release-380 From 2171a9b153a6adc20906fd4c485cd143ac382822 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 30 Jun 2023 15:49:58 +0200 Subject: [PATCH 057/226] [ui] using `AboutDialog` for collecting "about IDE" data in the Welcome Screen action (IDEA-323024) GitOrigin-RevId: a7b362566ce2c55bd97a76e8a6cf9e7217d53669 --- .../wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java index f142868812b9..6a07725cb88c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java @@ -6,7 +6,7 @@ import com.intellij.diagnostic.IdeMessagePanel; import com.intellij.diagnostic.MessagePool; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; -import com.intellij.ide.actions.AboutPopup; +import com.intellij.ide.actions.AboutDialog; import com.intellij.notification.NotificationType; import com.intellij.notification.impl.widget.IdeNotificationArea; import com.intellij.openapi.Disposable; @@ -147,7 +147,7 @@ public final class WelcomeScreenComponentFactory { private static AnAction createCopyAboutAction() { return DumbAwareAction.create(e -> { - CopyPasteManager.getInstance().setContents(new StringSelection(AboutPopup.getAboutText())); + CopyPasteManager.getInstance().setContents(new StringSelection(new AboutDialog(null).getExtendedAboutText())); }); } From 2d3624ced2c9f71b13e09921e0785b6cbb0b3488 Mon Sep 17 00:00:00 2001 From: "Denis.Popesku" Date: Thu, 29 Jun 2023 15:53:14 +0300 Subject: [PATCH 058/226] Add support for PsiFileSystemItem in PackageSet and GlobalInspectionContextBase classes Add default implementation for the contains() method to handle PsiFileSystemItem objects. This will allow for more flexibility when dealing with files and folders. GitOrigin-RevId: 435cd4ea326b02f296f27a241607c5a024121adf --- .../psi/search/scope/packageSet/PackageSet.java | 13 +++++++++++++ .../psi/search/scope/packageSet/PackageSetBase.java | 6 ++++++ .../ex/GlobalInspectionContextBase.java | 7 ++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/PackageSet.java b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/PackageSet.java index d8bff0b60472..88482364cc5a 100644 --- a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/PackageSet.java +++ b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/PackageSet.java @@ -17,6 +17,7 @@ package com.intellij.psi.search.scope.packageSet; import com.intellij.openapi.util.NlsSafe; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileSystemItem; import org.jetbrains.annotations.NotNull; import java.util.function.Function; @@ -24,10 +25,22 @@ import java.util.function.Predicate; public interface PackageSet { boolean contains(@NotNull PsiFile file, NamedScopesHolder holder); + + default boolean contains(@NotNull PsiFileSystemItem file, NamedScopesHolder holder) { + if (file instanceof PsiFile) { + return contains((PsiFile)file, holder); + } + else { + return false; + } + } + @NotNull PackageSet createCopy(); + @NlsSafe @NotNull String getText(); + int getNodePriority(); /** diff --git a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/PackageSetBase.java b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/PackageSetBase.java index 0221cf593a18..b5284e7eb2c3 100644 --- a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/PackageSetBase.java +++ b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/PackageSetBase.java @@ -5,6 +5,7 @@ import com.intellij.diagnostic.PluginException; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileSystemItem; import com.intellij.psi.PsiManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,6 +24,11 @@ public abstract class PackageSetBase implements PackageSet { @Override public boolean contains(@NotNull PsiFile file, @Nullable NamedScopesHolder holder) { + return contains((PsiFileSystemItem)file, holder); + } + + @Override + public boolean contains(@NotNull PsiFileSystemItem file, NamedScopesHolder holder) { VirtualFile virtualFile = file.getVirtualFile(); return virtualFile != null && contains(virtualFile, file.getProject(), holder); } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java index 364866345edd..233a9bf8ec18 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java @@ -195,10 +195,15 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G } public boolean isToCheckMember(@NotNull RefElement owner, @NotNull InspectionProfileEntry tool) { - return isToCheckFile(((RefElementImpl)owner).getContainingFile(), tool) && !((RefElementImpl)owner).isSuppressed(tool.getShortName(), tool.getAlternativeID()); + return isToCheckFile(((RefElementImpl)owner).getContainingFile(), tool) && + !((RefElementImpl)owner).isSuppressed(tool.getShortName(), tool.getAlternativeID()); } public boolean isToCheckFile(PsiFile file, @NotNull InspectionProfileEntry tool) { + return isToCheckFile((PsiFileSystemItem)file, tool); + } + + public boolean isToCheckFile(PsiFileSystemItem file, @NotNull InspectionProfileEntry tool) { Tools tools = getTools().get(tool.getShortName()); if (tools != null && file != null) { for (ScopeToolState state : tools.getTools()) { From 7cf73dc23d4f95418aa1e5719392d3538e853de0 Mon Sep 17 00:00:00 2001 From: Ruslan Cheremin Date: Thu, 29 Jun 2023 17:41:03 +0200 Subject: [PATCH 059/226] [monitoring] report count of executed Read|WriteActions to OTel.Metrics + charts for read/write actions count in open-telemetry-metrics-plotter.html GitOrigin-RevId: 55f83faf5092ba21f58c958a9b90d5bfc51de022 --- .../impl/open-telemetry-metrics-plotter.html | 28 ++++++++-- .../application/impl/ApplicationImpl.java | 54 +++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/platform/diagnostic/telemetry-impl/src/com/intellij/platform/diagnostic/telemetry/impl/open-telemetry-metrics-plotter.html b/platform/diagnostic/telemetry-impl/src/com/intellij/platform/diagnostic/telemetry/impl/open-telemetry-metrics-plotter.html index 56576b9935b9..d9dbf995ce15 100644 --- a/platform/diagnostic/telemetry-impl/src/com/intellij/platform/diagnostic/telemetry/impl/open-telemetry-metrics-plotter.html +++ b/platform/diagnostic/telemetry-impl/src/com/intellij/platform/diagnostic/telemetry/impl/open-telemetry-metrics-plotter.html @@ -823,11 +823,31 @@ as an example return } + const writeActionExecutionsCount = extractTimeSeries("WriteAction.executionsCount") + const readActionExecutionsCount = extractTimeSeries("ReadAction.executionsCount") + const finalizedExecutionsCount = extractTimeSeries("NonBlockingReadAction.finalizedExecutionsCount") const failedExecutionsCount = extractTimeSeries("NonBlockingReadAction.failedExecutionsCount") const finalizedExecutionTimeMs = extractTimeSeries("NonBlockingReadAction.finalizedExecutionTimeUs").mulScalar(1e-3) const failedExecutionTimeMs = extractTimeSeries("NonBlockingReadAction.failedExecutionTimeUs").mulScalar(1e-3) + plotTimeSeries( + 'Read and Write Actions count', + 'ReadAndWriteActions_CountChart', + [{ + name: 'Write Actions', + color: 'red', + series: writeActionExecutionsCount + }, { + name: 'Read Actions', + color: 'blue', + series: readActionExecutionsCount + }], + /*yaxis:*/ { + title: 'actions' + } + ) + plotTimeSeries( 'NonBlockingReadActions count: successful/interrupted', 'NonBlockingReads_CountChart', @@ -1280,7 +1300,7 @@ as an example
-
EDT: AWT & Flush Queues:
+
EDT: AWT & Flush Queues
@@ -1292,9 +1312,11 @@ as an example
-
+
-
NonBlockingReadAction:
+
Actions: Write, Read, and Non-Blocking-Read
+ +
diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 89fa483ca70a..e757c81a0702 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -35,6 +35,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.platform.diagnostic.telemetry.IJTracer; +import com.intellij.platform.diagnostic.telemetry.PlatformScopesKt; import com.intellij.platform.diagnostic.telemetry.TelemetryManager; import com.intellij.platform.diagnostic.telemetry.helpers.TraceUtil; import com.intellij.psi.util.ReadActionCache; @@ -47,6 +48,8 @@ import com.intellij.util.concurrency.Propagation; import com.intellij.util.containers.Stack; import com.intellij.util.messages.Topic; import com.intellij.util.ui.EDT; +import io.opentelemetry.api.metrics.BatchCallback; +import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; import kotlin.coroutines.EmptyCoroutineContext; @@ -62,6 +65,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import static com.intellij.ide.ShutdownKt.cancelAndJoinBlocking; @@ -118,6 +122,8 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl private static final String WAS_EVER_SHOWN = "was.ever.shown"; + private final OTelReadWriteActionsMonitor otelMonitor = new OTelReadWriteActionsMonitor(TelemetryManager.getMeter(PlatformScopesKt.EDT)); + @TestOnly public ApplicationImpl(boolean isHeadless, @NotNull RwLockHolder lockHolder) { super(null, @@ -385,6 +391,8 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl else { Disposer.dispose(myLastDisposable); } + + otelMonitor.close(); } @Override @@ -899,6 +907,7 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl if (status != null) { myLock.endRead(status); } + otelMonitor.readActionExecuted(); } } @@ -913,6 +922,7 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl if (status != null) { myLock.endRead(status); } + otelMonitor.readActionExecuted(); } } @@ -927,6 +937,7 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl if (status != null) { myLock.endRead(status); } + otelMonitor.readActionExecuted(); } } @@ -1137,6 +1148,7 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl if (status != null) { myLock.endRead(status); } + otelMonitor.readActionExecuted(); } return true; } @@ -1233,6 +1245,7 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl if (myWriteActionsStack.isEmpty()) { fireAfterWriteActionFinished(clazz); } + otelMonitor.writeActionExecuted(); } } @@ -1309,6 +1322,7 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl public void finish() { myReadActionCacheImpl.clear(); myLock.endRead(myReader); + otelMonitor.readActionExecuted(); } } @@ -1499,4 +1513,44 @@ public class ApplicationImpl extends ClientAwareComponentManager implements Appl myLock.setAllowImplicitRead(oldVal); } } + + /** Count read & write actions executed, and report to OpenTelemetry Metrics */ + private static class OTelReadWriteActionsMonitor implements AutoCloseable{ + private final @NotNull BatchCallback batchCallback; + + private final AtomicInteger readActionsExecuted = new AtomicInteger(); + + private final AtomicInteger writeActionsExecuted = new AtomicInteger(); + + private OTelReadWriteActionsMonitor(@NotNull Meter meter) { + var raExecutionsCounter = meter.counterBuilder("ReadAction.executionsCount") + .setDescription("Total read actions executed") + .buildObserver(); + var waExecutionsCounter = meter.counterBuilder("WriteAction.executionsCount") + .setDescription("Total write actions executed") + .buildObserver(); + + this.batchCallback = meter.batchCallback( + () -> { + raExecutionsCounter.record(readActionsExecuted.get()); + waExecutionsCounter.record(writeActionsExecuted.get()); + }, + raExecutionsCounter, + waExecutionsCounter + ); + } + + public void readActionExecuted(){ + readActionsExecuted.incrementAndGet(); + } + + public void writeActionExecuted(){ + writeActionsExecuted.incrementAndGet(); + } + + @Override + public void close() { + batchCallback.close(); + } + } } From e4bde4b34eae379061d1aec8e673f9f017cdd53a Mon Sep 17 00:00:00 2001 From: Zhanna Gorelova Date: Fri, 30 Jun 2023 16:13:24 +0200 Subject: [PATCH 060/226] [swagger][redoc] IDEA-323776 navigation was changed to use line and column, because offset used not right in some file GitOrigin-RevId: 89bd6e8243bfbbcf2b01a92a1e34896e94b6d71a --- .../intellij/ui/jcef/JBCefPsiNavigationUtils.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefPsiNavigationUtils.kt b/platform/platform-api/src/com/intellij/ui/jcef/JBCefPsiNavigationUtils.kt index 0c819d7dac37..c7e5851cad7a 100644 --- a/platform/platform-api/src/com/intellij/ui/jcef/JBCefPsiNavigationUtils.kt +++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefPsiNavigationUtils.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.OpenFileDescriptor import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.util.text.LineColumn import com.intellij.openapi.vfs.VirtualFileManager import org.jetbrains.annotations.NonNls import java.nio.file.Paths @@ -19,6 +20,14 @@ object JBCefPsiNavigationUtils { fun navigateTo(requestLink: String): Boolean { val (filePath, offset) = parsePsiElementCoordinates(requestLink) ?: return false + return navigateTo(filePath, offset) + } + + fun navigateTo(filePath: String, lineColumn: LineColumn): Boolean { + return navigateTo(filePath, null, lineColumn) + } + + private fun navigateTo(filePath: String, offset: Int?, lineColumn: LineColumn? = null): Boolean { DataManager.getInstance().dataContextFromFocusAsync.onSuccess { dataContext -> val project = CommonDataKeys.PROJECT.getData(dataContext) ?: return@onSuccess val virtualFile = ProjectRootManager.getInstance(project) @@ -27,9 +36,12 @@ object JBCefPsiNavigationUtils { .mapNotNull(VirtualFileManager.getInstance()::findFileByNioPath) .firstOrNull() ?: return@onSuccess + val descriptor = offset?.let { OpenFileDescriptor(project, virtualFile, offset) } + ?: lineColumn?.let { OpenFileDescriptor(project, virtualFile, lineColumn.line, lineColumn.column) } + ?: return@onSuccess + ApplicationManager.getApplication().invokeLater { - FileEditorManager.getInstance(project) - .openEditor(OpenFileDescriptor(project, virtualFile, offset), true) + FileEditorManager.getInstance(project).openEditor(descriptor, true) } } return true From 16fcd45b4cfe1da4ff44235ba6adda76e5235571 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Fri, 30 Jun 2023 19:44:10 +0400 Subject: [PATCH 061/226] log overriding isPopup for groups, fix incorrect cases Fixes IDEA-324067. GitOrigin-RevId: cf25d444cc8fe67b88890ba56d617e4fceeed593 --- .../actionSystem/impl/ActionManagerImpl.kt | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.kt index 693dfcea820f..0048c4719907 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.kt @@ -462,10 +462,15 @@ open class ActionManagerImpl protected constructor(private val coroutineScope: C synchronized(lock) { if (element.attributes.get(OVERRIDES_ATTR_NAME).toBoolean()) { - if (getActionOrStub(id) == null) { - LOG.error("$element '$id' doesn't override anything") + val actionOrStub = getActionOrStub(id) + if (actionOrStub == null) { + LOG.error("'$id' action group in '${plugin.name}' does not override anything") return } + if (action is ActionGroup && actionOrStub is ActionGroup && + action.isPopup != actionOrStub.isPopup) { + LOG.info("'$id' action group in '${plugin.name}' sets isPopup=$action.isPopup") + } val prev = replaceAction(actionId = id, newAction = action, pluginId = plugin.pluginId) if (action is DefaultActionGroup && prev is DefaultActionGroup) { @@ -542,6 +547,14 @@ open class ActionManagerImpl protected constructor(private val coroutineScope: C @Suppress("NAME_SHADOWING") val id = id ?: "" + val popup = element.attributes.get("popup") + if (popup != null) { + group.isPopup = popup.toBoolean() + if (group is ActionGroupStub) { + group.popupDefinedInXml = true + } + } + registerOrReplaceActionInner(element = element, id = id, action = group, plugin = module) val presentation = group.templatePresentation @@ -586,14 +599,6 @@ open class ActionManagerImpl protected constructor(private val coroutineScope: C presentation.icon = loadIcon(module = module, iconPath = iconPath, requestor = className) } - // popup - val popup = element.attributes.get("popup") - if (popup != null) { - group.isPopup = popup.toBoolean() - if (group is ActionGroupStub) { - group.popupDefinedInXml = true - } - } val searchable = element.attributes.get("searchable") if (searchable != null) { group.isSearchable = searchable.toBoolean() From 248c63b647b2757177aa90a061b84bed31a8c294 Mon Sep 17 00:00:00 2001 From: Alex Plate Date: Mon, 26 Jun 2023 11:21:50 +0300 Subject: [PATCH 062/226] [Workspace Model] Extract action description into the properties file. The actions is printing the state of modules in the workspace model GitOrigin-RevId: 5645afc84b8ac4761f68e2cc13bf0648d1f97d06 --- .../src/messages/ActionsBundle.properties | 4 +++- platform/platform-resources/src/idea/PlatformActions.xml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 97de8802c987..863973bd8ef3 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -2789,4 +2789,6 @@ action.addQuickAction.BackForward.text=Back / Forward action.addQuickAction.UndoRedo.text=Undo / Redo action.ColoredHeaderAction.text=Use Project Colors in Toolbar -action.ChangeMainToolbarColor.text=Change Toolbar Color... \ No newline at end of file +action.ChangeMainToolbarColor.text=Change Toolbar Color... + +group.Internal.WorkspaceModel.text=Workspace Model \ No newline at end of file diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index acb9fcfcec84..6f9560b53285 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -1209,7 +1209,7 @@ - + From 2a608bd7527962eee7571234d450ea7cce9e09d2 Mon Sep 17 00:00:00 2001 From: Alex Plate Date: Fri, 30 Jun 2023 19:08:18 +0300 Subject: [PATCH 063/226] [Workspace Model] [IDEA-324087] Change the subscription of PsiVFSListener to xml-based approach GitOrigin-RevId: 2fed7af4de09ddeb893592b77035b2ca576fa3a6 --- .../psi/impl/file/impl/PsiVFSListener.java | 15 +++++++-------- .../src/META-INF/LangExtensions.xml | 2 ++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java index 3022a2edf9a0..a26570aa6eca 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java @@ -2,7 +2,6 @@ package com.intellij.psi.impl.file.impl; import com.intellij.AppTopics; -import com.intellij.ProjectTopics; import com.intellij.application.Topics; import com.intellij.ide.PsiCopyPasteManager; import com.intellij.ide.impl.ProjectUtilCore; @@ -87,7 +86,6 @@ public final class PsiVFSListener implements BulkFileListener { }, project); } - connection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyModuleRootListener(project)); connection.subscribe(AdditionalLibraryRootsListener.TOPIC, new MyAdditionalLibraryRootListener(project)); connection.subscribe(FileTypeManager.TOPIC, new FileTypeListener() { @Override @@ -596,14 +594,12 @@ public final class PsiVFSListener implements BulkFileListener { name, fileTypeByFileName, "", vFile.getModificationStamp(), true, false); } - private static final class MyModuleRootListener implements ModuleRootListener { + public static final class MyModuleRootListener implements ModuleRootListener { private int depthCounter; // accessed from within write action only - private final PsiManagerImpl psiManager; - private final FileManagerImpl fileManager; + private final Project myListenerProject; - private MyModuleRootListener(@NotNull Project project) { - psiManager = (PsiManagerImpl)PsiManager.getInstance(project); - fileManager = (FileManagerImpl)psiManager.getFileManager(); + public MyModuleRootListener(@NotNull Project project) { + myListenerProject = project; } @Override @@ -617,6 +613,7 @@ public final class PsiVFSListener implements BulkFileListener { if (LOG.isTraceEnabled()) LOG.trace("depthCounter increased " + depthCounter); if (depthCounter > 1) return; + PsiManagerImpl psiManager = (PsiManagerImpl)PsiManager.getInstance(myListenerProject); PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(psiManager); treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_ROOTS); psiManager.beforePropertyChange(treeEvent); @@ -627,6 +624,8 @@ public final class PsiVFSListener implements BulkFileListener { @Override public void rootsChanged(@NotNull ModuleRootEvent event) { if (LOG.isTraceEnabled()) LOG.trace("rootsChanged call"); + PsiManagerImpl psiManager = (PsiManagerImpl)PsiManager.getInstance(myListenerProject); + FileManagerImpl fileManager = (FileManagerImpl)psiManager.getFileManager(); fileManager.dispatchPendingEvents(); if (event.isCausedByFileTypesChange()) return; diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index d32cfda1fb3c..e2303023782f 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -1746,5 +1746,7 @@ topic="com.intellij.ide.SaveAndSyncHandlerListener"/> + From b31e2a87a14d05f21cbe8080380620a0aca48673 Mon Sep 17 00:00:00 2001 From: Leonid Shalupov Date: Mon, 26 Jun 2023 13:18:13 +0200 Subject: [PATCH 064/226] ssl: do not nag developers in unit testing mode about certificates GitOrigin-RevId: 72ca2047ffa9871783a21c618668303f5bff6ad7 --- .../com/intellij/util/net/ssl/ConfirmingTrustManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/net/ssl/ConfirmingTrustManager.java b/platform/platform-api/src/com/intellij/util/net/ssl/ConfirmingTrustManager.java index 7796b2cf2544..9b794d74cd92 100644 --- a/platform/platform-api/src/com/intellij/util/net/ssl/ConfirmingTrustManager.java +++ b/platform/platform-api/src/com/intellij/util/net/ssl/ConfirmingTrustManager.java @@ -92,8 +92,11 @@ public final class ConfirmingTrustManager extends ClientOnlyTrustManager { Collection additionalTrustedCertificates = OsCertificatesService.getInstance().getCustomOsSpecificTrustedCertificates(); if (additionalTrustedCertificates.isEmpty()) { - LOG.warn( - "Received an empty list of custom trusted root certificates from the system. Check log above for possible errors, enable debug logging in category 'org.jetbrains.nativecerts' for more information"); + // don't nag developers, on jetbrains developer's machine this list is usually empty on MacOs and Windows + if (!ApplicationManager.getApplication().isUnitTestMode()) { + LOG.warn( + "Received an empty list of custom trusted root certificates from the system. Check log above for possible errors, enable debug logging in category 'org.jetbrains.nativecerts' for more information"); + } return null; } From 4bb8722b289d36c2c37ae0f6c1d11cb539892067 Mon Sep 17 00:00:00 2001 From: Yuriy Artamonov Date: Fri, 30 Jun 2023 18:39:38 +0200 Subject: [PATCH 065/226] [performance] Do not load WhatsNewAction in startup GitOrigin-RevId: a9460beea683e00c48514d37595dbd16eb03e411 --- .../com/intellij/ide/actions/WhatsNewAction.java | 7 +------ .../src/com/intellij/ide/actions/WhatsNewUtil.java | 13 +++++++++++++ .../updateSettings/impl/UpdateCheckerService.java | 3 ++- .../impl/UpdateSettingsConfigurable.kt | 4 ++-- 4 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/ide/actions/WhatsNewUtil.java diff --git a/platform/platform-impl/src/com/intellij/ide/actions/WhatsNewAction.java b/platform/platform-impl/src/com/intellij/ide/actions/WhatsNewAction.java index db9a356b34c0..57bb730ec308 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/WhatsNewAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/WhatsNewAction.java @@ -76,11 +76,6 @@ public class WhatsNewAction extends AnAction implements DumbAware { } } - @ApiStatus.Internal - public static boolean isAvailable() { - return ApplicationInfoEx.getInstanceEx().isShowWhatsNewOnUpdate() && !AppMode.isRemoteDevHost(); - } - @ApiStatus.Internal public static void openWhatsNewPage(@NotNull Project project, @NotNull String url) { if (!JBCefApp.isSupported()) { @@ -148,4 +143,4 @@ public class WhatsNewAction extends AnAction implements DumbAware { var title = IdeBundle.message("update.whats.new", ApplicationNamesInfo.getInstance().getFullProductName()); HTMLEditorProvider.openEditor(project, title, request); } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/actions/WhatsNewUtil.java b/platform/platform-impl/src/com/intellij/ide/actions/WhatsNewUtil.java new file mode 100644 index 000000000000..a45abd541e5b --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/actions/WhatsNewUtil.java @@ -0,0 +1,13 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.ide.actions; + +import com.intellij.idea.AppMode; +import com.intellij.openapi.application.ex.ApplicationInfoEx; +import org.jetbrains.annotations.ApiStatus; + +public final class WhatsNewUtil { + @ApiStatus.Internal + public static boolean isWhatsNewAvailable() { + return ApplicationInfoEx.getInstanceEx().isShowWhatsNewOnUpdate() && !AppMode.isRemoteDevHost(); + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerService.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerService.java index 11491384dfe3..60376fe9c791 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerService.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerService.java @@ -6,6 +6,7 @@ import com.intellij.ide.AppLifecycleListener; import com.intellij.ide.BrowserUtil; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.WhatsNewAction; +import com.intellij.ide.actions.WhatsNewUtil; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.InstalledPluginsState; import com.intellij.ide.plugins.PluginManagerConfigurable; @@ -187,7 +188,7 @@ final class UpdateCheckerService { private static void showWhatsNew(Project project, BuildNumber current) { String url = ApplicationInfoEx.getInstanceEx().getWhatsNewUrl(); - if (url != null && WhatsNewAction.isAvailable() && shouldShowWhatsNew(current, ApplicationInfoEx.getInstanceEx().isMajorEAP())) { + if (url != null && WhatsNewUtil.isWhatsNewAvailable() && shouldShowWhatsNew(current, ApplicationInfoEx.getInstanceEx().isMajorEAP())) { if (UpdateSettings.getInstance().isShowWhatsNewEditor()) { ApplicationManager.getApplication().invokeLater(() -> WhatsNewAction.openWhatsNewPage(project, url)); IdeUpdateUsageTriggerCollector.majorUpdateHappened(true); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.kt b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.kt index 7689ea42b5b2..abdec8ec88c0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.kt +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.kt @@ -4,7 +4,7 @@ package com.intellij.openapi.updateSettings.impl import com.intellij.icons.AllIcons import com.intellij.ide.DataManager import com.intellij.ide.IdeBundle -import com.intellij.ide.actions.WhatsNewAction +import com.intellij.ide.actions.WhatsNewUtil import com.intellij.ide.nls.NlsMessages import com.intellij.ide.plugins.newui.reloadPluginIcon import com.intellij.openapi.actionSystem.CommonDataKeys @@ -92,7 +92,7 @@ class UpdateSettingsConfigurable @JvmOverloads constructor (private val checkNow }.topGap(TopGap.SMALL) .bottomGap(BottomGap.SMALL) - if (WhatsNewAction.isAvailable()) { + if (WhatsNewUtil.isWhatsNewAvailable()) { row { checkBox(IdeBundle.message("updates.settings.show.editor")) .bindSelected(settings.state::isShowWhatsNewEditor) From 6c2d989c185976fcd6f2254961a1f6a37b80e3f8 Mon Sep 17 00:00:00 2001 From: Yuriy Artamonov Date: Fri, 30 Jun 2023 18:43:17 +0200 Subject: [PATCH 066/226] [kotlin] Do not load JavaToKotlinAction.Companion in startup GitOrigin-RevId: 957e4b4a69ee647c15bd5b85fc21bc628dfc14c6 --- .../kotlin/idea/actions/JavaToKotlinAction.kt | 36 +++++++++---------- .../copy/ConvertJavaCopyPasteProcessor.kt | 2 +- .../KotlinCreateTestIntention.kt | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt index 5fee1375ab9f..8ab9aac08207 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt @@ -53,7 +53,7 @@ import kotlin.io.path.notExists import kotlin.system.measureTimeMillis class JavaToKotlinAction : AnAction() { - companion object { + object Handler { private fun uniqueKotlinFileName(javaFile: VirtualFile): String { val nioFile = javaFile.fileSystem.getNioPath(javaFile) @@ -227,10 +227,24 @@ class JavaToKotlinAction : AnAction() { newFiles } } + + internal fun selectedJavaFiles(e: AnActionEvent): Sequence { + val virtualFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return sequenceOf() + val project = e.project ?: return sequenceOf() + return allJavaFiles(virtualFiles, project) + } + + private fun allJavaFiles(filesOrDirs: Array, project: Project): Sequence { + val manager = PsiManager.getInstance(project) + return getAllFilesRecursively(filesOrDirs) + .asSequence() + .mapNotNull { manager.findFile(it) as? PsiJavaFile } + .filter { it.fileType == JavaFileType.INSTANCE } // skip .jsp files + } } override fun actionPerformed(e: AnActionEvent) { - val javaFiles = selectedJavaFiles(e).filter { it.isWritable }.toList() + val javaFiles = Handler.selectedJavaFiles(e).filter { it.isWritable }.toList() val project = CommonDataKeys.PROJECT.getData(e.dataContext) ?: return val module = e.getData(PlatformCoreDataKeys.MODULE) ?: return @@ -262,7 +276,7 @@ class JavaToKotlinAction : AnAction() { if (Messages.showOkCancelDialog( project, question, - title, + Handler.title, okText, cancelText, Messages.getWarningIcon() @@ -273,7 +287,7 @@ class JavaToKotlinAction : AnAction() { } } - convertFiles(javaFiles, project, module) + Handler.convertFiles(javaFiles, project, module) } override fun getActionUpdateThread() = ActionUpdateThread.BGT @@ -309,18 +323,4 @@ class JavaToKotlinAction : AnAction() { return files.any(::isWritableJavaFile) } - - private fun selectedJavaFiles(e: AnActionEvent): Sequence { - val virtualFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return sequenceOf() - val project = e.project ?: return sequenceOf() - return allJavaFiles(virtualFiles, project) - } - - private fun allJavaFiles(filesOrDirs: Array, project: Project): Sequence { - val manager = PsiManager.getInstance(project) - return getAllFilesRecursively(filesOrDirs) - .asSequence() - .mapNotNull { manager.findFile(it) as? PsiJavaFile } - .filter { it.fileType == JavaFileType.INSTANCE } // skip .jsp files - } } \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt index 24df78d74f2b..11a481985ea8 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt @@ -257,7 +257,7 @@ internal fun ElementAndTextList.convertCodeToKotlin(project: Project, targetModu ThrowableComputable { runReadAction { converter.elementsToKotlin(inputElements) } }, - JavaToKotlinAction.title, + JavaToKotlinAction.Handler.title, true, project ) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/testIntegration/KotlinCreateTestIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/testIntegration/KotlinCreateTestIntention.kt index 3fb796d2908a..b0981b6999fc 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/testIntegration/KotlinCreateTestIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/testIntegration/KotlinCreateTestIntention.kt @@ -195,7 +195,7 @@ class KotlinCreateTestIntention : SelfTargetingRangeIntention Date: Mon, 26 Jun 2023 16:34:46 +0300 Subject: [PATCH 067/226] [floating toolbar] IDEA-321869: show popup above the ActionButton if it overlaps the component GitOrigin-RevId: 1511818ff1a5dc7c0998e5fca0d94efdc0d6b852 --- .../DropdownActionGroup.kt | 8 +----- .../actionSystem/impl/ActionButton.java | 25 ++++++++++++++++++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/DropdownActionGroup.kt b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/DropdownActionGroup.kt index 70a3482346c0..d769e476f252 100644 --- a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/DropdownActionGroup.kt +++ b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/DropdownActionGroup.kt @@ -4,7 +4,6 @@ package com.intellij.ui.codeFloatingToolbar import com.intellij.openapi.actionSystem.* import com.intellij.openapi.actionSystem.ex.CustomComponentAction import com.intellij.openapi.actionSystem.impl.ActionButtonWithText -import com.intellij.ui.popup.PopupFactoryImpl import javax.swing.JComponent class DropdownActionGroup: DefaultActionGroup(), CustomComponentAction { @@ -12,12 +11,7 @@ class DropdownActionGroup: DefaultActionGroup(), CustomComponentAction { override fun createCustomComponent(presentation: Presentation, place: String): JComponent { return object: ActionButtonWithText(this, presentation, place, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE) { override fun actionPerformed(event: AnActionEvent) { - val group = this@DropdownActionGroup - val popupPlace = ActionPlaces.getPopupPlace(place) - val context = event.dataContext - val popup = PopupFactoryImpl.getInstance().createActionGroupPopup(null, group, context, null, true, popupPlace) - popup.setRequestFocus(false) - popup.showUnderneathOf(this) + showActionGroupPopup(this@DropdownActionGroup, event) } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java index dddd0c7c4e83..a3f8db41ecb7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java @@ -11,6 +11,8 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.keymap.impl.IdeMouseEventDispatcher; import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupListener; +import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.openapi.ui.popup.util.PopupUtil; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Key; @@ -20,6 +22,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.Strings; import com.intellij.ui.ExperimentalUI; +import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.popup.PopupFactoryImpl; import com.intellij.ui.popup.PopupState; import com.intellij.ui.popup.WizardPopup; @@ -247,10 +250,30 @@ public class ActionButton extends JComponent implements ActionButtonComponent, A popup.setShowSubmenuOnHover(true); popup.setAlignByParentBounds(false); popup.setActiveRoot(getPopupContainer(this) == null); - popup.showUnderneathOf(event.getInputEvent().getComponent()); + Component component = event.getInputEvent().getComponent(); + adjustOverlappingIfNeed(popup, component); + popup.showUnderneathOf(component); return popup; } + private static void adjustOverlappingIfNeed(JBPopup popup, Component component){ + popup.addListener(new JBPopupListener() { + @Override + public void beforeShown(@NotNull LightweightWindowEvent event) { + Point currentLocation = popup.getLocationOnScreen(); + Rectangle currentArea = new Rectangle(currentLocation, popup.getSize()); + Point aboveLocation = new RelativePoint(component, new Point(0, 0)).getScreenPoint(); + Rectangle componentArea = new Rectangle(aboveLocation, component.getSize()); + if (currentArea.intersects(componentArea)) { + aboveLocation.setLocation(aboveLocation.x, aboveLocation.y - popup.getSize().height); + if (aboveLocation.y >= 0) { + popup.setLocation(aboveLocation); + } + } + } + }); + } + @NotNull private MenuItemPresentationFactory createPresentationFactory() { return new MenuItemPresentationFactory() { From 40f53851451fb79a851de63cbeceff6aa08d327a Mon Sep 17 00:00:00 2001 From: Alexandr Suhinin Date: Thu, 29 Jun 2023 10:09:49 +0300 Subject: [PATCH 068/226] [floating toolbar] IDEA-321869 fix: toolbar is not shown if code is selected by keyboard GitOrigin-RevId: bb6dd7f54088439c9edf235177b1fca299ffe56b --- .../actionSystem/impl/FloatingToolbar.kt | 35 +++++++++---------- .../util/resources/misc/registry.properties | 2 -- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt index 1b0a70b12212..5761eb7739c0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt @@ -16,7 +16,6 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.VisualPosition import com.intellij.openapi.editor.event.* import com.intellij.openapi.util.Disposer -import com.intellij.openapi.util.registry.Registry import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiEditorUtil @@ -31,6 +30,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.debounce import org.jetbrains.annotations.ApiStatus +import java.awt.AWTEvent import java.awt.Point import java.awt.event.KeyAdapter import java.awt.event.KeyEvent @@ -53,7 +53,6 @@ open class FloatingToolbar( private var hint: LightweightHint? = null private var buttonSize: Int by Delegates.notNull() private var lastSelection: String? = null - private var showToolbar = true private var hintWasShownForSelection = false private enum class HintRequest { @@ -88,30 +87,31 @@ open class FloatingToolbar( @RequiresEdt fun isShown(): Boolean { - return hint != null + return hint?.isVisible == true } @RequiresEdt private fun hide() { hint?.hide() + hint = null } @RequiresEdt private suspend fun showIfHidden() { - if (hint != null || !shouldReviveAfterClose() && !showToolbar) { + if (isShown() || hintWasShownForSelection) { return } + hintWasShownForSelection = true val canBeShownAtCurrentSelection = readAction { canBeShownAtCurrentSelection() } if (!canBeShownAtCurrentSelection) { return } val hint = createHint() + showHint(hint) hint.addHintListener { this.hint = null - showToolbar = false } this.hint = hint - showHint(hint) } private suspend fun createHint(): LightweightHint { @@ -143,7 +143,6 @@ open class FloatingToolbar( override fun dispose() { coroutineScope.cancel() hide() - hint = null } protected open fun createActionGroup(): ActionGroup? { @@ -242,7 +241,6 @@ open class FloatingToolbar( private inner class MouseListener : EditorMouseListener { override fun mouseReleased(event: EditorMouseEvent) { - hintWasShownForSelection = false updateOnProbablyChangedSelection { if (isShown()) { updateLocationIfShown() @@ -259,7 +257,6 @@ open class FloatingToolbar( if (event.source != editor.contentComponent) { return } - hintWasShownForSelection = false updateOnProbablyChangedSelection { scheduleHide() } @@ -270,13 +267,10 @@ open class FloatingToolbar( override fun mouseMoved(event: EditorMouseEvent) { val visualPosition = event.visualPosition val hoverSelected = editor.caretModel.allCarets.any { visualPosition.isInsideSelection(it) } - if (hoverSelected && (hintWasShownForSelection || hint?.isVisible == true)) { - hintWasShownForSelection = true + if (hoverSelected) { scheduleShow() - } else { - if (!Registry.get("floating.codeToolbar.revive.selectionChangeOnly").asBoolean()) { - showToolbar = true - } + } else if (!isShown()){ + hintWasShownForSelection = false } } @@ -289,16 +283,19 @@ open class FloatingToolbar( private inner class EditorSelectionListener : SelectionListener { override fun selectionChanged(event: SelectionEvent) { - val event = IdeEventQueue.getInstance().trueCurrentEvent - val isDoubleClick = (event as? MouseEvent)?.clickCount == 2 - showToolbar = !(disableForDoubleClickSelection() && isDoubleClick) hintWasShownForSelection = false + if (isIgnoredEvent(IdeEventQueue.getInstance().trueCurrentEvent)) { + hintWasShownForSelection = true + } + } + + private fun isIgnoredEvent(event: AWTEvent): Boolean { + return disableForDoubleClickSelection() && (event as? MouseEvent)?.clickCount == 2 } } private inner class DocumentChangeListener : BulkAwareDocumentListener { override fun documentChanged(event: DocumentEvent) { - hintWasShownForSelection = false if (!shouldSurviveDocumentChange()) { scheduleHide() } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index f77a856dce2d..4db2673771c2 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -1040,8 +1040,6 @@ floating.codeToolbar.verticalOffset=2 floating.codeToolbar.verticalOffset.description=Vertical offset between line and floating toolbar for code floating.codeToolbar.showBelow=true floating.codeToolbar.showBelow.description=Always show floating code toolbar below the selection when possible. -floating.codeToolbar.revive.selectionChangeOnly=true -floating.codeToolbar.revive.selectionChangeOnly.description=Show closed toolbar again only if editor selection was changed run.refactorings.under.progress=true run.refactorings.under.progress.description=Run refactorings write action under progress, not to freeze the UI during long operations From 4b85f82f0e626e86e5ee916edb8665181c31e1ee Mon Sep 17 00:00:00 2001 From: Alexandr Suhinin Date: Thu, 29 Jun 2023 10:20:46 +0300 Subject: [PATCH 069/226] [floating toolbar] IDEA-321869: don't require mouse exit from the selection to show toolbar if document was changed GitOrigin-RevId: 3c009838ee427f6de60633ae66266628ea22ecde --- .../com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt index 5761eb7739c0..1db39d41c231 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt @@ -296,6 +296,7 @@ open class FloatingToolbar( private inner class DocumentChangeListener : BulkAwareDocumentListener { override fun documentChanged(event: DocumentEvent) { + hintWasShownForSelection = false if (!shouldSurviveDocumentChange()) { scheduleHide() } From 15e3b828c9a6114a64d72e2aca9b810fa0c94dc1 Mon Sep 17 00:00:00 2001 From: Alexandr Suhinin Date: Thu, 29 Jun 2023 12:28:36 +0300 Subject: [PATCH 070/226] [floating toolbar] IDEA-321869: fix position for 'above' registry GitOrigin-RevId: 26b76b69870fcfdde16b4ad66c30dc62914fdb04 --- .../com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt index b08f50afac04..55648154abb8 100644 --- a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt +++ b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt @@ -71,7 +71,7 @@ class CodeFloatingToolbar( val offsetForHint = when { isOneLineSelection -> selectionStart isBelow -> getOffsetForLine(editor, getLineByVisualStart(editor, selectionEnd, true)) - else -> getOffsetForLine(editor, getLineByVisualStart(editor, selectionEnd, false)) + else -> getOffsetForLine(editor, getLineByVisualStart(editor, selectionStart, false)) } val visualPosition = editor.offsetToVisualPosition(offsetForHint) val hintPoint = HintManagerImpl.getHintPosition(hint, editor, visualPosition, HintManager.DEFAULT) From 40ca9342752dcde6febdf1da8bfaa993c982dc53 Mon Sep 17 00:00:00 2001 From: Alexandr Suhinin Date: Thu, 29 Jun 2023 12:48:25 +0300 Subject: [PATCH 071/226] [floating toolbar] IDEA-321869: don't show toolbar group in find actions GitOrigin-RevId: c2d6cb7d38d86d9213a53ab4d5bd87b1f2f0dcc2 --- platform/platform-resources/src/idea/LangActions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 8cb620243823..d409022495c1 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -484,7 +484,7 @@ - + Date: Thu, 29 Jun 2023 12:56:26 +0300 Subject: [PATCH 072/226] [floating toolbar] IDEA-321869: remove redundant method Floating toolbar should be revived always after re-entering selected code GitOrigin-RevId: db4cb83460e598ccdc01fd55614423e2d5caf4cb --- .../com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt | 2 -- .../com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt | 3 --- 2 files changed, 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt index 55648154abb8..93c5ce30817d 100644 --- a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt +++ b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt @@ -55,8 +55,6 @@ class CodeFloatingToolbar( override fun disableForDoubleClickSelection(): Boolean = true - override fun shouldReviveAfterClose(): Boolean = false - override fun shouldSurviveDocumentChange(): Boolean = false override fun hideByOtherHints(): Boolean = false diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt index 1db39d41c231..86922a48078a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt @@ -209,9 +209,6 @@ open class FloatingToolbar( return false } - - protected open fun shouldReviveAfterClose(): Boolean = true - protected open fun shouldSurviveDocumentChange(): Boolean = true protected open fun isEnabled(): Boolean { From c95567b59a22c3eb928819aab48efe5cec0f2460 Mon Sep 17 00:00:00 2001 From: Alexandr Suhinin Date: Fri, 30 Jun 2023 19:02:27 +0300 Subject: [PATCH 073/226] [floating toolbar] IDEA-321869: add intention actions into floating toolbar GitOrigin-RevId: b3636562cfce18bc71e7033365cd911fb752daa6 --- .../impl/IntentionHintComponent.java | 90 +++++++++++++------ .../CodeFloatingToolbar.kt | 8 +- .../actionSystem/impl/ActionButton.java | 24 +++-- .../actionSystem/impl/FloatingToolbar.kt | 17 +++- 4 files changed, 101 insertions(+), 38 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java index 165c17013dc2..2f25690a0144 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java @@ -6,6 +6,7 @@ import com.intellij.codeInsight.hint.*; import com.intellij.codeInsight.intention.CustomizableIntentionAction; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionActionDelegate; +import com.intellij.codeInsight.intention.actions.ShowIntentionActionsAction; import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings; import com.intellij.codeInsight.intention.impl.preview.IntentionPreviewPopupUpdateProcessor; import com.intellij.codeInsight.unwrap.ScopeHighlighter; @@ -18,6 +19,7 @@ import com.intellij.internal.statistic.IntentionFUSCollector; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.openapi.actionSystem.impl.SimpleDataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -43,6 +45,7 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.refactoring.BaseRefactoringIntentionAction; import com.intellij.ui.*; import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.codeFloatingToolbar.CodeFloatingToolbar; import com.intellij.ui.icons.RowIcon; import com.intellij.ui.popup.WizardPopup; import com.intellij.ui.popup.list.ListPopupImpl; @@ -221,37 +224,72 @@ public final class IntentionHintComponent implements Disposable, ScrollAwareHint @RequiresEdt private void showPopup(boolean mouseClick) { - RelativePoint positionHint = null; if (mouseClick && myLightBulbPanel.isShowing()) { - RelativePoint swCorner = RelativePoint.getSouthWestOf(myLightBulbPanel); - Point popup = swCorner.getPoint(); - - Point panel = SwingUtilities.convertPoint(myLightBulbPanel, new Point(), myEditor.getContentComponent()); - Point caretLine = myEditor.offsetToXY(myEditor.getCaretModel().getOffset()); - if (panel.y + myLightBulbPanel.getHeight() <= caretLine.y) { - // The light bulb panel is shown above the caret line. - // The caret line should be completely visible, as it contains the interesting code. - // The popup menu is shown below the caret line. - popup.y += 1; // Step outside the light bulb panel. - popup.y += myEditor.getLineHeight(); - } - else { - // Let the top border pixel of the popup menu overlap the bottom border pixel of the light bulb panel. - } - - // XXX: This formula is only guessed. - int adjust = (int)(UISettingsUtils.getInstance().getCurrentIdeScale() - 0.5); - // Align the left border of the popup menu with the light bulb panel. - // XXX: Where does the 1 come from? - popup.x += 1 + adjust; - // Align the top border of the menu bar. - popup.y += adjust; - - positionHint = new RelativePoint(swCorner.getComponent(), popup); + showPopup(findPositionForBulbButton()); + return; } + CodeFloatingToolbar toolbar = CodeFloatingToolbar.getToolbar(myEditor); + if (toolbar != null) { + if (toolbar.isShown()) { + showPopupFromToolbar(toolbar); + } else { + toolbar.show(() -> showPopupFromToolbar(toolbar)); + } + return; + } + showPopup(null); + } + + private void showPopup(@Nullable RelativePoint positionHint) { myPopup.show(this, positionHint); } + private @NotNull RelativePoint findPositionForBulbButton() { + RelativePoint swCorner = RelativePoint.getSouthWestOf(myLightBulbPanel); + Point popup = swCorner.getPoint(); + + Point panel = SwingUtilities.convertPoint(myLightBulbPanel, new Point(), myEditor.getContentComponent()); + Point caretLine = myEditor.offsetToXY(myEditor.getCaretModel().getOffset()); + if (panel.y + myLightBulbPanel.getHeight() <= caretLine.y) { + // The light bulb panel is shown above the caret line. + // The caret line should be completely visible, as it contains the interesting code. + // The popup menu is shown below the caret line. + popup.y += 1; // Step outside the light bulb panel. + popup.y += myEditor.getLineHeight(); + } + else { + // Let the top border pixel of the popup menu overlap the bottom border pixel of the light bulb panel. + } + + // XXX: This formula is only guessed. + int adjust = (int)(UISettingsUtils.getInstance().getCurrentIdeScale() - 0.5); + // Align the left border of the popup menu with the light bulb panel. + // XXX: Where does the 1 come from? + popup.x += 1 + adjust; + // Align the top border of the menu bar. + popup.y += adjust; + + return new RelativePoint(swCorner.getComponent(), popup); + } + + private void showPopupFromToolbar(@NotNull CodeFloatingToolbar toolbar){ + JComponent component = toolbar.getHintComponent(); + if (component == null) return; + List buttons = UIUtil.findComponentsOfType(component, ActionButton.class); + ActionButton intentionButton = ContainerUtil.find(buttons, (button) -> button.getAction() instanceof ShowIntentionActionsAction); + if (intentionButton == null) return; + RelativePoint buttonPoint = RelativePoint.getSouthWestOf(intentionButton); + RelativePoint toolbarPoint = RelativePoint.getSouthWestOf(component); + int horizontalOffset = toolbarPoint.getScreenPoint().x - buttonPoint.getScreenPoint().x; + buttonPoint.getPoint().translate(horizontalOffset, 0); + if (myPopup.myListPopup == null) { + myPopup.myHint = this; + IntentionPopup.recreateMyPopup(myPopup, new IntentionListStep(myPopup, myPopup.myEditor, myPopup.myFile, myPopup.myProject, myPopup.myCachedIntentions)); + } + ActionButton.adjustVerticalOverlapping(myPopup.myListPopup, intentionButton); + showPopup(buttonPoint); + } + private static final class MyComponentHint extends LightweightHint { private boolean myVisible; private boolean myShouldDelay; diff --git a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt index 93c5ce30817d..f5c8d91c1532 100644 --- a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt +++ b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt @@ -7,6 +7,7 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl import com.intellij.ide.ui.customization.CustomActionsSchema import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.actionSystem.Separator import com.intellij.openapi.actionSystem.impl.FloatingToolbar import com.intellij.openapi.actionSystem.impl.MoreActionGroup import com.intellij.openapi.editor.Editor @@ -21,6 +22,7 @@ import com.intellij.psi.PsiElement import com.intellij.ui.LightweightHint import kotlinx.coroutines.CoroutineScope import java.awt.Point +import javax.swing.JComponent /** * Represents floating toolbar which is shown for selected text inside editor. @@ -59,6 +61,9 @@ class CodeFloatingToolbar( override fun hideByOtherHints(): Boolean = false + val hintComponent: JComponent? + get() = hint?.component + override fun getHintPosition(hint: LightweightHint): Point { val selectionEnd = editor.selectionModel.selectionEnd val selectionStart = editor.selectionModel.selectionStart @@ -116,8 +121,9 @@ class CodeFloatingToolbar( override fun createActionGroup(): ActionGroup? { val contextAwareActionGroupId = getContextAwareGroupId() val mainActionGroup = CustomActionsSchema.getInstance().getCorrectedAction(contextAwareActionGroupId) as? ActionGroup ?: return super.createActionGroup() + val showIntentionsAction = CustomActionsSchema.getInstance().getCorrectedAction("ShowIntentionActions") ?: error("Can't find ShowIntentionActions action") val configurationGroup = createConfigureGroup(contextAwareActionGroupId) - return DefaultActionGroup(mainActionGroup, configurationGroup) + return DefaultActionGroup(showIntentionsAction, Separator.create(), mainActionGroup, Separator.create(), configurationGroup) } private fun getContextAwareGroupId(): String { diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java index a3f8db41ecb7..82ab81d362ed 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.Strings; import com.intellij.ui.ExperimentalUI; import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.popup.AbstractPopup; import com.intellij.ui.popup.PopupFactoryImpl; import com.intellij.ui.popup.PopupState; import com.intellij.ui.popup.WizardPopup; @@ -250,30 +251,39 @@ public class ActionButton extends JComponent implements ActionButtonComponent, A popup.setShowSubmenuOnHover(true); popup.setAlignByParentBounds(false); popup.setActiveRoot(getPopupContainer(this) == null); - Component component = event.getInputEvent().getComponent(); - adjustOverlappingIfNeed(popup, component); + InputEvent inputEvent = event.getInputEvent(); + LOG.assertTrue(inputEvent != null); + Component component = inputEvent.getComponent(); + adjustVerticalOverlapping(popup, component); popup.showUnderneathOf(component); return popup; } - private static void adjustOverlappingIfNeed(JBPopup popup, Component component){ + public static void adjustVerticalOverlapping(JBPopup popup, Component component){ popup.addListener(new JBPopupListener() { @Override public void beforeShown(@NotNull LightweightWindowEvent event) { + Dimension popupSize = getFullPopupSize(popup); Point currentLocation = popup.getLocationOnScreen(); - Rectangle currentArea = new Rectangle(currentLocation, popup.getSize()); + Rectangle currentArea = new Rectangle(currentLocation, popupSize); Point aboveLocation = new RelativePoint(component, new Point(0, 0)).getScreenPoint(); Rectangle componentArea = new Rectangle(aboveLocation, component.getSize()); if (currentArea.intersects(componentArea)) { - aboveLocation.setLocation(aboveLocation.x, aboveLocation.y - popup.getSize().height); - if (aboveLocation.y >= 0) { - popup.setLocation(aboveLocation); + int y = aboveLocation.y - popupSize.height; + if (y >= 0) { + popup.setLocation(new Point(currentLocation.x, y)); } } } }); } + private static @NotNull Dimension getFullPopupSize(@NotNull JBPopup popup){ + Dimension contentSize = popup.getSize(); + int footerAdvertisementHeight = popup instanceof AbstractPopup abstractPopup ? abstractPopup.getAdComponentHeight() : 0; + return new Dimension(contentSize.width, contentSize.height + footerAdvertisementHeight); + } + @NotNull private MenuItemPresentationFactory createPresentationFactory() { return new MenuItemPresentationFactory() { diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt index 86922a48078a..e3232aa19ded 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/FloatingToolbar.kt @@ -50,7 +50,7 @@ open class FloatingToolbar( private val coroutineScope: CoroutineScope, protected val defaultActionGroupId: String ): Disposable { - private var hint: LightweightHint? = null + protected var hint: LightweightHint? = null private var buttonSize: Int by Delegates.notNull() private var lastSelection: String? = null private var hintWasShownForSelection = false @@ -98,10 +98,10 @@ open class FloatingToolbar( @RequiresEdt private suspend fun showIfHidden() { - if (isShown() || hintWasShownForSelection) { + hintWasShownForSelection = true + if (isShown() || !isEnabled()) { return } - hintWasShownForSelection = true val canBeShownAtCurrentSelection = readAction { canBeShownAtCurrentSelection() } if (!canBeShownAtCurrentSelection) { return @@ -114,6 +114,15 @@ open class FloatingToolbar( this.hint = hint } + fun show(callback: Runnable){ + coroutineScope.launch { + withContext(Dispatchers.EDT) { + showIfHidden() + callback.run() + } + } + } + private suspend fun createHint(): LightweightHint { val toolbar = createUpdatedActionToolbar(editor.contentComponent) val component = BorderLayoutPanel().apply { @@ -126,7 +135,7 @@ open class FloatingToolbar( } fun scheduleShow() { - if (isEnabled()) { + if (isEnabled() && !hintWasShownForSelection) { check(hintRequests.tryEmit(HintRequest.Show)) } } From f3b660c2d85b333ae331e04d84324f43f5e2da61 Mon Sep 17 00:00:00 2001 From: Alexandr Suhinin Date: Fri, 30 Jun 2023 19:17:26 +0300 Subject: [PATCH 074/226] [floating toolbar] IDEA-322906: hide toolbar after disabling GitOrigin-RevId: b7e2d648aeb82e20dbf5b6e1bed6c71ec02c233e --- .../intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt | 4 ++-- .../codeFloatingToolbar/DisableCodeFloatingToolbarAction.kt | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt index f5c8d91c1532..d2a6b73c9792 100644 --- a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt +++ b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/CodeFloatingToolbar.kt @@ -37,8 +37,8 @@ class CodeFloatingToolbar( private val FLOATING_TOOLBAR = Key("floating.codeToolbar") @JvmStatic - fun getToolbar(editor: Editor): CodeFloatingToolbar? { - return editor.getUserData(FLOATING_TOOLBAR) + fun getToolbar(editor: Editor?): CodeFloatingToolbar? { + return editor?.getUserData(FLOATING_TOOLBAR) } } diff --git a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/DisableCodeFloatingToolbarAction.kt b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/DisableCodeFloatingToolbarAction.kt index 197efb4ac9bd..d7d9b0503ad6 100644 --- a/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/DisableCodeFloatingToolbarAction.kt +++ b/platform/lang-impl/src/com/intellij/ui/codeFloatingToolbar/DisableCodeFloatingToolbarAction.kt @@ -3,10 +3,13 @@ package com.intellij.ui.codeFloatingToolbar import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.options.advanced.AdvancedSettings class DisableCodeFloatingToolbarAction: AnAction() { override fun actionPerformed(e: AnActionEvent) { AdvancedSettings.setBoolean("floating.codeToolbar.hide", true) + val editor = e.dataContext.getData(CommonDataKeys.EDITOR) + CodeFloatingToolbar.getToolbar(editor)?.scheduleHide() } } \ No newline at end of file From ddc91500eff1475f828ac30e9d783a2c7613dd17 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Fri, 30 Jun 2023 18:59:55 +0200 Subject: [PATCH 075/226] json: support "Sort properties alphabetically" intention when caret is after last symbol GitOrigin-RevId: d51665f0e1a1cc8f20af8df39525afd48c438869 --- .../intentions/JsonSortPropertiesIntention.kt | 18 ++++++++++-------- .../JsonSortPropertiesIntentionTest.kt | 4 ++++ .../SortWhenCaretAfterLastSymbol.json | 7 +++++++ .../SortWhenCaretAfterLastSymbol_after.json | 6 ++++++ 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 json/tests/testData/intention/SortWhenCaretAfterLastSymbol.json create mode 100644 json/tests/testData/intention/SortWhenCaretAfterLastSymbol_after.json diff --git a/json/src/com/intellij/json/intentions/JsonSortPropertiesIntention.kt b/json/src/com/intellij/json/intentions/JsonSortPropertiesIntention.kt index 2569ad189afe..efc785fb1923 100644 --- a/json/src/com/intellij/json/intentions/JsonSortPropertiesIntention.kt +++ b/json/src/com/intellij/json/intentions/JsonSortPropertiesIntention.kt @@ -1,10 +1,11 @@ // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.json.intentions +import com.intellij.codeInsight.intention.BaseElementAtCaretIntentionAction import com.intellij.codeInsight.intention.LowPriorityAction -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction import com.intellij.ide.lightEdit.LightEditCompatible import com.intellij.json.JsonBundle +import com.intellij.json.psi.JsonFile import com.intellij.json.psi.JsonObject import com.intellij.json.psi.JsonProperty import com.intellij.json.psi.impl.JsonRecursiveElementVisitor @@ -19,7 +20,7 @@ import com.intellij.refactoring.util.CommonRefactoringUtil import com.intellij.util.IncorrectOperationException import org.jetbrains.annotations.Nls -open class JsonSortPropertiesIntention : PsiElementBaseIntentionAction(), LowPriorityAction, LightEditCompatible, DumbAware { +open class JsonSortPropertiesIntention : BaseElementAtCaretIntentionAction(), LowPriorityAction, LightEditCompatible, DumbAware { override fun getText(): @Nls(capitalization = Nls.Capitalization.Sentence) String = JsonBundle.message("json.intention.sort.properties") override fun getFamilyName(): @Nls(capitalization = Nls.Capitalization.Sentence) String = @@ -65,9 +66,9 @@ open class JsonSortPropertiesIntention : PsiElementBaseIntentionAction(), LowPri } private fun collectObjects(rootObj: JsonObject): Set { - val result : MutableSet = LinkedHashSet() + val result: MutableSet = LinkedHashSet() if (selectionModel.hasSelection()) { - object: JsonRecursiveElementVisitor() { + object : JsonRecursiveElementVisitor() { override fun visitObject(o: JsonObject) { super.visitObject(o) if (o.textRange?.intersects(selectionModel.selectionStart, selectionModel.selectionEnd) == true) { @@ -81,7 +82,10 @@ open class JsonSortPropertiesIntention : PsiElementBaseIntentionAction(), LowPri } private fun findRootObject(): JsonObject? { - val initObj = PsiTreeUtil.getParentOfType(contextElement, JsonObject::class.java) + val initObj: JsonObject? = PsiTreeUtil.getParentOfType(contextElement, JsonObject::class.java) ?: run { + val jsonFile = contextElement.containingFile as? JsonFile ?: return@run null + return jsonFile.allTopLevelValues.filterIsInstance().firstOrNull() + } if (initObj == null || !selectionModel.hasSelection()) { return initObj } @@ -92,7 +96,7 @@ open class JsonSortPropertiesIntention : PsiElementBaseIntentionAction(), LowPri return obj } - fun hasUnsortedObjects() : Boolean = objects.any { !isSorted(it) } + fun hasUnsortedObjects(): Boolean = objects.any { !isSorted(it) } fun sort() { objects.forEach { @@ -101,9 +105,7 @@ open class JsonSortPropertiesIntention : PsiElementBaseIntentionAction(), LowPri } } } - } - companion object { private fun isSorted(obj: JsonObject): Boolean { return obj.propertyList.asSequence() .map { it.name } diff --git a/json/tests/test/com/intellij/json/intentions/JsonSortPropertiesIntentionTest.kt b/json/tests/test/com/intellij/json/intentions/JsonSortPropertiesIntentionTest.kt index befc914d4fe7..feacaad07d75 100644 --- a/json/tests/test/com/intellij/json/intentions/JsonSortPropertiesIntentionTest.kt +++ b/json/tests/test/com/intellij/json/intentions/JsonSortPropertiesIntentionTest.kt @@ -25,4 +25,8 @@ class JsonSortPropertiesIntentionTest : JsonTestCase() { fun testSortRecursively() { doTest() } + + fun testSortWhenCaretAfterLastSymbol() { + doTest() + } } \ No newline at end of file diff --git a/json/tests/testData/intention/SortWhenCaretAfterLastSymbol.json b/json/tests/testData/intention/SortWhenCaretAfterLastSymbol.json new file mode 100644 index 000000000000..5c589779d5af --- /dev/null +++ b/json/tests/testData/intention/SortWhenCaretAfterLastSymbol.json @@ -0,0 +1,7 @@ +{ + "version": "1.0.0", + "main": "index.js", + "name": "my-app", + "license": "MIT" +} + \ No newline at end of file diff --git a/json/tests/testData/intention/SortWhenCaretAfterLastSymbol_after.json b/json/tests/testData/intention/SortWhenCaretAfterLastSymbol_after.json new file mode 100644 index 000000000000..4d381a1ee713 --- /dev/null +++ b/json/tests/testData/intention/SortWhenCaretAfterLastSymbol_after.json @@ -0,0 +1,6 @@ +{ + "license": "MIT", + "main": "index.js", + "name": "my-app", + "version": "1.0.0" +} From fb8f1663140577caf6e5bb1c08c3c65dc25064d2 Mon Sep 17 00:00:00 2001 From: "lada.gagina" Date: Fri, 30 Jun 2023 16:49:47 +0200 Subject: [PATCH 076/226] [python] fix IOOBE in PyDictLiteralCompletionContributor (DS-5159) GitOrigin-RevId: 7943a0ef0c28b365898af9c10b1cd1da4f26c462 --- .../completion/PyDictLiteralCompletionContributor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyDictLiteralCompletionContributor.kt b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyDictLiteralCompletionContributor.kt index 8ad5d27712ad..e9a17d91ca2c 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyDictLiteralCompletionContributor.kt +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyDictLiteralCompletionContributor.kt @@ -54,7 +54,7 @@ private class DictLiteralCompletionProvider : CompletionProvider Date: Fri, 30 Jun 2023 19:20:58 +0200 Subject: [PATCH 077/226] [ui] dropping the old "About" popup implementation and related stuff GitOrigin-RevId: 0866af8c07859d305ba0e7b3c8038865691c75f4 --- .../application/ex/ApplicationInfoEx.java | 12 - .../application/impl/ApplicationInfoImpl.java | 96 +- .../resources/messages/IdeBundle.properties | 1 + .../ide/AboutPopupDescriptionProvider.kt | 6 +- .../com/intellij/ide/actions/AboutAction.java | 11 +- .../com/intellij/ide/actions/AboutDialog.java | 211 ++++- .../com/intellij/ide/actions/AboutPopup.java | 834 ------------------ .../ui/ShowAboutPopupInDebugModeAction.java | 22 - .../src/messages/ActionsBundle.properties | 3 +- .../src/idea/ApplicationInfo.xsd | 3 +- .../src/idea/PlatformActions.xml | 1 - .../util/resources/misc/registry.properties | 3 - 12 files changed, 190 insertions(+), 1013 deletions(-) delete mode 100644 platform/platform-impl/src/com/intellij/ide/actions/AboutPopup.java delete mode 100644 platform/platform-impl/src/com/intellij/internal/ui/ShowAboutPopupInDebugModeAction.java diff --git a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java index 9dc24fdfe570..f46cf3e1ffce 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java +++ b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java @@ -20,8 +20,6 @@ public abstract class ApplicationInfoEx extends ApplicationInfo { public abstract String getSplashImageUrl(); - public abstract String getAboutImageUrl(); - /** @deprecated please use {@link #getSmallApplicationSvgIconUrl()} instead */ @Deprecated @ApiStatus.ScheduledForRemoval @@ -47,8 +45,6 @@ public abstract class ApplicationInfoEx extends ApplicationInfo { @ApiStatus.ScheduledForRemoval public abstract @Nullable String getWelcomeScreenLogoUrl(); - public abstract boolean showLicenseeInfo(); - public abstract String getCopyrightStart(); public abstract boolean isEAP(); @@ -96,10 +92,6 @@ public abstract class ApplicationInfoEx extends ApplicationInfo { public abstract String getMacKeymapUrl(); - public abstract long getAboutForeground(); - - public abstract long getAboutLinkColor(); - public interface UpdateUrls { String getCheckingUrl(); String getPatchesUrl(); @@ -114,8 +106,6 @@ public abstract class ApplicationInfoEx extends ApplicationInfo { public abstract @Nullable String getWelcomeWizardDialog(); - public abstract int @Nullable [] getAboutLogoRect(); - public abstract String getSubscriptionFormId(); public abstract String getSubscriptionNewsKey(); @@ -135,8 +125,6 @@ public abstract class ApplicationInfoEx extends ApplicationInfo { return "JetBrains".equals(getShortCompanyName()); } - public abstract long getCopyrightForeground(); - public abstract @NotNull BuildNumber getApiVersionAsNumber(); public abstract @NotNull List getEssentialPluginsIds(); diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java index d954c19f3daa..a0b6b18bb306 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java @@ -54,13 +54,8 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { private String myCopyrightStart = "2000"; private String myShortCompanyName; private String myCompanyUrl = "https://www.jetbrains.com/"; - private long myCopyrightForeground = -1; - private long myAboutForeground = -1; - private long myAboutLinkColor = -1; - private int[] myAboutLogoRect; // don't use Rectangle to avoid dependency on AWT private String mySplashImageUrl; private String myEapSplashImageUrl; - private String myAboutImageUrl; private String mySmallIconUrl = "/icon_small.png"; private String mySvgIconUrl; private String mySvgEapIconUrl; @@ -71,7 +66,6 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { private Calendar myBuildDate; private Calendar myMajorReleaseBuildDate; - private boolean myShowLicensee = true; private String myWelcomeScreenDialog; private UpdateUrls myUpdateUrls; private String myDocumentationUrl; @@ -157,37 +151,6 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { } break; - case "about": { - myAboutImageUrl = child.getAttributeValue("url"); - - String v = child.getAttributeValue("foreground"); - if (v != null) { - myAboutForeground = parseColor(v); - } - v = child.getAttributeValue("copyrightForeground"); - if (v != null) { - myCopyrightForeground = parseColor(v); - } - - String c = child.getAttributeValue("linkColor"); - if (c != null) { - myAboutLinkColor = parseColor(c); - } - - String logoX = child.getAttributeValue("logoX"); - String logoY = child.getAttributeValue("logoY"); - String logoW = child.getAttributeValue("logoW"); - String logoH = child.getAttributeValue("logoH"); - if (logoX != null && logoY != null && logoW != null && logoH != null) { - try { - myAboutLogoRect = new int[]{Integer.parseInt(logoX), Integer.parseInt(logoY), Integer.parseInt(logoW), Integer.parseInt(logoH)}; - } - catch (NumberFormatException ignored) { - } - } - } - break; - case "icon": { mySmallIconUrl = child.getAttributeValue("size16", mySmallIconUrl); String toolWindowIcon = getAttributeValue(child, "size12"); @@ -205,11 +168,6 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { } break; - case "licensee": { - myShowLicensee = Boolean.parseBoolean(child.getAttributeValue("show")); - } - break; - case "welcome-screen": { myWelcomeScreenLogoUrl = child.getAttributeValue("logo-url"); } @@ -501,16 +459,6 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { return isEAP() && myEapSplashImageUrl != null ? myEapSplashImageUrl : mySplashImageUrl; } - @Override - public String getAboutImageUrl() { - return myAboutImageUrl; - } - - @Override - public long getCopyrightForeground() { - return myCopyrightForeground; - } - @Override public @NotNull String getSmallIconUrl() { return mySmallIconUrl; @@ -648,26 +596,11 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { return myMacKeymapUrl; } - @Override - public long getAboutForeground() { - return myAboutForeground; - } - - @Override - public long getAboutLinkColor() { - return myAboutLinkColor; - } - @Override public String getFullApplicationName() { return getVersionName() + " " + getFullVersion(); } - @Override - public boolean showLicenseeInfo() { - return myShowLicensee; - } - @Override public String getCopyrightStart() { return myCopyrightStart; @@ -687,11 +620,6 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { return myKeyConversionUrl; } - @Override - public int @Nullable [] getAboutLogoRect() { - return myAboutLogoRect; - } - @Override public String getSubscriptionFormId() { return mySubscriptionFormId; @@ -834,10 +762,6 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { return calendar; } - private static long parseColor(String colorString) { - return Long.parseLong(colorString, 16); - } - @ReviseWhenPortedToJDK("9") private static String requireNonNullElse(String s) { return s != null ? s : "0"; @@ -861,37 +785,25 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { @Override public @Nullable String getDefaultLightLaf() { String override = System.getProperty(IDEA_APPLICATION_INFO_DEFAULT_LIGHT_LAF); - if (override != null) { - return override; - } - return myDefaultLightLaf; + return override != null ? override : myDefaultLightLaf; } @Override public @Nullable String getDefaultClassicLightLaf() { String override = System.getProperty(IDEA_APPLICATION_INFO_DEFAULT_CLASSIC_LIGHT_LAF); - if (override != null) { - return override; - } - return myDefaultClassicLightLaf; + return override != null ? override : myDefaultClassicLightLaf; } @Override public @Nullable String getDefaultDarkLaf() { String override = System.getProperty(IDEA_APPLICATION_INFO_DEFAULT_DARK_LAF); - if (override != null) { - return override; - } - return myDefaultDarkLaf; + return override != null ? override : myDefaultDarkLaf; } @Override public @Nullable String getDefaultClassicDarkLaf() { String override = System.getProperty(IDEA_APPLICATION_INFO_DEFAULT_CLASSIC_DARK_LAF); - if (override != null) { - return override; - } - return myDefaultClassicDarkLaf; + return override != null ? override : myDefaultClassicDarkLaf; } public @Nullable ZenDeskForm getFeedbackForm() { diff --git a/platform/platform-api/resources/messages/IdeBundle.properties b/platform/platform-api/resources/messages/IdeBundle.properties index 9f81f5f46d7f..33d01aa249ac 100644 --- a/platform/platform-api/resources/messages/IdeBundle.properties +++ b/platform/platform-api/resources/messages/IdeBundle.properties @@ -2373,6 +2373,7 @@ dialog.message.no.message=No message dialog.text.error.getting.value=Error getting value: {0} recent.project.unavailable=(unavailable) search.everywhere.command.plugins=Plugins: {0} +progress.third.party.software=Loading Third-Party Software Licenses dialog.title.third.party.software=Third-Party Software Used by {0} {1} status.bar.text.script.execution.finished=Script execution finished status.bar.message.at.line=Line {0}: {1} diff --git a/platform/platform-impl/src/com/intellij/ide/AboutPopupDescriptionProvider.kt b/platform/platform-impl/src/com/intellij/ide/AboutPopupDescriptionProvider.kt index 11b1b411f1ae..cd57568d8293 100644 --- a/platform/platform-impl/src/com/intellij/ide/AboutPopupDescriptionProvider.kt +++ b/platform/platform-impl/src/com/intellij/ide/AboutPopupDescriptionProvider.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide import com.intellij.openapi.util.NlsContexts.DetailedDescription @@ -10,7 +10,7 @@ import com.intellij.openapi.util.NlsContexts.DetailedDescription */ interface AboutPopupDescriptionProvider { /** - * Return additional info which should be shown in About popup. + * Return additional info which should be shown in the "About" dialog. */ fun getDescription(): @DetailedDescription String? -} \ No newline at end of file +} diff --git a/platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java b/platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java index 0bdc00aa3bf2..014c414a9db1 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.actions; import com.intellij.ide.lightEdit.LightEditCompatible; @@ -7,8 +7,6 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.wm.WindowManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,11 +28,6 @@ public class AboutAction extends AnAction implements DumbAware, LightEditCompati } public static void perform(@Nullable Project project) { - if (Registry.is("ide.new.about.dialog")) { - new AboutDialog(project).show(); - } - else { - AboutPopup.show(WindowManager.getInstance().suggestParentWindow(project), false); - } + new AboutDialog(project).show(); } } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/AboutDialog.java b/platform/platform-impl/src/com/intellij/ide/actions/AboutDialog.java index e7a52b9cffac..be22614f93d2 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/AboutDialog.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/AboutDialog.java @@ -1,53 +1,76 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.actions; +import com.intellij.CommonBundle; import com.intellij.ide.AboutPopupDescriptionProvider; import com.intellij.ide.IdeBundle; import com.intellij.ide.nls.NlsMessages; +import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.ex.ApplicationInfoEx; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.ide.CopyPasteManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.NlsContexts; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.AppUIUtil; -import com.intellij.ui.HyperlinkAdapter; -import com.intellij.ui.HyperlinkLabel; -import com.intellij.ui.LicensingFacade; +import com.intellij.openapi.util.NlsSafe; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtilRt; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.registry.RegistryValue; +import com.intellij.openapi.vfs.DiskQueryRelay; +import com.intellij.ui.*; import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.scale.JBUIScale; import com.intellij.ui.scale.ScaleContext; -import com.intellij.util.ObjectUtils; -import com.intellij.util.ui.JBFont; -import com.intellij.util.ui.JBUI; +import com.intellij.util.PlatformUtils; +import com.intellij.util.ui.*; import com.intellij.util.ui.components.BorderLayoutPanel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.HyperlinkEvent; +import javax.swing.text.html.HTMLDocument; import java.awt.*; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; +import java.io.IOException; +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.nio.file.Files; +import java.nio.file.Path; import java.text.DateFormat; import java.text.MessageFormat; import java.text.SimpleDateFormat; +import java.time.LocalDate; import java.util.List; import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static java.util.Objects.requireNonNullElse; +import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER; +import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED; -/** - * @author Konstantin Bulenkov - */ public class AboutDialog extends DialogWrapper { + private static final ExtensionPointName EP_NAME = new ExtensionPointName<>("com.intellij.aboutPopupDescriptionProvider"); /** - * Use paragraph to support copy/paste multilines + * See {@link org.jetbrains.intellij.build.impl.DistributionJARsBuilderKt#createBuildThirdPartyLibraryListJob}. */ - private static final String EOL = "

"; + private static final String THIRD_PARTY_LIBRARIES_FILE = "license/third-party-libraries.html"; private final List myInfo = new ArrayList<>(); @@ -64,7 +87,7 @@ public class AboutDialog extends DialogWrapper { protected JComponent createSouthPanel() { JComponent result = super.createSouthPanel(); - // Register copy action on buttons panel only, because it conflicts with copyable labels in center panel + // Registering the copy action only on the buttons panel, because it conflicts with copyable labels in the center panel new DumbAwareAction() { @Override public void actionPerformed(@NotNull AnActionEvent e) { @@ -115,16 +138,12 @@ public class AboutDialog extends DialogWrapper { catch (Exception ignore) { } } - public String getExtendedAboutText() { - return StringUtil.join(myInfo, "\n") + "\n" + AboutPopup.getExtraInfo(); - } - - @SuppressWarnings("DuplicatedCode") private Box getText() { Box box = Box.createVerticalBox(); List lines = new ArrayList<>(); ApplicationInfoEx appInfo = ApplicationInfoEx.getInstanceEx(); - String appName = appInfo.getFullApplicationName(); //NON-NLS + + @NlsSafe String appName = appInfo.getFullApplicationName(); String edition = ApplicationNamesInfo.getInstance().getEditionName(); if (edition != null) appName += " (" + edition + ")"; box.add(label(appName, JBFont.h3().asBold())); @@ -133,17 +152,16 @@ public class AboutDialog extends DialogWrapper { String buildInfo = IdeBundle.message("about.box.build.number", appInfo.getBuild().asString()); String buildInfoNonLocalized = MessageFormat.format("Build #{0}", appInfo.getBuild().asString()); - Date timestamp = appInfo.getBuildDate().getTime(); + Date buildDate = appInfo.getBuildDate().getTime(); + String formattedBuildDate = DateFormat.getDateInstance(DateFormat.LONG, Locale.US).format(buildDate); if (appInfo.getBuild().isSnapshot()) { - String time = new SimpleDateFormat("HH:mm").format(timestamp); - buildInfo += IdeBundle.message("about.box.build.date.time", NlsMessages.formatDateLong(timestamp), time); - buildInfoNonLocalized += MessageFormat.format(", built on {0} at {1}", - DateFormat.getDateInstance(DateFormat.LONG, Locale.US).format(timestamp), time); + String buildTime = new SimpleDateFormat("HH:mm").format(buildDate); + buildInfo += IdeBundle.message("about.box.build.date.time", NlsMessages.formatDateLong(buildDate), buildTime); + buildInfoNonLocalized += MessageFormat.format(", built on {0} at {1}", formattedBuildDate, buildTime); } else { - buildInfo += IdeBundle.message("about.box.build.date", NlsMessages.formatDateLong(timestamp)); - buildInfoNonLocalized += MessageFormat.format(", built on {0}", - DateFormat.getDateInstance(DateFormat.LONG, Locale.US).format(timestamp)); + buildInfo += IdeBundle.message("about.box.build.date", NlsMessages.formatDateLong(buildDate)); + buildInfoNonLocalized += MessageFormat.format(", built on {0}", formattedBuildDate); } lines.add(buildInfo); lines.add(""); @@ -151,7 +169,7 @@ public class AboutDialog extends DialogWrapper { LicensingFacade la = LicensingFacade.getInstance(); if (la != null) { - final String licensedTo = la.getLicensedToMessage(); //NON-NLS + String licensedTo = la.getLicensedToMessage(); if (licensedTo != null) { lines.add(licensedTo); myInfo.add(licensedTo); @@ -179,14 +197,14 @@ public class AboutDialog extends DialogWrapper { //Print extra information from plugins ExtensionPointName ep = new ExtensionPointName<>("com.intellij.aboutPopupDescriptionProvider"); for (AboutPopupDescriptionProvider aboutInfoProvider : ep.getExtensions()) { - String description = aboutInfoProvider.getDescription(); //NON-NLS + String description = aboutInfoProvider.getDescription(); if (description != null) { lines.add(description); lines.add(""); } } - String text = String.join(EOL, lines); //NON-NLS + @NlsSafe String text = String.join("

", lines); // joining with paragraph separators for better-looking copied text box.add(label(text, getDefaultTextFont())); addEmptyLine(box); @@ -197,7 +215,7 @@ public class AboutDialog extends DialogWrapper { openSourceSoftware.addHyperlinkListener(new HyperlinkAdapter() { @Override protected void hyperlinkActivated(@NotNull HyperlinkEvent e) { - AboutPopup.showOpenSoftwareSources(ObjectUtils.notNull(AboutPopup.loadThirdPartyLibraries(), "")); + showOssInfo(box); } }); openSourceSoftware.setFont(getDefaultTextFont()); @@ -207,7 +225,9 @@ public class AboutDialog extends DialogWrapper { box.add(panel); //Copyright - box.add(label(AboutPopup.getCopyrightText(), getDefaultTextFont())); + int year = LocalDate.now().getYear(); + @NlsSafe String copyrightText = String.format(Locale.ROOT, "Copyright © %s–%d %s", appInfo.getCopyrightStart(), year, appInfo.getCompanyName()); + box.add(label(copyrightText, getDefaultTextFont())); addEmptyLine(box); return box; @@ -226,4 +246,127 @@ public class AboutDialog extends DialogWrapper { label.setCopyable(true); return label; } + + public String getExtendedAboutText() { + var text = new StringBuilder(); + + myInfo.forEach(s -> text.append(s).append('\n')); + + text.append(SystemInfo.getOsNameAndVersion()).append('\n'); + + for (var aboutInfoProvider : EP_NAME.getExtensions()) { + var description = aboutInfoProvider.getDescription(); + if (description != null) { + text.append(description).append('\n'); + } + } + + text.append("GC: ") + .append(ManagementFactory.getGarbageCollectorMXBeans().stream().map(GarbageCollectorMXBean::getName).collect(Collectors.joining(", "))) + .append('\n'); + + text.append("Memory: ").append(Runtime.getRuntime().maxMemory() / FileUtilRt.MEGABYTE).append("M\n"); + + text.append("Cores: ").append(Runtime.getRuntime().availableProcessors()).append('\n'); + + if (UIUtil.isMetalRendering()) { + text.append("Metal Rendering is ON\n"); + } + + var changedValues = Registry.getAll().stream().filter(RegistryValue::isChangedFromDefault).toList(); + if (!changedValues.isEmpty()) { + text.append("Registry:\n"); + changedValues.forEach(v -> text.append(" ").append(v.getKey()).append('=').append(v.asString()).append('\n')); + } + + var extraPlugins = PluginManagerCore.getLoadedPlugins().stream().filter(p -> !p.isBundled()).toList(); + if (!extraPlugins.isEmpty()) { + text.append("Non-Bundled Plugins:\n"); + extraPlugins.forEach(p -> text.append(" ").append(p.getPluginId().getIdString()).append(" (").append(p.getVersion()).append(")\n")); + } + + if (PlatformUtils.isIntelliJ()) { + var kotlinPlugin = PluginManagerCore.getPlugin(PluginId.findId("org.jetbrains.kotlin")); + if (kotlinPlugin != null) { + text.append("Kotlin: ").append(kotlinPlugin.getVersion()).append('\n'); + } + } + + if (SystemInfo.isXWindow) { + text.append("Current Desktop: ").append(requireNonNullElse(System.getenv("XDG_CURRENT_DESKTOP"), "Undefined")).append('\n'); + } + + return text.toString(); + } + + private static void showOssInfo(JComponent component) { + @NlsSafe String licenseText; + try { + var title = IdeBundle.message("progress.third.party.software"); + licenseText = ProgressManager.getInstance().run(new Task.WithResult(null, component, title, true) { + @Override + protected String compute(@NotNull ProgressIndicator indicator) throws IOException { + return DiskQueryRelay.compute(() -> { + var content = Files.readString(Path.of(PathManager.getHomePath(), THIRD_PARTY_LIBRARIES_FILE)); + var matcher = Pattern.compile("(\\d+)px").matcher(content); + var sb = new StringBuilder(); + while (matcher.find()) { + matcher.appendReplacement(sb, JBUIScale.scale(Integer.parseInt(matcher.group(1))) + "px"); + } + matcher.appendTail(sb); + content = sb.toString(); + if (StartupUiUtil.isUnderDarcula()) { + content = content.replace("779dbd", "5676a0"); + } + return content; + }); + } + }); + } + catch (IOException e) { + Logger.getInstance(AboutDialog.class).error(e); + return; + } + + var dialog = new DialogWrapper(true) { + { + init(); + setAutoAdjustable(false); + setOKButtonText(CommonBundle.message("close.action.name")); + } + + @Override + protected JComponent createCenterPanel() { + var viewer = SwingHelper.createHtmlViewer(true, null, JBColor.WHITE, JBColor.BLACK); + viewer.setFocusable(true); + viewer.addHyperlinkListener(new BrowserHyperlinkListener()); + viewer.setText(licenseText); + + var styleSheet = ((HTMLDocument)viewer.getDocument()).getStyleSheet(); + styleSheet.addRule("body {font-family: \"Segoe UI\", Tahoma, \"Helvetica Neue\", Helvetica, Arial, sans-serif;}"); + styleSheet.addRule("body {margin-top:0;padding-top:0;}"); + styleSheet.addRule("body {font-size:" + JBUIScale.scaleFontSize((float)14) + "pt;}"); + + viewer.setCaretPosition(0); + viewer.setBorder(JBUI.Borders.empty(0, 5, 5, 5)); + + var scrollPane = new JBScrollPane(viewer, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_NEVER); + + var centerPanel = new JPanel(new BorderLayout(JBUIScale.scale(5), JBUIScale.scale(5))); + centerPanel.add(scrollPane, BorderLayout.CENTER); + return centerPanel; + } + + @Override + protected Action @NotNull [] createActions() { + return new Action[]{getOKAction()}; + } + }; + + dialog.setTitle(IdeBundle.message("dialog.title.third.party.software", + ApplicationNamesInfo.getInstance().getFullProductName(), + ApplicationInfo.getInstance().getFullVersion())); + dialog.setSize(JBUIScale.scale(750), JBUIScale.scale(650)); + dialog.show(); + } } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/AboutPopup.java b/platform/platform-impl/src/com/intellij/ide/actions/AboutPopup.java deleted file mode 100644 index a144e8cdd05b..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/actions/AboutPopup.java +++ /dev/null @@ -1,834 +0,0 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.ide.actions; - -import com.intellij.CommonBundle; -import com.intellij.icons.AllIcons; -import com.intellij.ide.AboutPopupDescriptionProvider; -import com.intellij.ide.BrowserUtil; -import com.intellij.ide.IdeBundle; -import com.intellij.ide.nls.NlsMessages; -import com.intellij.ide.plugins.IdeaPluginDescriptor; -import com.intellij.ide.plugins.PluginManagerCore; -import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.application.ApplicationInfo; -import com.intellij.openapi.application.ApplicationNamesInfo; -import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.application.ex.ApplicationInfoEx; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.extensions.PluginId; -import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.GraphicsConfig; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.util.NlsSafe; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.io.FileUtilRt; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.util.registry.RegistryValue; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.BrowserHyperlinkListener; -import com.intellij.ui.JBColor; -import com.intellij.ui.LicensingFacade; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.ui.components.JBScrollPane; -import com.intellij.ui.scale.JBUIScale; -import com.intellij.util.Alarm; -import com.intellij.util.MathUtil; -import com.intellij.util.PlatformUtils; -import com.intellij.util.ui.*; -import com.intellij.util.ui.accessibility.AccessibleContextUtil; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.accessibility.AccessibleAction; -import javax.accessibility.AccessibleContext; -import javax.swing.*; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.StyleSheet; -import java.awt.*; -import java.awt.event.*; -import java.io.File; -import java.io.IOException; -import java.lang.management.GarbageCollectorMXBean; -import java.lang.management.ManagementFactory; -import java.text.DateFormat; -import java.text.MessageFormat; -import java.text.SimpleDateFormat; -import java.util.List; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collector; -import java.util.stream.Collectors; - -import static com.intellij.util.ObjectUtils.notNull; -import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER; -import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED; - -/** - * @author Konstantin Bulenkov - */ -public final class AboutPopup { - private static JBPopup ourPopup; - private static final Logger LOG = Logger.getInstance(AboutPopup.class); - /** - * File with third party libraries HTML content, - * see the same constant at org.jetbrains.intellij.build.impl.DistributionJARsBuilder#THIRD_PARTY_LIBRARIES_FILE_PATH - */ - private static final String THIRD_PARTY_LIBRARIES_FILE_PATH = "license/third-party-libraries.html"; - - public static void show(@Nullable Window window, boolean showDebugInfo) { - ApplicationInfoEx appInfo = (ApplicationInfoEx)ApplicationInfo.getInstance(); - - final PopupPanel panel = new PopupPanel(new BorderLayout()); - Icon image = IconLoader.getIcon(appInfo.getAboutImageUrl(), AboutPopup.class.getClassLoader()); - if (appInfo.showLicenseeInfo()) { - final InfoSurface infoSurface = new InfoSurface(image, showDebugInfo); - infoSurface.setPreferredSize(new Dimension(image.getIconWidth(), image.getIconHeight())); - panel.setInfoSurface(infoSurface); - } - else { - panel.add(new JLabel(image), BorderLayout.NORTH); - } - - RelativePoint location; - if (window != null) { - Rectangle r = window.getBounds(); - location = new RelativePoint(window, new Point((r.width - image.getIconWidth()) / 2, (r.height - image.getIconHeight()) / 2)); - } - else { - Rectangle r = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds(); - location = new RelativePoint(new Point((r.width - image.getIconWidth()) / 2, (r.height - image.getIconHeight()) / 2)); - } - - ourPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, panel) - .setRequestFocus(true) - .setFocusable(true) - .setResizable(false) - .setMovable(false) - .setModalContext(false) - .setShowShadow(true) - .setShowBorder(false) - .setCancelKeyEnabled(true) - .setCancelOnClickOutside(true) - .setCancelOnOtherWindowOpen(true) - .createPopup(); - - Disposer.register(ourPopup, new Disposable() { - @Override - @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") - public void dispose() { - ourPopup = null; - } - }); - - ourPopup.show(location); - } - - static @Nullable String loadThirdPartyLibraries() { - final File thirdPartyLibrariesFile = new File(PathManager.getHomePath(), THIRD_PARTY_LIBRARIES_FILE_PATH); - if (thirdPartyLibrariesFile.isFile()) { - try { - return FileUtil.loadFile(thirdPartyLibrariesFile); - } - catch (IOException e) { - LOG.warn(e); - } - } - return null; - } - - static @NotNull @Nls String getCopyrightText() { - ApplicationInfoEx appInfo = ApplicationInfoEx.getInstanceEx(); - // Copyright message should not be translated - @NlsSafe - String copyrightText = String.format(Locale.ROOT, - "Copyright © %s–%d %s", appInfo.getCopyrightStart(), Calendar.getInstance(Locale.US).get(Calendar.YEAR), appInfo.getCompanyName()); - return copyrightText; - } - - private static final class InfoSurface extends JPanel { - private static final ExtensionPointName EP_NAME = new ExtensionPointName<>("com.intellij.aboutPopupDescriptionProvider"); - - private final Color myColor; - private final Color myLinkColor; - private final Icon myImage; - private final boolean myShowDebugInfo; - private Font myFont; - private Font myBoldFont; - private final List myLines = new ArrayList<>(); - private final StringBuilder myInfo = new StringBuilder(); - private final List myLinks = new ArrayList<>(); - private Link myActiveLink; - private boolean myShowCopy = false; - private float myShowCopyAlpha; - private final Alarm myAlarm = new Alarm(); - - InfoSurface(Icon image, final boolean showDebugInfo) { - ApplicationInfoEx appInfo = ApplicationInfoEx.getInstanceEx(); - - myImage = image; - //noinspection UseJBColor - myColor = Color.white; - long aboutLinkColor = appInfo.getAboutLinkColor(); - //noinspection UseJBColor - myLinkColor = aboutLinkColor == -1 ? JBUI.CurrentTheme.Link.Foreground.ENABLED : new Color((int)aboutLinkColor, aboutLinkColor > 0xffffff); - myShowDebugInfo = showDebugInfo; - - setOpaque(false); - setBackground(myColor); - setFocusable(true); - - String appName = appInfo.getFullApplicationName(); - String edition = ApplicationNamesInfo.getInstance().getEditionName(); - if (edition != null) appName += " (" + edition + ")"; - myLines.add(new AboutBoxLine(appName, true)); - appendLast(); - - String buildInfo = IdeBundle.message("about.box.build.number", appInfo.getBuild().asString()); - String buildInfoNonLocalized = MessageFormat.format("Build #{0}", appInfo.getBuild().asString()); - Date timestamp = appInfo.getBuildDate().getTime(); - if (appInfo.getBuild().isSnapshot()) { - String time = new SimpleDateFormat("HH:mm").format(timestamp); - buildInfo += IdeBundle.message("about.box.build.date.time", NlsMessages.formatDateLong(timestamp), time); - buildInfoNonLocalized += MessageFormat.format(", built on {0} at {1}", - DateFormat.getDateInstance(DateFormat.LONG, Locale.US).format(timestamp), time); - } - else { - buildInfo += IdeBundle.message("about.box.build.date", NlsMessages.formatDateLong(timestamp)); - buildInfoNonLocalized += MessageFormat.format(", built on {0}", - DateFormat.getDateInstance(DateFormat.LONG, Locale.US).format(timestamp)); - } - myLines.add(new AboutBoxLine(buildInfo)); - myInfo.append(buildInfoNonLocalized).append("\n"); - - myLines.add(new AboutBoxLine("")); - - LicensingFacade la = LicensingFacade.getInstance(); - if (la != null) { - final String licensedTo = la.getLicensedToMessage(); - if (licensedTo != null) { - myLines.add(new AboutBoxLine(licensedTo, true)); - appendLast(); - } - for (String message : la.getLicenseRestrictionsMessages()) { - myLines.add(new AboutBoxLine(message)); - appendLast(); - } - } - - myLines.add(new AboutBoxLine("")); - - Properties properties = System.getProperties(); - String javaVersion = properties.getProperty("java.runtime.version", properties.getProperty("java.version", "unknown")); - String arch = properties.getProperty("os.arch", ""); - myLines.add(new AboutBoxLine(IdeBundle.message("about.box.jre", javaVersion, arch))); - myInfo.append(MessageFormat.format("Runtime version: {0} {1}\n", javaVersion, arch)); - - String vmVersion = properties.getProperty("java.vm.name", "unknown"); - String vmVendor = properties.getProperty("java.vendor", "unknown"); - myLines.add(new AboutBoxLine(IdeBundle.message("about.box.vm", vmVersion, vmVendor))); - myInfo.append(MessageFormat.format("VM: {0} by {1}\n", vmVersion, vmVendor)); - - myLines.add(new AboutBoxLine("")); - myLines.add(new AboutBoxLine("")); - myLines.add(new AboutBoxLine(IdeBundle.message("about.box.powered.by") + " ").keepWithNext()); - - final String thirdPartyLibraries = loadThirdPartyLibraries(); - if (thirdPartyLibraries != null) { - myLines.add(new AboutBoxLine(IdeBundle.message("about.box.open.source.software"), - () -> showOpenSoftwareSources(thirdPartyLibraries))); - } - else { - // When compiled from sources, third-party-libraries.html file isn't generated, so window can't be shown - myLines.add(new AboutBoxLine(IdeBundle.message("about.box.open.source.software"))); - } - - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent event) { - if (myActiveLink != null) { - event.consume(); - myActiveLink.actionPerformed(new ActionEvent(event.getSource(), event.getID(), event.paramString())); - } - - if (getCopyIconArea().contains(event.getPoint())) { - CopyPasteManager.copyTextToClipboard(getText()); - if (ourPopup != null) { - ourPopup.cancel(); - } - } - } - - static final double maxAlpha = 1.0; - static final double fadeStep = 0.05; - static final int animationDelay = 15; - - @Override - public void mouseEntered(MouseEvent e) { - if (!myShowCopy) { - myShowCopy = true; - myAlarm.cancelAllRequests(); - myAlarm.addRequest(new Runnable() { - @Override - public void run() { - if (myShowCopyAlpha < maxAlpha) { - myShowCopyAlpha = (float)Math.min(myShowCopyAlpha + fadeStep, maxAlpha); - repaint(); - myAlarm.addRequest(this, animationDelay); - } - } - }, animationDelay); - } - } - - @Override - public void mouseExited(MouseEvent e) { - if (myShowCopy) { - myShowCopy = false; - myAlarm.cancelAllRequests(); - myAlarm.addRequest(new Runnable() { - @Override - public void run() { - if (myShowCopyAlpha > 0) { - myShowCopyAlpha -= fadeStep; - repaint(); - myAlarm.addRequest(this, animationDelay); - } - } - }, animationDelay); - } - } - }); - - addMouseMotionListener(new MouseMotionAdapter() { - @Override - public void mouseMoved(MouseEvent event) { - boolean hadLink = (myActiveLink != null) || getCursor() == Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); - myActiveLink = null; - Point point = event.getPoint(); - for (Link link : myLinks) { - if (link.myRectangle.contains(point)) { - myActiveLink = link; - if (!hadLink) { - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } - return; - } - } - - if (getCopyIconArea().contains(point)) { - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - return; - } - - if (hadLink && myActiveLink == null) { - setCursor(Cursor.getDefaultCursor()); - } - } - }); - } - private static Rectangle getCopyIconArea() { - return new Rectangle(getCopyIconCoord(), JBUI.size(16)); - } - - private void appendLast() { - myInfo.append(myLines.get(myLines.size() - 1).getText()).append("\n"); - } - - @Override - public void paint(Graphics g) { - super.paint(g); - - Graphics2D g2 = (Graphics2D)g; - GraphicsConfig config = new GraphicsConfig(g); - UISettings.setupAntialiasing(g); - - Font labelFont; - if (SystemInfo.isWindows) { - labelFont = JBUI.Fonts.create("Segoe UI", 14); - } else if (SystemInfo.isMac) { - labelFont = JBUI.Fonts.create("Helvetica Neue", 13); - } else { - labelFont = JBUI.Fonts.create("Arial", 14); - } - - int startFontSize = 14; - for (int labelSize = JBUIScale.scale(startFontSize); labelSize != JBUIScale.scale(6); labelSize -= 1) { - myLinks.clear(); - g2.setPaint(myColor); - myImage.paintIcon(this, g2, 0, 0); - - g2.setColor(myColor); - TextRenderer renderer = createTextRenderer(g2); - UIUtil.setupComposite(g2); - myFont = labelFont.deriveFont(Font.PLAIN, labelSize); - myBoldFont = labelFont.deriveFont(Font.BOLD, labelSize + 1); - try { - renderer.render(0, 0, myLines); - break; - } - catch (TextRenderer.OverflowException ignore) { } - } - - ApplicationInfoEx appInfo = ApplicationInfoEx.getInstanceEx(); - int[] aboutLogoRect = appInfo.getAboutLogoRect(); - if (aboutLogoRect != null) { - myLinks.add(new Link(new JBRectangle(aboutLogoRect[0], aboutLogoRect[1], aboutLogoRect[2], aboutLogoRect[3]), appInfo.getCompanyURL())); - } - - long copyrightForeground = appInfo.getCopyrightForeground(); - Color color; - if (copyrightForeground < 0) { - color = JBColor.BLACK; - } - else { - //noinspection UseJBColor - color = new Color((int)copyrightForeground, copyrightForeground > 0xffffff); - } - g2.setColor(color); - if (SystemInfo.isWindows) { - g.setFont(JBUI.Fonts.create("Segoe UI", 10)); - } else if (SystemInfo.isMac) { - g.setFont(JBUI.Fonts.create("Helvetica Neue", 10)); - } else { - g.setFont(JBUI.Fonts.create("Arial", 10)); - } - - JBPoint copyrightCoord = getCopyrightCoord(); - g2.drawString(getCopyrightText(), copyrightCoord.x, copyrightCoord.y); - if (myShowDebugInfo) { - g2.setColor(createColor(appInfo.getAboutForeground())); - for (Link link : myLinks) { - g2.drawRect(link.myRectangle.x, link.myRectangle.y, link.myRectangle.width, link.myRectangle.height); - } - } - - config.restore(); - if (myShowCopy) { - JBPoint coord = getCopyIconCoord(); - float alpha = myShowCopyAlpha; - config = new GraphicsConfig(g).paintWithAlpha(MathUtil.clamp(alpha, 0f, 1f)); - AllIcons.General.CopyHovered.paintIcon(this, g, coord.x, coord.y); - config.restore(); - } - } - - private @NotNull TextRenderer createTextRenderer(Graphics2D g) { - Rectangle r = getTextRendererRect(); - return new TextRenderer(r.x, r.y, r.width, r.height, g); - } - - private static JBRectangle getTextRendererRect() { - return new JBRectangle(49, 169, 500, 220); - } - - private static JBPoint getCopyrightCoord() { - return new JBPoint(49, 365); - } - - private static JBPoint getCopyIconCoord() { - return new JBPoint(15, 155); - } - - public String getText() { - return myInfo + getExtraInfo(); - } - - private class TextRenderer { - private final int xBase; - private final int yBase; - private final int w; - private final int h; - private final Graphics2D g2; - - private int x = 0; - private int y = 0; - private FontMetrics fontmetrics; - private int fontAscent; - private int fontHeight; - private Font font; - - public static class OverflowException extends Exception { } - - TextRenderer(final int xBase, final int yBase, final int w, final int h, final Graphics2D g2) { - this.xBase = xBase; - this.yBase = yBase; - this.w = w; - this.h = h; - this.g2 = g2; - - if (SystemInfo.isWindows) { - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - } - } - - public void render(int indentX, int indentY, List lines) throws OverflowException { - x = indentX; - y = indentY; - ApplicationInfoEx appInfo = (ApplicationInfoEx)ApplicationInfo.getInstance(); - for (AboutBoxLine line : lines) { - final String s = line.getText(); - setFont(line.isBold() ? myBoldFont : myFont); - if (line.isRunnable()) { - g2.setColor(myLinkColor); - FontMetrics metrics = g2.getFontMetrics(font); - final Rectangle myRectangle = new Rectangle(xBase + x, yBase + y - fontAscent, metrics.stringWidth(s + " "), fontHeight); - myLinks.add(new Link(myRectangle, line)); - } - else { - g2.setColor(createColor(appInfo.getAboutForeground())); - } - renderString(s, indentX); - if (!line.isKeepWithNext() && !line.equals(lines.get(lines.size()-1))) { - lineFeed(indentX, s); - } - } - } - - private void renderString(final String s, final int indentX) throws OverflowException { - final List words = StringUtil.split(s, " "); - for (String word : words) { - int wordWidth = fontmetrics.stringWidth(word); - if (x + wordWidth >= w) { - lineFeed(indentX, word); - } - renderWord(word, indentX); - } - } - - private void renderWord(final String s, final int indentX) throws OverflowException { - FontMetrics fm = null; - Font f = null; - try { - for (int j = 0; j != s.length(); ++j) { - final char c = s.charAt(j); - if (!g2.getFont().canDisplay(c)) { - f = g2.getFont(); - fm = fontmetrics; - g2.setFont(new Font("Monospaced", f.getStyle(), f.getSize())); - fontmetrics = g2.getFontMetrics(); - } - final int cW = fontmetrics.charWidth(c); - if (x + cW >= w) { - lineFeed(indentX, s); - } - g2.drawChars(new char[]{c}, 0, 1, xBase + x, yBase + y); - x += cW; - } - x += fontmetrics.charWidth(' '); - } - finally { - if (f != null) { - g2.setFont(f); - fontmetrics = fm; - } - } - } - - private void lineFeed(int indent, final String s) throws OverflowException { - x = indent; - if (s.length() == 0) { - y += fontHeight / 3; - } - else { - y += fontHeight; - } - if (y >= h) { - throw new OverflowException(); - } - } - - private void setFont(Font font) { - this.font = font; - fontmetrics = g2.getFontMetrics(font); - g2.setFont(font); - fontAscent = fontmetrics.getAscent(); - fontHeight = fontmetrics.getHeight(); - } - } - - private static class AboutBoxLine implements ActionListener { - private final String myText; - private final boolean myBold; - private boolean myKeepWithNext; - private final Runnable myRunnable; - - AboutBoxLine(final String text, final boolean bold) { - myText = text; - myBold = bold; - myRunnable = null; - } - - AboutBoxLine(final String text) { - this(text, false); - } - - AboutBoxLine(final String text, @NotNull Runnable runnable) { - myText = text; - myBold = false; - myRunnable = runnable; - } - - public String getText() { - return myText; - } - - public boolean isBold() { - return myBold; - } - - public boolean isRunnable() { - return myRunnable != null; - } - - public boolean isKeepWithNext() { - return myKeepWithNext; - } - - public AboutBoxLine keepWithNext() { - myKeepWithNext = true; - return this; - } - - @Override - public void actionPerformed(ActionEvent e) { - if (myRunnable != null) myRunnable.run(); - } - } - - private static final class Link implements ActionListener { - private final Rectangle myRectangle; - private final ActionListener myAction; - - private Link(Rectangle rectangle, ActionListener action) { - myRectangle = rectangle; - myAction = action; - } - - private Link(Rectangle rectangle, String url) { - myRectangle = rectangle; - myAction = e -> BrowserUtil.browse(url); - } - - @Override - public void actionPerformed(ActionEvent e) { - myAction.actionPerformed(e); - } - } - - @Override - public AccessibleContext getAccessibleContext() { - if (accessibleContext == null) { - accessibleContext = new AccessibleInfoSurface(); - } - return accessibleContext; - } - - protected class AccessibleInfoSurface extends AccessibleJPanel { - @Override - public String getAccessibleName() { - String text = IdeBundle.message("about.popup.system.info", getText(), getCopyrightText()); - @NlsSafe String result = AccessibleContextUtil.replaceLineSeparatorsWithPunctuation(text); - return result; - } - } - } - - @SuppressWarnings("UseJBColor") - private static Color createColor(long rgba) { - return rgba == -1 ? Color.BLACK : new Color((int)rgba, rgba > 0xffffff); - } - - static @NotNull String getExtraInfo() { - String extraInfo = SystemInfo.getOsNameAndVersion() + "\n"; - - for (AboutPopupDescriptionProvider aboutInfoProvider : InfoSurface.EP_NAME.getExtensions()) { - String description = aboutInfoProvider.getDescription(); - if (description != null) { - extraInfo += description + "\n"; - } - } - - extraInfo += "GC: " + ManagementFactory.getGarbageCollectorMXBeans().stream() - .map(GarbageCollectorMXBean::getName).collect(StringUtil.joining()) + "\n"; - - extraInfo += "Memory: " + (Runtime.getRuntime().maxMemory() / FileUtilRt.MEGABYTE) + "M" + "\n"; - - extraInfo += "Cores: " + Runtime.getRuntime().availableProcessors() + "\n"; - - if (UIUtil.isMetalRendering()) { - extraInfo += "Metal Rendering is ON\n"; - } - - Collector joiner = Collectors.joining("\n"); - - String registryKeys = Registry.getAll().stream().filter(RegistryValue::isChangedFromDefault) - .map(v -> " " + v.getKey() + "=" + v.asString()).collect(joiner); - if (!StringUtil.isEmpty(registryKeys)) { - extraInfo += "Registry:\n" + registryKeys + "\n\n"; - } - - String nonBundledPlugins = PluginManagerCore.getLoadedPlugins().stream() - .filter(p -> !p.isBundled()) - .map(p -> " " + p.getPluginId().getIdString() + " (" + p.getVersion() + ")") - .collect(joiner); - if (!StringUtil.isEmpty(nonBundledPlugins)) { - extraInfo += "Non-Bundled Plugins:\n" + nonBundledPlugins + "\n"; - } - - if (PlatformUtils.isIntelliJ()) { - IdeaPluginDescriptor kotlinPlugin = PluginManagerCore.getPlugin(PluginId.findId("org.jetbrains.kotlin")); - if (kotlinPlugin != null) { - extraInfo += "\nKotlin: " + kotlinPlugin.getVersion(); - } - } - - if (SystemInfo.isUnix && !SystemInfo.isMac) { - extraInfo += "\nCurrent Desktop: " + notNull(System.getenv("XDG_CURRENT_DESKTOP"), "Undefined"); - } - return extraInfo; - } - - public static class PopupPanel extends JPanel { - - private InfoSurface myInfoSurface; - - public PopupPanel(LayoutManager layout) { - super(layout); - } - - @Override - public AccessibleContext getAccessibleContext() { - if (accessibleContext == null) { - accessibleContext = new AccessiblePopupPanel(); - } - return accessibleContext; - } - - public void setInfoSurface(InfoSurface infoSurface) { - myInfoSurface = infoSurface; - add(infoSurface, BorderLayout.NORTH); - DumbAwareAction.create(e -> CopyPasteManager.copyTextToClipboard(myInfoSurface.getText())) - .registerCustomShortcutSet(CustomShortcutSet.fromString("meta C", "control C"), this); - } - - protected class AccessiblePopupPanel extends AccessibleJPanel implements AccessibleAction { - @Override - public String getAccessibleName() { - ApplicationInfoEx appInfo = (ApplicationInfoEx)ApplicationInfo.getInstance(); - return IdeBundle.message("about.popup.about.app", appInfo.getFullApplicationName()); - } - - @Override - public String getAccessibleDescription() { - return myInfoSurface != null ? IdeBundle.message("press.copy.key.to.copy.system.information.to.clipboard") : null; - } - - @Override - public AccessibleAction getAccessibleAction() { - return this; - } - - @Override - public int getAccessibleActionCount() { - return myInfoSurface != null ? 1 : 0; - } - - @Override - public String getAccessibleActionDescription(int i) { - return i == 0 && myInfoSurface != null ? IdeBundle.message("copy.system.information.to.clipboard") : null; - } - - @Override - public boolean doAccessibleAction(int i) { - if (i == 0 && myInfoSurface != null) { - CopyPasteManager.copyTextToClipboard(myInfoSurface.getText()); - return true; - } - return false; - } - } - } - - public static void showOpenSoftwareSources(@NotNull String htmlText) { - DialogWrapper dialog = new DialogWrapper(true) { - { - init(); - setAutoAdjustable(false); - setOKButtonText(CommonBundle.message("close.action.name")); - } - - @Override - protected JComponent createCenterPanel() { - JPanel centerPanel = new JPanel(new BorderLayout(JBUIScale.scale(5), JBUIScale.scale(5))); - - JEditorPane viewer = SwingHelper.createHtmlViewer(true, null, JBColor.WHITE, JBColor.BLACK); - viewer.setFocusable(true); - viewer.addHyperlinkListener(new BrowserHyperlinkListener()); - - @NonNls String resultHtmlText = getScaledHtmlText(); - if (StartupUiUtil.isUnderDarcula()) { - resultHtmlText = resultHtmlText.replaceAll("779dbd", "5676a0"); - } - viewer.setText(resultHtmlText); - - StyleSheet styleSheet = ((HTMLDocument)viewer.getDocument()).getStyleSheet(); - styleSheet.addRule("body {font-family: \"Segoe UI\", Tahoma, \"Helvetica Neue\", Helvetica, Arial, sans-serif;}"); - styleSheet.addRule("body {margin-top:0;padding-top:0;}"); - styleSheet.addRule("body {font-size:" + JBUIScale.scaleFontSize((float)14) + "pt;}"); - - viewer.setCaretPosition(0); - viewer.setBorder(JBUI.Borders.empty(0, 5, 5, 5)); - - JBScrollPane scrollPane = new JBScrollPane(viewer, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_NEVER); - - centerPanel.add(scrollPane, BorderLayout.CENTER); - return centerPanel; - } - - @Override - protected Action @NotNull [] createActions() { - return new Action[]{getOKAction()}; - } - - private @NotNull String getScaledHtmlText() { - final Pattern pattern = Pattern.compile("(\\d+)px"); - final Matcher matcher = pattern.matcher(htmlText); - - StringBuilder sb = new StringBuilder(); - while (matcher.find()) { - matcher.appendReplacement(sb, JBUIScale.scale(Integer.parseInt(matcher.group(1))) + "px"); - } - matcher.appendTail(sb); - - return sb.toString(); - } - }; - - if (ourPopup != null) { - ourPopup.cancel(); - } - dialog.setTitle(IdeBundle.message("dialog.title.third.party.software", - ApplicationNamesInfo.getInstance().getFullProductName(), - ApplicationInfo.getInstance().getFullVersion())); - dialog.setSize(JBUIScale.scale(750), JBUIScale.scale(650)); - dialog.show(); - } - - public static @NotNull @NlsSafe String getAboutText() { - ApplicationInfoEx appInfo = (ApplicationInfoEx)ApplicationInfo.getInstance(); - InfoSurface infoSurface = new InfoSurface(IconLoader.getIcon(appInfo.getAboutImageUrl(), AboutPopup.class.getClassLoader()), false); - return infoSurface.getText(); - } -} diff --git a/platform/platform-impl/src/com/intellij/internal/ui/ShowAboutPopupInDebugModeAction.java b/platform/platform-impl/src/com/intellij/internal/ui/ShowAboutPopupInDebugModeAction.java deleted file mode 100644 index 486ac9407fad..000000000000 --- a/platform/platform-impl/src/com/intellij/internal/ui/ShowAboutPopupInDebugModeAction.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.internal.ui; - -import com.intellij.ide.actions.AboutPopup; -import com.intellij.openapi.actionSystem.ActionUpdateThread; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.wm.WindowManager; -import org.jetbrains.annotations.NotNull; - -final class ShowAboutPopupInDebugModeAction extends DumbAwareAction { - - @Override - public @NotNull ActionUpdateThread getActionUpdateThread() { - return ActionUpdateThread.BGT; - } - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - AboutPopup.show(WindowManager.getInstance().suggestParentWindow(getEventProject(e)), true); - } -} diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 863973bd8ef3..8084b0e00d52 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -2185,7 +2185,6 @@ action.ToggleUiInspectorHierarchyTrace.text.disable=Disable UI Inspector Hierarc action.GrayFilterConfig.text=&GrayFilter action.TextGrayFilterConfig.text=&TextGrayFilter action.ShowSplash.text=Show Splash -action.ShowAboutPopupInDebugModeAction.text=Show About Popup in Debug Mode action.ValidationTest.text=Validation Dialog Test action.MacMessagesTest.text=Test Mac Messages action.ColorBlindnessTest.text=Test ColorBlindness @@ -2791,4 +2790,4 @@ action.addQuickAction.UndoRedo.text=Undo / Redo action.ColoredHeaderAction.text=Use Project Colors in Toolbar action.ChangeMainToolbarColor.text=Change Toolbar Color... -group.Internal.WorkspaceModel.text=Workspace Model \ No newline at end of file +group.Internal.WorkspaceModel.text=Workspace Model diff --git a/platform/platform-resources/src/idea/ApplicationInfo.xsd b/platform/platform-resources/src/idea/ApplicationInfo.xsd index 2a353c0f4e05..3150ad544f4c 100644 --- a/platform/platform-resources/src/idea/ApplicationInfo.xsd +++ b/platform/platform-resources/src/idea/ApplicationInfo.xsd @@ -316,8 +316,9 @@ - If 'true' information about licensee will be shown on the splash screen. + Deprecated: information about licensee is never shown on the splash screen (for faster loading) + deprecated diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 6f9560b53285..a8eacc70b20b 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -1277,7 +1277,6 @@ - diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 4db2673771c2..b36da5a35549 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -2252,9 +2252,6 @@ eclipse.scan.home.directory.description=Scan home directory for existing Eclipse ide.diagnostics.show.context.menu.invocation.time=false ide.diagnostics.show.context.menu.invocation.time.description=Show time in ms between mouse event and context menu appearance on screen -ide.new.about.dialog=true -ide.new.about.dialog.description=Enable dialog based About popup - run.index.rescanning.on.plugin.load.unload=true run.index.rescanning.on.plugin.load.unload.description=Run force index rescanning on plugin load/unload From 87cd36ac6dad3cceabe204ead6000b1c5373a9c4 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 30 Jun 2023 22:08:15 +0200 Subject: [PATCH 078/226] Revert "[platform] minor optimization in Windows launcher: trying to activate another instance before anything else" This reverts commit 7b58e567 IDEA-324092 GitOrigin-RevId: ceae4363ffd48eab0f1a1e42a87fd744e4dc09d1 --- native/WinLauncher/WinLauncher.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/native/WinLauncher/WinLauncher.cpp b/native/WinLauncher/WinLauncher.cpp index 36519efdae1b..acbe05b70a0f 100644 --- a/native/WinLauncher/WinLauncher.cpp +++ b/native/WinLauncher/WinLauncher.cpp @@ -903,9 +903,6 @@ int APIENTRY _tWinMain(HINSTANCE hInstance, if (!IsSupportedVersion()) return 1; - int exitCode = CheckSingleInstance(); - if (exitCode != -1) return exitCode; - std::string homeDir = GetHomeDir(); if (!LocateJVM(homeDir)) return 1; @@ -923,6 +920,10 @@ int APIENTRY _tWinMain(HINSTANCE hInstance, SetPathVariable(L"APPDATA", FOLDERID_RoamingAppData); SetPathVariable(L"LOCALAPPDATA", FOLDERID_LocalAppData); + //it's OK to return 0 here, because the control is transferred to the first instance + int exitCode = CheckSingleInstance(); + if (exitCode != -1) return exitCode; + // Read current directory and pass it to JVM through environment variable. The real current directory will be changed // in LoadJVMLibrary. std::wstring currentDirectory = GetCurrentDirectoryAsString(); From c982635b73331e45eb50d21634ef1ce96955ab8e Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 30 Jun 2023 21:07:41 +0200 Subject: [PATCH 079/226] IDEA-323554 i18n: Tooltip "Double Shift" of search everywhere is not localized GitOrigin-RevId: 274fd627419a27703e0b0ba318df2e76d64fe13d --- .../lang-api/resources/messages/LangBundle.properties | 3 ++- .../searcheverywhere/SearchEverywhereManagerImpl.java | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/lang-api/resources/messages/LangBundle.properties b/platform/lang-api/resources/messages/LangBundle.properties index 447c9c5e016e..d3ec4c5f5c60 100644 --- a/platform/lang-api/resources/messages/LangBundle.properties +++ b/platform/lang-api/resources/messages/LangBundle.properties @@ -584,4 +584,5 @@ label.change.shortcut=Change Shortcut action.clear.recent.actions.text=Clear Recent Actions action.clear.recent.actions.description=Clear recent history actions.tab.assign.a.shortcut=Press {0} to assign a shortcut -search.everywhere.advertiser.class.on.in.split=Open In Right Split \ No newline at end of file +search.everywhere.advertiser.class.on.in.split=Open In Right Split +double.shift=Double Shift \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java index c014a93948b7..27443cb51b4b 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -6,6 +6,7 @@ import com.intellij.ide.actions.BigPopupUI; import com.intellij.ide.actions.OpenInRightSplitAction; import com.intellij.ide.lightEdit.LightEdit; import com.intellij.ide.lightEdit.LightEditCompatible; +import com.intellij.lang.LangBundle; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.keymap.KeymapUtil; @@ -26,6 +27,7 @@ import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBInsets; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -375,9 +377,9 @@ public final class SearchEverywhereManagerImpl implements SearchEverywhereManage } private static Map createShortcutsMap() { - Map res = new HashMap<>(); + Map res = new HashMap<>(); - res.put(ALL_CONTRIBUTORS_GROUP_ID, "Double Shift"); + res.put(ALL_CONTRIBUTORS_GROUP_ID, LangBundle.message("double.shift")); addShortcut(res, "ClassSearchEverywhereContributor", "GotoClass"); addShortcut(res, "FileSearchEverywhereContributor", "GotoFile"); addShortcut(res, "SymbolSearchEverywhereContributor", "GotoSymbol"); @@ -388,7 +390,7 @@ public final class SearchEverywhereManagerImpl implements SearchEverywhereManage return res; } - private static void addShortcut(Map map, String contributorID, String actionID) { + private static void addShortcut(Map map, String contributorID, String actionID) { KeyboardShortcut shortcut = ActionManager.getInstance().getKeyboardShortcut(actionID); if (shortcut != null) map.put(contributorID, KeymapUtil.getShortcutText(shortcut)); } From 9bccc8e1157d92699abbc49c81ac68acdf026e68 Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Fri, 30 Jun 2023 19:52:46 +0200 Subject: [PATCH 080/226] [java-inspection] flacky test - com.intellij.java.codeInsight.editorActions.FixDocCommentTest.testAllesZusammen GitOrigin-RevId: ec2ed4392c8e25d56c0e8bceec44e3e71c1280fe --- .../documentation/JavaDocCommentFixer.java | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java b/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java index d40011fcb97b..c0f51be8c393 100644 --- a/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java +++ b/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java @@ -12,6 +12,7 @@ import com.intellij.codeInspection.javaDoc.MissingJavadocInspection; import com.intellij.javadoc.JavadocNavigationDelegate; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -52,8 +53,7 @@ public class JavaDocCommentFixer implements DocCommentFixer { */ private static final Set CARET_ANCHOR_TAGS = ContainerUtil.newHashSet(PARAM_TAG, "@throws", "@return"); - private static final Comparator COMPARATOR = - (e1, e2) -> e2.getTextRange().getEndOffset() - e1.getTextRange().getEndOffset(); + private static final Comparator COMPARATOR = (e1, e2) -> e2.getEndOffset() - e1.getEndOffset(); @Override public void fixComment(@NotNull Project project, @NotNull Editor editor, @NotNull PsiComment comment) { @@ -144,9 +144,9 @@ public class JavaDocCommentFixer implements DocCommentFixer { private static void fixCommonProblems(@NotNull List problems, @NotNull PsiComment comment, @NotNull final Document document, - @NotNull Project project) - { - List toRemove = new ArrayList<>(); + @NotNull Project project) { + List toRemove = new ArrayList<>(); + List problemsToApply = new ArrayList<>(); for (ProblemDescriptor problem : problems) { PsiElement element = problem.getPsiElement(); if (element == null) { @@ -157,32 +157,36 @@ public class JavaDocCommentFixer implements DocCommentFixer { // Unnecessary element like '@return' at the void method's javadoc. for (PsiElement e = element; e != null; e = e.getParent()) { if (e instanceof PsiDocTag) { - toRemove.add(e); + toRemove.add(document.createRangeMarker(e.getTextRange())); break; } } } else { - // Problems like 'missing @param'. - QuickFix[] fixes = problem.getFixes(); - if (fixes != null && fixes.length > 0) { - fixes[0].applyFix(project, problem); - } + problemsToApply.add(problem); } } - if (toRemove.isEmpty()) { - return; - } - if (toRemove.size() > 1) { - toRemove.sort(COMPARATOR); + for (ProblemDescriptor problem : problemsToApply) { + // Problems like 'missing @param'. + QuickFix[] fixes = problem.getFixes(); + if (fixes != null && fixes.length > 0) { + fixes[0].applyFix(project, problem); + } } PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project); + if (toRemove.isEmpty()) { + psiDocumentManager.commitDocument(document); + return; + } + psiDocumentManager.doPostponedOperationsAndUnblockDocument(document); CharSequence text = document.getCharsSequence(); - for (PsiElement element : toRemove) { - int startOffset = element.getTextRange().getStartOffset(); + List toDelete = new ArrayList<>(); + for (RangeMarker rangeMarker : toRemove) { + TextRange range = rangeMarker.getTextRange(); + int startOffset = range.getStartOffset(); int startLine = document.getLineNumber(startOffset); int i = CharArrayUtil.shiftBackward(text, startOffset - 1, " \t"); if (i >= 0) { @@ -195,14 +199,20 @@ public class JavaDocCommentFixer implements DocCommentFixer { startOffset = Math.max(i, document.getLineStartOffset(startLine) - 1); } - int endOffset = element.getTextRange().getEndOffset(); + int endOffset = range.getEndOffset(); // Javadoc PSI is awkward, it includes next line text before the next tag. That's why we need to strip it. i = CharArrayUtil.shiftBackward(text, endOffset - 1, " \t*"); if (i > 0 && text.charAt(i) == '\n') { endOffset = i; } - document.deleteString(startOffset, endOffset); + toDelete.add(new TextRange(startOffset, endOffset)); } + + toDelete.sort(COMPARATOR); + for (TextRange range : toDelete) { + document.deleteString(range.getStartOffset(), range.getEndOffset()); + } + psiDocumentManager.commitDocument(document); } From 8eacd2c20763bedf25d3cabba85a58f7745e3030 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 30 Jun 2023 21:10:29 +0200 Subject: [PATCH 081/226] IDEA-258627 Translation string error in Resource Bundle Dialog window GitOrigin-RevId: 4f575af8d96e54c5b8c3858485afe16664248a4f --- .../src/com/intellij/lang/properties/PropertiesUtil.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java index 34f99b1094db..e6566740d9ef 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java @@ -203,13 +203,13 @@ public class PropertiesUtil { @NotNull public static @Nls String getPresentableLocale(@NotNull Locale locale) { List names = new ArrayList<>(); - if (locale.getDisplayLanguage() != null) { + if (StringUtil.isNotEmpty(locale.getDisplayLanguage())) { names.add(locale.getDisplayLanguage()); } - if (locale.getDisplayCountry() != null) { + if (StringUtil.isNotEmpty(locale.getDisplayCountry())) { names.add(locale.getDisplayCountry()); } - if (locale.getDisplayVariant() != null) { + if (StringUtil.isNotEmpty(locale.getDisplayVariant())) { names.add(locale.getDisplayVariant()); } return names.isEmpty() ? "" : " (" + StringUtil.join(names, "/") + ")"; From c8df2a469820b7f8e74669b68924974ebe9c5ba6 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Fri, 30 Jun 2023 19:45:29 +0200 Subject: [PATCH 082/226] [icons] refactoring: rename AllIcons.Welcome.Project to RecentProjects The new name better reflects the purpose of the icons, and also this way it won't be suggested in auto-import and completion instead of Project interface. GitOrigin-RevId: a876ddfd0626afe87246be49fda55270ca0610f5 --- .../{project => recentProjects}/remove-hover.svg | 0 .../{project => recentProjects}/remove-hover_dark.svg | 0 .../src/welcome/{project => recentProjects}/remove.svg | 0 .../removeDisabled-hover.svg | 0 .../removeDisabled-hover_dark.svg | 0 .../{project => recentProjects}/removeDisabled.svg | 0 .../removeDisabled_dark.svg | 0 .../{project => recentProjects}/remove_dark.svg | 0 .../wm/impl/welcomeScreen/RecentProjectPanel.java | 2 +- .../recentProjects/RecentProjectFilteringTree.kt | 8 ++++---- platform/util/ui/src/com/intellij/icons/AllIcons.java | 10 +++++----- 11 files changed, 10 insertions(+), 10 deletions(-) rename platform/icons/src/welcome/{project => recentProjects}/remove-hover.svg (100%) rename platform/icons/src/welcome/{project => recentProjects}/remove-hover_dark.svg (100%) rename platform/icons/src/welcome/{project => recentProjects}/remove.svg (100%) rename platform/icons/src/welcome/{project => recentProjects}/removeDisabled-hover.svg (100%) rename platform/icons/src/welcome/{project => recentProjects}/removeDisabled-hover_dark.svg (100%) rename platform/icons/src/welcome/{project => recentProjects}/removeDisabled.svg (100%) rename platform/icons/src/welcome/{project => recentProjects}/removeDisabled_dark.svg (100%) rename platform/icons/src/welcome/{project => recentProjects}/remove_dark.svg (100%) diff --git a/platform/icons/src/welcome/project/remove-hover.svg b/platform/icons/src/welcome/recentProjects/remove-hover.svg similarity index 100% rename from platform/icons/src/welcome/project/remove-hover.svg rename to platform/icons/src/welcome/recentProjects/remove-hover.svg diff --git a/platform/icons/src/welcome/project/remove-hover_dark.svg b/platform/icons/src/welcome/recentProjects/remove-hover_dark.svg similarity index 100% rename from platform/icons/src/welcome/project/remove-hover_dark.svg rename to platform/icons/src/welcome/recentProjects/remove-hover_dark.svg diff --git a/platform/icons/src/welcome/project/remove.svg b/platform/icons/src/welcome/recentProjects/remove.svg similarity index 100% rename from platform/icons/src/welcome/project/remove.svg rename to platform/icons/src/welcome/recentProjects/remove.svg diff --git a/platform/icons/src/welcome/project/removeDisabled-hover.svg b/platform/icons/src/welcome/recentProjects/removeDisabled-hover.svg similarity index 100% rename from platform/icons/src/welcome/project/removeDisabled-hover.svg rename to platform/icons/src/welcome/recentProjects/removeDisabled-hover.svg diff --git a/platform/icons/src/welcome/project/removeDisabled-hover_dark.svg b/platform/icons/src/welcome/recentProjects/removeDisabled-hover_dark.svg similarity index 100% rename from platform/icons/src/welcome/project/removeDisabled-hover_dark.svg rename to platform/icons/src/welcome/recentProjects/removeDisabled-hover_dark.svg diff --git a/platform/icons/src/welcome/project/removeDisabled.svg b/platform/icons/src/welcome/recentProjects/removeDisabled.svg similarity index 100% rename from platform/icons/src/welcome/project/removeDisabled.svg rename to platform/icons/src/welcome/recentProjects/removeDisabled.svg diff --git a/platform/icons/src/welcome/project/removeDisabled_dark.svg b/platform/icons/src/welcome/recentProjects/removeDisabled_dark.svg similarity index 100% rename from platform/icons/src/welcome/project/removeDisabled_dark.svg rename to platform/icons/src/welcome/recentProjects/removeDisabled_dark.svg diff --git a/platform/icons/src/welcome/project/remove_dark.svg b/platform/icons/src/welcome/recentProjects/remove_dark.svg similarity index 100% rename from platform/icons/src/welcome/project/remove_dark.svg rename to platform/icons/src/welcome/recentProjects/remove_dark.svg diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java index cbb4b39b6559..502b338d9b8c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java @@ -359,7 +359,7 @@ public class RecentProjectPanel extends JPanel { private Icon detectActionIcon(int rowIndex, boolean hovered) { if (isProjectInvalid(rowIndex)) { - return hovered ? AllIcons.Welcome.Project.RemoveHover : AllIcons.Welcome.Project.Remove; + return hovered ? AllIcons.Welcome.RecentProjects.RemoveHover : AllIcons.Welcome.RecentProjects.Remove; } return hovered ? AllIcons.Ide.Notification.GearHover : AllIcons.Ide.Notification.Gear; } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/recentProjects/RecentProjectFilteringTree.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/recentProjects/RecentProjectFilteringTree.kt index 17587a9e7daa..73c844652daf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/recentProjects/RecentProjectFilteringTree.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/recentProjects/RecentProjectFilteringTree.kt @@ -415,8 +415,8 @@ internal class RecentProjectFilteringTree( AllIcons.Ide.Notification.GearHover) } else { - buttonViewModel.prepareActionsButton(projectActions, rowHovered, AllIcons.Welcome.Project.Remove, - AllIcons.Welcome.Project.RemoveHover) + buttonViewModel.prepareActionsButton(projectActions, rowHovered, AllIcons.Welcome.RecentProjects.Remove, + AllIcons.Welcome.RecentProjects.RemoveHover) } val toolTipPath = PathUtil.toSystemDependentName(item.projectPath) @@ -537,8 +537,8 @@ internal class RecentProjectFilteringTree( projectActionButton.isVisible = true // always visible } false -> { - buttonViewModel.prepareActionsButton(projectActionButton, rowHovered, AllIcons.Welcome.Project.Remove, - AllIcons.Welcome.Project.RemoveHover) + buttonViewModel.prepareActionsButton(projectActionButton, rowHovered, AllIcons.Welcome.RecentProjects.Remove, + AllIcons.Welcome.RecentProjects.RemoveHover) } else -> {} } diff --git a/platform/util/ui/src/com/intellij/icons/AllIcons.java b/platform/util/ui/src/com/intellij/icons/AllIcons.java index a0eeda689a30..940543c940f6 100644 --- a/platform/util/ui/src/com/intellij/icons/AllIcons.java +++ b/platform/util/ui/src/com/intellij/icons/AllIcons.java @@ -1248,11 +1248,11 @@ public class AllIcons { /** 24x24 */ public static final @NotNull Icon Open = load("welcome/open.svg", -1167853047, 2); /** 24x24 */ public static final @NotNull Icon OpenSelected = load("welcome/openSelected.svg", 297876432, 0); - public static final class Project { - /** 10x10 */ public static final @NotNull Icon RemoveHover = load("welcome/project/remove-hover.svg", -1138969467, 2); - /** 10x10 */ public static final @NotNull Icon Remove = load("welcome/project/remove.svg", -1344345313, 2); - /** 10x10 */ public static final @NotNull Icon RemoveDisabledHover = load("welcome/project/removeDisabled-hover.svg", 225648199, 2); - /** 10x10 */ public static final @NotNull Icon RemoveDisabled = load("welcome/project/removeDisabled.svg", 693821036, 2); + public static final class RecentProjects { + /** 10x10 */ public static final @NotNull Icon RemoveHover = load("welcome/recentProjects/remove-hover.svg", -1138969467, 2); + /** 10x10 */ public static final @NotNull Icon Remove = load("welcome/recentProjects/remove.svg", -1344345313, 2); + /** 10x10 */ public static final @NotNull Icon RemoveDisabledHover = load("welcome/recentProjects/removeDisabled-hover.svg", 225648199, 2); + /** 10x10 */ public static final @NotNull Icon RemoveDisabled = load("welcome/recentProjects/removeDisabled.svg", 693821036, 2); } /** @deprecated to be removed */ From 3dd59e27e591892a9b49fc4909fbfc2ac7012e67 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 30 Jun 2023 22:24:37 +0200 Subject: [PATCH 083/226] Revert "[platform] minor optimization in Windows launcher: trying to activate another instance before anything else" (binaries) This reverts commit 7b58e567 IDEA-324092 GitOrigin-RevId: 4e27124719db4c1c574626e59150ca9fa972a020 --- .../win/launcher/aarch64/WinLauncher.exe | Bin 898048 -> 898048 bytes .../win/launcher/amd64/WinLauncher.exe | Bin 932352 -> 932352 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/platform/build-scripts/resources/win/launcher/aarch64/WinLauncher.exe b/platform/build-scripts/resources/win/launcher/aarch64/WinLauncher.exe index 8b571bee1955c85db01b7e424b782eb3f28725a7..3cf0fdef01916f084ab94493d0cc4823270ab463 100644 GIT binary patch delta 28618 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 z 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 QpX>R#;nT_08^2%wAFnPy$^ZZW delta 28661 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 vt`m50&3iXwt^0<4B*LJzFP&4+7mn7Gj7+g__ diff --git a/platform/build-scripts/resources/win/launcher/amd64/WinLauncher.exe b/platform/build-scripts/resources/win/launcher/amd64/WinLauncher.exe index 16dcabf31809f6065acb05a42a86e301c77d1571..6a406f9671928ce158b039d411b1cfd7fc7a998a 100644 GIT binary patch delta 63565 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 delta 63575 zcmZr&2UrwI)86VC5CZ}#Sp)$UGpHC*K@k@PbHE7Zte7(fOo%8tYMJAChBF?gV>+{9 zz<6iQc@c9&Pvw7m7Vp0M{*UKjcBiMOLv@9>s;hV6`|1d4lRy6P7q2y^r{t4XLtG+StQAljQhBYFTHf2w)y8B_I$=&aY^j2(=A_^n zh4PxrDfWSQ%ko%TrAESd6s{iiV+3fx40LUgM4kCbgVZ@I>dGk>wFYL>{>9d$+AP6Xcw5@$KA%1neaU) z$8ty8XBR=~n#enYJhbGz<*AjnCvQz{dFrWQ`7D}~jVUteMAodx^kX^r zYY_A?YocXcS=D6eua(cYlx}IK^3`#&sf=nV1?rlUZbT>DvwW9aZMZDdlmWoxB>)mo_y%pc%Y5S1d6(lhI!b#wZ0YbQCGmGQ;$L`%zm&(+Dn7=xtU zh@VWRJ#LcXUkhrR3XG!8nxFk}vS^F#m$)W9R!u=K%t@R5H=xEIA6c!Fy$xSjMn$yF z1q(RWw3p;bHz(m5YG-YyWZHy+g@_8L&2u+XnolBPKXDg=>zm7S9lm2}@yJ1-_`^E;tOxg6KzCziuk>)_m%CTJ&| zKhR-qze}`8yQPH%d1@tHi&2Qyz_p=xt!T4dtI=KUglilnXr2LIt)_=3=~^3)ns_;Fo<}dDMD2@bS4V$=r5yya?eW1tEH%>l z7wx3b&9u|rMTkzM-SwGAJ_mDDQ)2C9AM8vy4pZM?^f}IU!Qi(P`y`ZELbbWRGbmZ} z@M}!2T2H^Vp(s*@I5X11U?+RJixDNQ?9ehpR8 z23H89(`jiHCJ{Mm!GYDVYy$!-l1W=07)EQfyMb{uUJDJHPcyX3LHE(VUa6b1=8($w zpOA}Ix$+b0rg>C3PQPpSsx+a2xcX|%gZoO_2REd}X=>HBM8&m^)eg{_G|%dGL^aa< zYiuDUYq!dds}+AOyXFyew6E3?s+*P&vXjU?tx6q7qUu_Mx+iInRxoruwbgcoZgCI0 zA>}*WoYK)hG;Ft>kSgK&ubV6vwQ*tfFq(s5K~yyDO;{|6ui09Q`c`Rm zm0IUUB|JvU!lc7cPj?|tP*0ojSc+Jjw!G01+M>lZZs+vyyj;6k{wH%8I!!y>xHXN| ze4>1zGwMgZq?=l$=r&lVr07aCSKA+5gBofdqdSwG*1Ab4x}c435>1t~Gfk?|OigK8 zg>1CyO*<0yO7lohefr*6avf(W*7SM2eQLMN_J;wQune zTCjP`yA-DdwYscCJXN(rt%_--T3@EXv~R6T5slJHv~2+O*spCgoz(WUE$WoM$2#yh zN2?^V_M~k~``Esa{}lUaaDx+2I{2b=RC${Cf;v`FRGO_U1uVdlg`0p_G5QQ#6UZDOAQhd+0yrc}(g8CpDQd7$ZiD$pzKNuRRR zPb<_n0;}4tZ$*)vrp@fT9HJZ0&yU(^QT>WR#`^WEPcOA?{d^0ix3Mv0{Qbwp^OLjo zzF#5;GpfHI<<*w;uTZ$&Mb*?OrNG$8BugY&q)`pjZubxMpRiRmWtDB3qQdfAhn2D1 zx$xf=GqkV)6)}>*0|w9v?e2hR*tzlp-R#@0RZUYr4zt6HmWo=7frDZ0j}3ewmZlhF zK0nAFruO!r+0;erA77S&wMFq|XtH)RJ^*ug9$%B5Xr%_1D4xB@$^oI01N=5gGG~J# z=3E+o=%5W494bC-)V2+lw7D~Q2v)E8kh0Kf;zFn+h@@>qC&wb2E=cZng<9TDb zpzRp4pB&N#4uu-6r6mlDr9o+ThBYOpLF;69v;1e|N@QKF&WPevLyH^njXG$ZN5;~e zv;!j>Lm1ZlyJELBTHO&o)F~}wba`p+`i`kf^hesJu~mtdrQIKgyN+qa6S5VjL<~uG zaVWQomRgy~p43u{n0y2}I&b1GN=ZAEc#LR9+SI8jHpnW|i;>z!NEI2BBNdmhJv0p-X5XDGBsU+m}*K>9JMS_T{ZE#-wQ5 z`?=(?BAM=5*lZ7~t#zE;Tzs0PZJTW@$82Lc=F|{xleL5)uC|*l+L|nnw2gBD>8f^P zjxQC^zRf9G7;d`Ws-zzVc8Cv;NPwKBlrk0{`ZE$M&h}ja}B%O%NIbqa@ z!a^!{FwUum9HuP5D?mBX;JAVYAOcQ$Z3)?e*(N18?y>#5*^AnvR6nR+ySc%H#hvQ{ zIc`0-g!hmN66!VavGlQi39!WB%hVhz!@xAp?M8vxx4C8Lu@*2d9L8Y4yfQRgTZHe; zwA=V@quFVz#MkNCCatzx32+|5|dulMy#yv{cTir3NcEbf$-nAM)XuI9@Y;qt5~$V(YKr^^s8*3c zb-Gq))dIS#ZCJGd9MgPts_56js;yTW+ImeEO-cK_20#oL;-|TETU+(hM8K-z>;8gS z^ZK~~%xSluUx=^swHE7NkbPR{hGDkib$@Nw*6LJDd$qNqb3%U%(aD^X{?CHkoc%X{ z+gn;|&9-?$Y4+c?l$L9D+pB`&b+^}a^6Q89+t7+ zX&1J4gi$TO@8mh`Choc zPjYBcK#6;_}BC==391#nTuq{-Bq3>qsxrB}Su* zURu|q#YOQLZN?EVZOzdxfc@&RZg{2lvBRWkWsZ-7CR~4ft{m!#KWST9!SoQKAzI^; zIW#1#@u@*1q3h{N_ zB&9Yf6I8J*(n@6Xg2R!LQ4}zGQ^sDAT|zs5##5Vg)}_So`2T94I|}}*0n+xLtya+; z55i>2nJb}F(5X3PzJDO_ZFG{w@^#REHIt=HI~SleI#&o%(CM6Op+)~)VLB>Qg{}Pk z+*0bE*6#ezMC;~V90Tk$_Tm;P(3eh%G_yf6$3I$$P_tGIG)?@YHD#n-|Kl=I!L)6c zJ%o7Yshznxn0jlquRVYf^tqlzN^>`rS1+T&l%@IJEbBPPO|D@smh%l&`C?&FL>qjw zu=rX}yBFxJExlQV&T1EK)&^Az-f~wKxWe;TDO|MBTlL8u4}7$rZaFK;KgD^{uHX6! zjip_=Q>mm1-hy(AB8ZLQ4!`RxNfqt|#?Cp0RlwR<=4ch}j({RxcQ@8Mrm!KSQAyo_ zFO&NF$3R0z(>;K6G+=qA`Q3{xG_%uxH9A_Ge=i6i{KUQX5ZmJS2S5$Xx$j9`wO{W0 zN$=x+c{-H#?S3B;A04#b4}$`RwwH^7aov~tH#8dT5r?AOfgOjsiAs8A`R1Sq$|`^iO?g zep>0L!v!3`m6?O#J2*Y7Q21<13@I#Kty>y>-Iw(1r?q$%N@FzbnFd)dl~oCDX#1?* zv_w0aRmsb>1xApr*6|rP&Ico@gZbthHI(QL%P(4?=TWp(i+x@c*k#=FLAXADKHH(5 zt)$8upg*6^nV$o-^W~kj6)#Fj=l;c73AtXbAR4CSeLa9mY9n7yaP2AN3$}o-RU;D* z2`sD>M3ZL!rZh!p)!x)s%9P1fhjZVQfcv4p*#cLz$J;8DUt99_w8+lkRS0eX{f~Y3 zp2$gy|4^N-X&XN@N5JB*4^1(##ve<=A`SmIv2>nSiuCiE54J_8hb`GJaSI3Vt)+8+ z>Hj#_%YATHEB49F<3#S`8WjJ4Yr#7=KTF>Rb*Uj3{MiRDyou+xcie9o3iQr&&Y`xs*M%A{!oOPi5&kZ?LCtvtQfdD|g;fcgA$8E;HU zLu}Qa($apj8&Wtj*`ZNNk@8qEQxrY3+^uUX=`IQIFp*uXmlYD*p`N~!JKFkBFkY!zkX?EbE z+=YnZ!=7m2zJAM-HVX0SD^D**eQ6HAEk@PIkIQ&dJ*v(Fyr~Ht=KbE}MjiRGH`Smc zx`Pij6;y{~eW{-KE1TE)QV+`DynZxaT+ej zRVZ#)mI2p+E>cq*=8)1@wCDQV(iBY2yIw1X(_0-rFKm6&mw8NN;+<(;3&5y_y!D6329kl)f%uN*|D$Z3^Dio-1bRIHG!8_)KYu?D0ER;KYH zzu$AklzHPXV5|GQJD6(H1AZ4w<>@&WuSzvVk7lZ*$T@;-c^kn&?Nn9HM%NjqyA@2LhNM{f2~E0sWh8I@R7;$L#TtCQwY^? z8GFZIIQR^h7rY3=DLBVM>t_CzY3#RYQ#>th;2!s&OmM1fNlbAf0ua#ETZXV_GulT_^sCLNj#6^{N(|HLY<{+!hDRZz6j2wx8@k^uSNGS`Yqg?| zM8|niYbs7Hd2ef~>2q?qV#+ENmGqOp3H1zhlQPTywLz+9mM>5BB5kO-)Mh=~g7{T9 zsV(gwU#=Ac?YWt|#E@&D@TF+NRT9YXIUZONd1ef>%%8k5hE`B8o7>SRI?JK$DHGk6 z>41h}^ym)snW(DXuoLB@yk&p4N^J}~wHD6$pw2Xm@-N=^H=`KEjA9SnD~>i1c=%)& z(x^Ch>`FbH3Kx@eJ|V?2MvB@me5otNI<58kcX2JQ*NqNC8LQptCY9%V-7$;vY}zn7EF8_4yb+&I;;0@JDqaua**!pj)qJl9d6r!L3q}Ny4$Y?5rj}&iX`xiq_UAU2>m9{CM)#Qp@@zI`>IA zbP5d-4Au@vC@Jz+^+uwyS8iKU&2Hk97e27WV)&e8As zq2Z85uU(Ka*{KoiO_Dd(V6SXwAuA(kwQu%Xtg&(eQXpg{Ohs+! zhJUHct0u!fUScH?>g6g|O{C|3W7yikkF{!qdrW@Pu~bmZpkym&>8bQr*q4 zs=Fk5Lo4}v5{1DKgwCY)l#iFrq>`QwQzgNUW{IGi=42P(H@nEv7o_T~l*VDRs7$^f zbK;RwkP1r*J0??UishQg;Lw|VIvL~pjo&0wRrkj`6jOAK_rnTDrZjbwjYOAzEe$?2 z$t+l#03JSzg2dZk-Y|>W=UX!yeacv#rcLVaQY;6%qY1L;e+>gIq`<}p%;pNI6yP*_ zy)aomR52!MM7piBJ(2=U*oK?V#%wF`(AgB`5wi^~*7(a9QUU9{3|tzz%{s4!KjsDe zG6%4)E!Uevarwlo+_C*4$7UnPc8AmFz*@v}`BbbyZSI&#C4^tH)yywSrEauZ|C&mU zf|{|tM#Y@&L)4;WV8?KCzCZ{+92yzR7mf~ zlu7_{Ul&m)So`*isfKOlBrw@E-rr6s$~zYWR`h45C1CpI9JK_-I}a~hLc!uq44+*> zC6!Y#R+A?S?q#4}dTM}%|DtkhUM1-#)fR=*vqN5F9>Irs<)uXFb!)WLgs4NS=aHqULl+}nR+Dd%S$ zieVX6@|`2ploYOTl*-Wv?r;zQ@417kKnBs!CmW`!VW8Q`zk}j7DFs zb(~5&g|_*}_{ebmH6DH(I&n2`I1U9?o*x~jo^*s8pMZA&$L9nEd#1NS_bE~S)h)H( zSUuxrxw#oB{Q3kO#5tTVod!Z~MyF#CqxsKt3}OtIJ&8dydCCB;NNziEB!c*k$ zJh4SChVDhc(9#HAvlQVPr!bBh-2W6c6d&I3&QsJIM!48%aMK)4I89YOEzPV0F zTg5gP!39}7?;^y?iN9V1$9QqvB}&EuJ-px#5 z7eR;k_v=(09e%tH)d**#>@8|v+_kQCy^L+0XLWF6u+ESDv-gkrX9SAix<9-Hzi%>o z-liJC&1Ai)hlUM-@--(OEoDx8cn>f(JF9>h2-gy1G;`Ey85|>X4oS-}g_CYmW#@af zWf#TFNeOP!(=cq;NxpcSR^_WKA4vtj9ZJ-L9C+a!a5@~(J5<$WT?iPhu#_EZsK(fB zG_n0%uuC63@GhlDnLluky7`Q)iFP0j#*~`Kn}1CyhQsbd_08a^_u+e7=VSM&Sq32e+q9s=NdbHXE=w9o8%8g0Z)$3RYX%bLLnP8?u+%FT3&jwD)q{iZF zHT_B^y(RihKa~XrrD0t91$Fdstsu$t59oSYULy2K$2LG8AGLh=lh?hV(=a0OFX@qJ zR!$l&7w-Rx@{97hH*@4ozTBH%UtuLK@a0#u-PN_MB-fi9=YhTC{!%XFxzEd9!!NnX z2VTR9Z066eX%R5Tyf^SO0XN@}Z{azm<%{t4@<*pMfWSSlJk|r=f-+#hmhbSH#tHAJ zWd3p(d!|WlmORt9p@3Y|OXhZ2tedq<10~Mo=kKA)OY+bU@ccLMhYz$Hg1Yr1Sb8sK zeWdtynnwkA z@LxcZPx#RotUi+{Z?gbSnSST6tA&<=ecu zr~JZ$*VX z%t@30T68QV`XFpKrjYP-erlH+L6go-uDkY%Hx&{CD23e$iz&c`%L@ztf(P?~DSqGz z*sa1CH5~FHA_Wo7XGO$Hi0@2i;o)@6=0945JNAfoI*S?*j#thi*zwwVOd-X2K&*ra zhb^bLii>DZFL{oONPoHEW;R0Iy#>?(SK{|mc`Wpq~G?k1`e&DS&C1x#7G z9^om95+-)ZD{|GWM%c=)yI< zMQPa2?%rZ2n8w3L)Pp2+@&R?!zpSnPr!!lCQ+&iOs-cG$7rjYjXY*EH;Y)w&7kxzl zDQiConZH)jF4rSQ48&h}!yYyA7e{Cj+XMO2Fg>V*Fq2$_lA;`4;q@iKXMghXl31C6 zT(Oks<@M~Nb+HX?f8CIG8G4kVPRkQcDtrxgZp(Lh zZ$&Yef;cJ=^R?sAfua8T5Ui2tmj%Fi4DYt}f*>$=00g8n!zSQAo)p&G`2q z&=6s}Akl%$T%(c*2a-&vB)kezrj<-aLL;J3l|+bg&?1bTYyE2_v6u?x$(7hRDX}+r zZ56EZZ`>|ev~Ui7V(l#*nhANT=no0R`k`QsR+Ux38yYKc(qR`+BNpAoSeo@GuhxEC3IGOijB+c~oa z9`S?^V7)1|#GImY?@9%jo~(o=HS~c;gaBg00PDug2(B0+Vw4Ye1niSDuMB}e9pmdE zA_)FO{@NlCgAJ)Iyp+awtTX5M+M*_m|1Y&gC26H)qa z0ZQfZb-}*Dys9qNq94Dl3zhZh8@q-=D4=&j(Lfg-7K(?=Cqls&e*7#H3ibO}b_|1M z7|9V~qLq^GMsCkL!oZUAIDb9iDfd|FL7FOa-+Ce*e)Y|IBGzg0b}PM3N=jfwDskib zVmi&_KkAF(;Z*i$@B4ElfS@ zrK=-N*64M^TsN}vmD~Z%Xdu4YWdDgy`S2d$%qt?q?hxC}lGrCA37e{!L6>C0&BOO{ zTx}73Xy}FzhTKw1HDs`C=|7Jg*@rwupB&6q6`|tC>Y4C^g9pwN#Ps zn8jc@>_{<{*7KD}Je$fsjl?$E!WS9|tyC!-Xyw({Sa@ zjm2gl;C4}>o5b%?Vv5j4@anoScb%eP?oRRiXsk|a-W?4K0FWLH6Pv&-n}882>a&}O z8j910)mGAH=aPOMUu!O|C|g$v>+ZW*Ki)zdBinZ;gmm{;FNVtO)K=u>&8@&Hd-YST zL>y5|y-XY7PPR3U{i{|ImiuX2!Q%Uo^%G+R75I7>&t+m*vkskjVggLy+ICO^0UX?3 zlyuqgP#^?dZX^&ieBeyE;p`*#{Mw6RPUG>+oKnOS5f&kny1jT+d(qa#*?7f2_m%tB zR{;Dw2v@V^fh1s^thxc3g}ztTE}erdwXuy+*-SYy zqWKd_wdMny;b2ehAlA5A?h8}nlp-V1-h^m+B$?zgiVRzB0w>?%piZKQ6q8P(t@9wr{D0T%z`u49zOAZDO@YLfKyXK98w3E6 z;ExTtzPUZS8*joHl-m4;B_D31N`GpUqV~fq;xUVnxwCi;J(B4n1Bf4|=mDK!po^~8 zB+pGT&>Dv5`S%w07fT3Vj1|8_In0R@HN^XQd^!%Y#rz~rT$2#A3%Jfn@84AvCh<+@ zN!`RIM19J2hd3VM!QH`eA-tfw7$YMnJs_%iIHHI6192mdo}wS6^R%8~7<|RQdWw4a z9WD#go&c$1;Rp2sYO&+xy+mzn(BAAN+R#w0)LS%07$>1O8uG}zAxwbL-LbKEu7Hgx zY`1(b zkNSzqis!m1lDB~0ES)^bP~1PH0ioJKnC%L_I|wMD92bulk7%TBJ6J3y1eJaoB5*q4 zgsu+-?4sei-Ebkut;Kk$NK}6?*MDXXz|xKoy^8!XPCjj50DS|T-@wk`@)4qwbJzd> zBjD%qw$W2E=`G)i8k)nd)JWgCg4Lt25P3Oc6cl1zE;btY z;Ub5O7XD6~A(l{x;ln^Lxqq~u2agu5t1TRDm=|+WNBBi=YS<1~J{x({a1qduXMuY<5^&KPjiEU;p+zlHmsw$613hm`*Pi5p0p%wVz zizxZNv7#a3M#?zR67E*paafBGUN=sp7V5PEM$`xt=c1#k+;F_8r+BW&)zz!Uiz5YV zE|-Fkn_7T~TmqZ~DA>6Zge!H|H%`F*JNEjvOoWwpQVA5|mA^=Zrd6KA18T!Q}QD33n z?3^OT(te(sBAyZPxY@wB34C`p@LCD3K1Vd6syuxTMk@G^IY7I9Tr(9iwT(Nc3KzFU zTd5?)XrEJsyKveRC&@O;e^l;%6(V<76w))e@B-mm=IRDvg4G<`5kdtW=WkWDZ!Cj4V~OMj-;XrztsJ{R1ed+m zNVXo1NJ?V1-H<|ZeF88hV3{Mrk{>Vqy<$)r3&b6S`ByB2?O(?C7mA;dSTT(u>3jGX zi<(Xk5>a2C{y{d1jONv0hee`fv0g@TLVT!BnZx1H12j2I=_|j0jT`AL7fIlMmbWj) zJiwTXMT9cC9k|ZbgX5Nnh18QjEfKz@DzBEK`LPuNeQCMBMwS%JHREj@r5PX3p-aI* z54hh_u>)Y&YZ=_YQEamum@kOSEr$xq;;zeK@CxzK<)|6UFJ<8l_Fp05+-I!B(tv&@ znJ5CPhf1spG;@!auK>y_$T=(EPr{I_#GnuG-IegNhjPhPVg_~Ax2+O;2tw6ojp!_Q zH`ic7)!BJ1z`{$8T`MLO8VF9#MKzgIr7kbeuh)uXF?TU0k>hus z~=a!W|20!e@2cRlWBcyzQ)Ket|#gx2B@8^QB2++dTqZ~J7P?29M< z1Sk>l3#f3HD{L0`#P?Ko+#({K>JPNGKO+}4KnrXU9=1iC6_Z8NXKoQV?SNgVZQ$EB zTxy%>BHs7oncLvtY|{VOCY2`4$##(eteUn1kjc!!zXIDi@W5ZiOY-4PX)qYWIOsPt z&`fXro4}4#0iL^4)KiZaP)u5m>c+2j0&y(kyu0A`oaGC<;E@#JxjMvnn|?_b`4AP= zZ|@e#$QaW5>=j7$@Zfj9gX5w&=zth5K6c~{2hiy%zJCD39?2CB;-M4wKPWuJfhb;) zgvqZtDBQph`woioWZ}$%@JfE+l7~R4SRQdm=m_XmI4u10lxc4e7&*;Fc)(#%pZs~p zVJs|!_XsTh4(@ma`g=N0J0iA9xN{U8BS+z=a4R-#jHG3_zZqg3-oPq*xpJLpap#|o zLb;dbM@QjGnv6HFXH)VRtX&U|IR?Enn4#V`3EK)>GYcbMGK$+|iK?ROD4vbaf{n_9 z3xBB26#eya5D1nmC>^Q|;mLHc@qC24p`oBa(*a6N-039jJqk~Xfa3kYImid^7-%H; z=8AbUsE4|Sn13y!A32FAL!qgqg(-QMe>vGzyyW^S9C;d&Qi?a7#sWip&Ojrj58;<* zg{NpA!1>P!U)O0vtUNswGV@Ws8k#FGX8;-lO7ZP;5@d4A3`8j~pbU`GmzQP$Ysd0| z3^9);a`Urdl9*Y7%b&qY`S6Rgcq5JTofCd;FxrO1{JZrU(Y)e}sKg`BiSF1UxpfY9 zvM_%+hb~^Q&v{W?jP>Vb83-W7o)uJq+*7WHJ;%OLe! zebi-G76kd;U%@Osq4+8|dK|aD3NzB2_g_WxC;7uwaU9!L`>uhQfqeTKdRfI@*D;TI z-1NF=>r}Izctk%lN*o5l351tspjqhVfD|pa-EX!$Ldmmc8KA)C_-u&`Du+uSK`~Y`| zEj+*?m0&m!XW_B!dMM(ZpR_~!DFtGqAgM9YbV#}km$=p=NOcVNcm%WN%o`pFU-!2K zg{i?59N=v7F((HHUVr4}?B$1etmp*=zj`WsT;`*mRM9f;MlyYPRS8tIcxPvB`54gp zXYTb_9LQ76UIL59eBc^@33judfQ}1!Mgz-y9b%oS6m7`hb@{7wIxi_X51qPcQTmaL&1mDuu;qrY zM7;8%Y%Ul)_e$IX^7`d9h=H|xEsDC8jF!WbngiprkA%U&VIB+gwBtm6CBywNxG$+0l zrwa};9_Qu}m()AF1C~|3mK2PW9WH$My=bBI!JWr4a8>XJ5WNcb`5^i!Grp14qxRLa zJ_rwj`nUZAyVHVOei9?xdX*9K?604#Jo~Ev;Ow!(=qv#DpP+9pan2_(6S+Avv$6i^ zyek{ppatK}7B1e~d<}8MI4v2^k@J;QyOXaiz@dF-d?355$Y+rVTe0Xf0A>Mx^V#q` zZNG?tkpAIc5YC;>U%r5z-F5fB5T~Jh`p~bS6^z4yZz2a;?Z9`jn%e1cIReQWThOnUa(v7qG}7SDB}U+T9NWZZcPZq3`c8>9mg@Q%VtMKJOG!phI$gDoc&QJ%_O9cSea;IalTm@9l0BwNd$CXhX5TP)neO=<1+K;W$u_&k;k{xVT7 z*SA6Dnj0wlfOFiG?${LU?yk(lp7<+wrMT04u&t3HoV(Escho~UMmj(7P)ZcO48DZ; zpdW0E$>SWaeYu#Y5?nMA50E+HFm)KX%4%he0J0Oxjf@3{jG$AQMe)#bvE=t0iyhDP zR33Ph&XKNg?&jRr?}X?Nyc;8!Zpo{s7F7xo-O*QiDRDM5exaYT7ulQp{FIVNpLpP> zT*l7TZhs{hXz8WDvJ0DQ>q>wx0GLZCrC~SSN-Ecbe|b-)tb#etYb)ZUwawu7Ho3rg zVm|94^uu%bRFjU)K!M>_9kl>3mr|ySPw#kJDWxtz^{Y|}c13*ruVUhBP%rUTqrJPZA7*#gNDqeiAwBiBl{a0zlYr>;_M$hkL&(*_?o>8%# ztau8K8ccoRFl7}`yS0xK^4QxBl*@n>ay$=Pev&uXt4ndd5sYUGaEnKw@=?3WKbl)4 zUmJr*nXP40Se<|z=f35UvQavJ+r1IsEcq)S*{ zVX2b&Z8;^Ns>=t0(iv)ND4ly~(yDZZzLaCZR^nkx>Tan~ydqHrqS^=_mPvZE@(PYK z{mzFfD4hUeid9rxs>VP6`<;|s#yb(J@lHd0SQ6f1%&F+W$ggVCc6SVXBg^}D+_$1~ zue>M#>=@-AB~Q4twEQ^{VRw^!o{%NmOvgC|+)3gf`T*M(2$6oGbD+{vffmTBj6ooq zp^B2G&_w-PHDxfl&4d4w?1m`3eD6ybgwhdd*p{(8t%lMbTYC3vC==mPcde;RLAds5 zO|&?I^VCurgP~g1QU(A69ImC50_M!D1@2AZRUwKS_Ad8?D3hR!Yt;sWhpUNKd~;ppnH+tn)MdBy)nQ6H92D+T zU#Sj_yQaP}6ppb=xDt*GqYmLpZGl%8M=14xpl?M$r6M=6p#qTif>X`PUg!3gB#BO# zb9XC1I+G=WVZQnt{Qt04VT$u24OKWEyQEG4)=Ba|}4a*h-VB->G`u#>ymt0A6ym(pw&|h*mzx9e^fEsMnATy!Atu zHNeewGJ?I*<3x^kQ;1!Rp3+p=NRktqEAOD`%C-Qtrt*vyO1RU7lk)vp{xP|rXcgaX zp^S0d`3y8Z5kY~O85ppolHRMOazv0HqRvW3A>nk4a!I^+WW;~QL7Df^H*`^&pb`C3HwDLZkh$GMSzjo6r!p+wU(@t8y`X;(W_r+DsVd(8$sT=_vfi#U$*QBRFf{S$cY|+l z$XN0(e-a1Yhv~1w6Z$Bv0mU!(QQ~D7xUX^(PK0kiB|`jkiRUCJMO~)Jg-vc^_ai{z zCP7VcUe-_9N%^@&e^ecI(WvU$=HmaT`equR?XUcX@l76py5SeB&6bqQ`rpkWv2OsH z{e^!Wh^j@-TdRIN_dlx6<#L0RO`!PIK}v*7YKm99TrQsdA2s{y&Eu7>l<(9=gA1U< z`PFXW&Q}I2&!LTu4pEMZkL!8HP?&4@io=u#(n%Z+0|I|ts|ty_db?m7+3PKT#dTPa6s3pE)t{=&fUA@?6%_{R4%3va61E zXW@%YSpl){#BnQO5ejkRRZwZ$T3BmT zU#<9(uijxbY>@aeN}sYusYBRpJGxdmXM@avc^k1z>3n6QvYTG&b2cfXW#U%e&B`JO z{F=?mOB^Gby9LIr7rSg#;@lz{0BON_E9xJe^caWOtUs*reh|;zs+>W#S^I6uDw#L3 z4K@n7vD=lo1;5pkv&}UCzv*YUE9VqA^vixzW(sPfm(rp2u?Sv!l>T{a-?ax)du>G7 z^|gl-i`*)obxeuEpspWNysEYt2?d@s{A*OoX8-=M$}s7;Vvi5M$y4+1XZ`)V|L23^ zdb#6DGaEAL<4-FkWESe$GfD_8=X+kOAcPt_de+D7Bz8(leB8WXmJZDqn%^ zhMiL?RA}@@E}wP(Onz23Cq>xF%;M503p!;fV?57=-dpqw=ae=!a&CVrW1!jfHJ6oc zHqg(uH({s}`O8gA2-_34l%s?+lH1BiA->e&DR-6S)Is;Xr!-Wku-^Bf5^f_I$f8Wh zLrwIGuN6Njv7AzBvcwtz>U>1jd`hcj0ezxMt6ixxZ!4|Nl3QG5)G*k@gfi-Cn#(?A)gnF@ zZj#(6EMrc$g@|xxPW?9{4Okc&+pz?5V7F5MQUTOBJ;)uuz*SYE0oFh>d+bO2h1}DKg3DEjY7MMXdm!@VW{Z zw>U=ytECYY84-+^Zt|{RwIue}ZU?KGPSbuyC&|b%mUOS2VfmS_R>hmiY+FsegHZnC zYASwDfupOd<&carrn*`Sk&a!})mE^v`D>`5@b05(sNUXA4`e&b{4J7aCmq|4kJ!$g zj#`|P0EsOQJhO)CUwFu0rrd!B$ZFPs)&TcR=X^EQSOmfQ)>Jzof_k#18ji@ReJ!;z zf(c=@R6j^xk6LO^2xvwv%w;KmtOYqm!dHmuJ>kwDvbDxB5(L^~ow7;8xYO5Cg^5!Mnnlo$Zh#!|&v0uec5PVR_=17u&v zip&vwK15xD_2^q$4Meui(%Nbx_nQ|@rqpm8g$1+J>MRpOZOtjs-ZJD?TlJVwnNd4-a@){<0f$z7D3x0WPWOU|R@ptYpG zwd5fB)-C!OjA^&@_n7ObK1D8{H6b+(e-68jm{XcNCZEjwmCw|{Vo&AlI%*{``7&qJ zfq=E%aWVMA_U-^Zh=s>C`?-EP_;kg zbz!L5qU>)Feb8Zf2T2Ddm*bjAjvIp~4gtfktDbl)zQa+=G%g&b%3}nL!qjF(#03o4 z%G~B$o_VEj4Fi>7=kC^1Tjcdzf-M)YQa7$yAH|4w)mJAVMxRw5dd`tk!qxiN0>2op zHgg;+B`g^U=+V_=&)DEKpf>UpBoRmdIK5Uox`9H4X)bsLc9^(JZpvJ_*Qsy^6K8{Jg(mHRzS z)q&#eS}xE`O>mtIUDq=_$$xB?t2qhjOcDymSUU3RX0ReSA1FUYaH-~M@qp*$rOg`d zD|Z+I_o~KRq7PXX41khGc`G@OK+Bg39N%1xfPbMkhYD=NgdxVYEkd+gCz0BrGo1$B_HPGq+0OH82J9gxZdMEE!3ZpejV3REhW#9wuE-v z!mnGZAv8)a-%7P7n8{kL)d+Xb6DCuoLs@npuIjL>!BebVQ%NbLMYLAE3g7QfrVPtX z<9Zp_RLglj-5P|6=NGM2{N@$AwSmn&pjT_7st6}@NL#fA^yG-PYV|fRk4ifl?(ehL zi1>h3%`BCA8S{6TI#4`Qfcu}H4%6xPu&BwMCKQz2`7LMeT_k)=>=?4QKK6j%rQu%YHs8KL_pSoQ`T$QEfk0>!en#k+big?*72{ z|J~i?uEv5J*HgyzC|`+H*CEz2E)J%(9AAvXY9kf2i`uMw*k0M@EdPnQEbC<4V;b@v zhgb0dDRu24+r+u!F6tZvmEF3kEf6&7*H!&V9((QvObUhE4MYp!!QIp@a998620e*w zmF}vaYX#ke^dg{{Bqcf}f+CZznv+jjuqlOy$iv&wU7ZH0uHFL{*p^rJfE+*OLp`9< zkha+ansO}r_C$v`LcM@$u>;x*3bQ1y?*;XVt(9JCZE3lC<0Fs< z^j53IW&bLtn1b~;w8<&scA3AA)Gm{bAr@o$7cU%dC+FHSLyG4f<9nKMy^oR%OW83} zcvl-GON}d7yAN=DRX*59o$Ii<6`A(RHZKEtJ%2kG_)g1#j8Z35B4u!?2!i$IE;6KD@s5(Zf>tU+d@1X$`UuP+i z$sf!~!*P^-{8e*Or@PU~CnA&oG$)^fUU)Q2-6fAU4_8OIe@3A7M7X!B{ING2OYt#- zp;DsPTUK+q5s=uWJY)o>h^|JcgWzA~9jP|LF9Ea~2?J=y3r4CDj)&L&FnOhXOemV-jYCV{%j8>1rlxL5I z^EQdy#;C`D4sMT8-Nnan&K?6^PG^^~Dt?QB2aQ#0h_5So(^&Xc+xX*HRYQ^ntrk@L}PpqiBEiI&s7jr%h{?)S?3R~yg32I+-W1gs%C|nl71+e&Ua=PBecXysRQH>Gr z8}p5c>Pm!m$4rv;p%_n?tOfzE@0hH>LQ~f*==R-AM-LYjB?msHZ&<=BcY~>dnANc<@}cN7t6)ZdhA$5>8?!;HO*@ z91RqaDxnrc5dq2hs&}q^5#OUW>u5 zy|~U|ASQ%t7ppJDw|d-siP~0Xr7lq$72DVn%_g1@k+nV!%V&ij(bux}?eUS*ozG57 z)i&aIXCAv;4bB4~Y_fcw!0VQRV{pc4Ddc23cUlIQ6oG|hSf1JJupCxmG_o6^1k!lS zaI!txgTA?`J+qO26Ol|G%%-?94p#%ro~q&&)hCpXG)i z|6fNFk-K0SuD8o+o+5r>n!f^7kt32?w3BF(W35l$C~d`jRxU zVx=M4v@4BBwQoRuWw!WxrJ-S^PyDHt(&Yaz`9ILn@CU=Ur0SagBetW4i#Jw59>JN^ zDo7w)99#tfX1J)o8p8wYxYd|162zg^2)inZS0h5Q=(xu4R)vlvD1&b`6Af1zDpj=Y zJ|-8*v`ogL-&wL(h-k3d zU=j8WkZmuDeH#pKRr+!;rYk!%&a*p|4$ZzIV56Z%Ob;Kbm#*^v9r>Rm|69xd82R5+ z{x_8Wb>)AE{0|hLY&0zLYg!kzooxv~zR|jo&Nelu_MeC)TMdnPygRZ9G396U@E^p= zpRu}gijYm{{ixJUhSovKKoX5);n7Cq z#w=!S!Pe1s@z)lh4*pQ0VrYJ_6|DSTTf%HXZxU>U?AA}Tav0v0TCkWHaqY)p7^?p$ zNm4V80}pUU_Y+@iG1L;%w?Tq{q`M91^M!dk(D9bcc0;t@-=-xVMeT~a(A$wXp0?V7 z#M}1O61R)bb^y9g6zo9FOcntZ*6%j7H!p#3{O_u4r11FFU^S*<*I>4D zuxRirvOivA{|aXEzWDi92t(20ELncy>92+;&rq%?c-%H~pNi`y&G#6B^>;rNz4sUf zx?^=7n2>Grjyfdr_ZTcqKBj5+{!N!F^9j^$`ob5#P1~E8=ZzYPI^?pvIS+bHnyj8p zFszc@b0EO27j<$B(HZB^Ws0H5n4V`lm{@>SF72V6M~BUGzB$L`nu6KwGiuNGTRp>? z_&hdhv+V}OW%=$aQez^yEY|^5?9HRl3|Q^r!Mfj^QFv=E!TzKu9uX5E^+4IehTW1b z+uRUw79ye;?Om3&aEa?V2EUB%hml7m4yCquLH8WNR#I2#fJk04QZtzv7U?calLgRv z)QCcj!}JoVyDVYlMBjod<_L1@t;ZNIEX)a&fxCU@AB=~CcNviKmb3!*I?~5 z*O#EbIajB^&YZ9Z8<$;wMA9FCJgwq?bXmF~4VR_4OetR*w%`0pIul*67nFEGZf<0y_JmT$rhNfaeu7TlQ z!L7N5_SF_a3PdGrLzmrysf+f#(to7Qkw{_1o5PjbAv~UTDREmGl?irNRSY;_2=QGu zj0Sjx=QJU>$^RG66veUr05;2YNsfOG8cGa0m$-ctr!xtT$;S+{^&X4peX=Yawq7@i zfP6#k>Yp7$F|sCqjfC-hIlae5<+b&*8GwVQQ1Y>9hWoDhkgqHvFCSxVs&JBTm#A<8 z9CD%@ zeiD9X4U_b2wODW#Id+LZ&LZk5p+9G+8IZEvO=+8z;8S3;8!0o{9i6SRy7>H#Or?vs zbKsV3h5ektU+2xEKd7f^JyhJYL7n|McFBTRWs?}Gz7?gBBJ1c-TnrlxMI}h9T zHTu+_CBIT-KLcfo)@xDssAN96uYZ{!${8X~c z3FqZw`ZQp|oZsWMS?n>;!4dq;oUMA%0J3cQhawQ5?}uQ7&P6F$b(D%7uu4yghKgp_ z3{Bs8ffvVZ=;a-3_L$~)<(Do=$3&f^_;Jn-U>UaNF*N|E;^<&gaY{Ot7DuHB67yTa zw8uOayRSj+Y9PF>gEcf2Z(N5=Hqg=aI<||9OWvVMY$2B2K(pgo$_>L1ean~AQBcbx zT&l{py3dd$^(X7ql14h4A?m*+1wTi7prlD+yc5g7!;Vc(1D=3-;z+z@cuTL_=$QEz z1aBy*Rk&@?>x~T)Dd8iIigyirb?QL8Sbx;1PjLKx58GD8!g%t2Dn59C-Q5hw?gxe! zI^*P60{T1lJ~Rx`#hAyHH%0)QXp9K5Ue99NxYx6I%Oj~;nF4V~= z(dmVuf6TOz_r(TAzIG4IHOAOV=A8 z)Fp4W=um;Z5xW)l+gu^rPB9yduuT)A>*Q8+^x=g$01L7!0)@nBJm zeI}N=vufCriSuBV3dh4Gy60!&qC2Yz{f8H1<%%E=76|zqI04vX@8!X&WAIW8)vU$n zFD@Vpczx#=4@7|4st2p3pD{_i1aT4M$&A=Y4fA9*a1Pqm6Bwyts3-6@i#cRH5nDW2 zZPSQJ$X90HDkxgS1mW~#Mc5lXX=1e5Rbpao0+xrO_*qbwPr=HX%_kqd;Dk+Zwm|gs zVs)@zGu?~T!(wr>7i-&iCEhc(+1*fMHhY{32_zW_*x45Z&SKkO#Z7sX=JP7b5YfoY zdRsk#Nev9arn1ehYBP`>d%Jlq%U!X~%-#ZL{>RMfVx<-2&C+Uo6ataQX1|bL2}~c% zS~`gJN7euSzN0o*Nb{C@BK%WCgCp# zI%%OU%kvm&4^tEPk+qe9An!V4%QDpxeXFo0x|c#!VV(4D@uIj2TY>$6IaOH;>;N3C z%2Ke|7gCL_#d_pqH5RYCCo2213_ZkzdH(D@bk)25%z_JmJb--+y`513ELQhaYzko0 zYI~p*nI$^&6f5}m)I;fQ53+y!(Ne_Bvn`fbWC>Tl#rsxPwbELY3ce<=oHHYJ%0aeO z*sU0HC&W=Ji{Wl(pStK8X?3=x{)}p18Mkp3NKJ^7tH)qGnkIyKD;tHtsidS0F)m@> z4Au{?SfeaqA|jAk->!&Irxo%9BvUk!sT%oB(w|lz2VqeI%)?pCWaK3?&js0x72<_H z^x#{t$V)c74`3Z&zlg5`S*TC@(@$OLV{QFRli)zXVnlu*n_KA?ed9n58ZB>=Vy=kv zAXcx+4g^5XzmRTproDxuX`H5m$C{Rl?LjOtVwgBMSnKvlJXBntfD{$Q!dN-Ml!hXD>06V4#DgwPBg5wShQsdp23gL%+n=g zv2kz~8x!mdQ+X}csD2Fm2bo8Kn;c0AStb=u^Nv3&n=|L2HUM~V#ZB3X1+J21{YxCH z#Udhh1Cp7i9%Sp_z?^^^8f)N+f3zD`cul((aTLD^GQ)wr-*n^nr_0|eBKQK}^!3r8)St%Ol_2t%?| zZIAs@nJSD__%gA6%VO=xZ)YpX%3^*%C(Jmw{Q)}2?o~7>l+r;~3>S^1S(!y31y8k#?_aZRq2@Co+opA8$_HV zh$w(z$io@R4|0ncRp$0XnLoChtSr_5=m#0}^Gb7QhD*y~)lyek7AS{4fMMAkY0IjN z<&KGNGlj8$sxh*5cRrz1u}X!&d>lQ+h3kWHVeAbYhl~kh)%}lCud#0;tSBrp_Yi6y ztc6{c6=DP7;r2rq3&EzUDV$mBUPMFK?1^ACiQX!W_z5ElHI-tFGgaoecNc`fVgG0X%%`O`gf~(G$_Eh$d891{|a-i7r%wG zYW~*|%ly?Iyw}ebfRmD)MRsP$2;o)-GRPkyv<|E1?<0HAVy7(fyz`Q&ACZOrQw*zv znSY{KUx#&$sDr#h*rEpLK!-bVw(P{a=C5#}1q(ykJQ#t3$%O*u4$+`4YmHUcsJbiy zO2|v=vaVQsJ+8}!Rrv^yy4td1`oJp2^9F7-ele2;i3#;st*X&lXygBcUav1E)?>aR zzaBH-+S8eO$QRTIA|MlNcXWwhduU-`X~3%JDt&Ys^rP@`nM8B4z3Uhhd$EX%WLN7| ztV7KJ6)LQed*6asF?oLh3f*hp(PVo(9+^LY-+;V>vi8abj={B>1H~@nzKN??qi278jKhRvdi8??Y5t zbvGsk)=fufOV&;o6rYP>Z~p8Wmg-59pD00!GTN6MN)=^{=@Dz|m>bJ3=yj=%k6W?b zZZ(s70WqyQnmZ0IXB2K0p|-qAg|lNWOSnjW3w5x@@%dYdysp^Mg}sf3`zmxrm%J(7@5+ACxg1{aGTa<`=%~_-{qAO{vH+2` z_h7*e{~m0lPH%RJFM6^C^g2r~)?1xAAM!<3M^zN`Vj*I4FSbnIq`rvvV0fjVH#64q zPDCqcYHL#NfQ0XjW?`y?%T>tVj<0*OZS*un$3E;wC^$du!`{_nL%d@@woF&W@vt8o z>ISWgejl->P>Wvl5&K4uz2|0wSxd{eXYkzx5;~pv=p87%yNmrS?1Py#=qm&jTai>h zI9x|?33(9=BzQY6eYs5OB5yEjh{NfpgV~2Q=lxB3+)|u**JX(XM&^@l=@ALpt&Px- zL!-NfZ zekN`WVQqWdMZu#EVN>o3)j+nT0G88Enn#EQvFk_~=Zd|9EK!|dW^0XP%h|pCLUOh# z2hq0c&?!M_okr;=@x{l?FXPeef8*(8JWU>w(XuESYKo$zYtcr-a+bVsxsWunfCp!_ zG=F-9&i8*&`mZibFCq_J5YtW<8ru<7;^3ef)RgG020e(7s5+3u+Uo-lE5^+B$zM95 zOXJo3_q{~MGDCWZ1*z;kQ+N^TlF-qvmaQXLlDnrk?1sLZ z?q$XzQFQ&39fS5-@OZX};R{5+PG;+LP!b=S$!uJA#j!Put=H?D))o_IGrQydOopp^ zUpR)%VqSV(kYmDZX3}Gj*ypn8dfn%aO7mEONw?JT&-aYG>3f^Rgq18<1g>N~b(bCE zSF&|#wP?CsY)(8*3qR-Eq_W@#!5q`9uV}rVjl$-mV?BheN#eqKma2Y?qvHs_N_C7pR&nRw`p-BbM%A?^PYN5Gua*Eh_pu&FFDB36o4Y zUR2J(I_eMcP7Z74yJ9}Hmk-gTic2a$#H|aL1-FrM7=7ENAP2iK14YPQ*2q1k6=v8Y zwkYdS(RVLfU3v0Xz=z-nQG5@&Kgr+I9D)0oURQBc9NJrQ(7U#N_mRbgB5FUwcYH+u z{VWIyDO2~e9oQp@%Y}^dg&2^_T0);Y&SStH5(t<+&tx1j3E>`Q9?bPIMjI3)}Guj%w=gM z79C-qV2SN}6qPYev^mN?^=M?5YuE}dOMy6c6g+8_sCA4DhH}>z$5?K&D!9Y|{SkwK@VF#QBKxr<_3{~!%y{-4e%-_%r=WRXC`s(Q8 zA^EI_V}j{y5TN+p7IfQVwu&n!Se1Q_mz4y)G`ZWG1``iz2{g*-}phO<1AAv&1$V#2_pPF8x8&7CFj|Y zfbIiPA63z&HgaJ3Y<-6uMmXw=&aN;L%bk^{l!m& z|3%iRO5kKv$4Pr=&m@iq{0(#%vGvs^N1I!JYw7meV zDa+Bl2AI2qd<eRGPn zr?_{SRSH#+1VFcu(W3kDW^V&+4r~gMC(dq`{4%PRt)*9(AVi0Q1v` z&xFSn=C3|Fqr)K|yCdpfVZM!?XudN@)4BElW`sHe2ABhE=G`egW|gA#*48UoBb{ zvI#(PL>v~C3R#0UKc~pWJuRP+ePYzf#<@k8EEe*Vgze2e@iZcws64&-u;^3Buj%!X zfN3Qz@}p_L6B7$r?Ur9_zI5O@llN0I495{PSZvC^*=W&02*&Ic%{q{Snsy8vsPtiZ zpwSxVgsg#SCnB4(KSVQS#{49zUuC`l)XMt%=DpU@a4>V1Q(z${Ke6DS^%5PfvVe>w z6log72I~8!w(t!w-#meVdw76(;)wy~uoDD-4{+PTJ+Wxc;GCQi4w&U_z|gOAV9;;F ztkY0lz%Rnh7Qzi1!=XEk9P1}q82l-0mKIisu)_PI_$u=V)1syTwfpZt**CdF{~Tg* zw&ijp&H=KmXR(QgrS@@A{TgcqIjh?>*05Uw=$NPcr1kw+>7gAo)J+RY0W*iTTD5Hh z6u-L}ayCJIjYQo!AMS;^W-8!R8BRb(`%=!Ui!0Z#Zf`E0Tw_5Mo&!#KzAkE9XHnK} z@al7)?X|uO2g@z!ax%9B^;sGJ3_9=ES%5hMA?9fid8yZ!!o@cL_C1Xk1aj|RLp5n^#&I7sF)ip z+W-3#C|*bo=7-MaKx8Aulu9(7rLYvS?gmb=28p~I>}%a~(f1}KzC&X9O_qrRny^1v zjNZ7|@zI|U2XOmht&@%RT>XKY5`A}kG!}5*iTXt>$bBLpnS0{0aA=-Vgl(&q;)^0y z#gLwg<;Rr}R;{Y7-vyif>C{7GheTVS;Tt!j`jI@9-Q%S4@9%%*>@mzZ6| z{Gg~d^A;o{Z}H15$RwAZ+ zVu*mVMa*BUpQ#>&)UowD0cj#gtow^~);S%zzu6HT9&tN%8{E2{V0XaqEFz4or=r~* zoOm>JY`equ>mYzmxCe1`f!K8qfz!klvPKF0efAj%uJ_q6(}fhIfStX=Sc4s#|A1vf zVx0AWwXXgQmn*O&S%)84cb~FQ`et60 z=j<_-Xx=Z_P-rzxe1VEg5nEnBep~Jcf5{Ab-4FBX^B`UCE${Gm+@LP;of{AGu)2Y{ zyQ7em-SEi;9x0x>@u_MrJuNjXZ#kwL_-&oOTfA7}#sl5o!d|gNj&UsE9G|S2Zozgxy-#n!)&J~lRnH_%flx*_YP4B{!9DEoe&UmaXY2NcLf?cMMY%9L7@ zAB8r;#un zk_k!4sC4S?c?+ZqXbL|j!%|H1G#tSGm7tbtVJ}MO?<2rJj(8DO0Y|cXg@=`ghF?Tg z0OKV>4^kOn?}P1x49Kb@jCSlJAq7?xJ*+%6;{=u;_su@oGe)E*r0y0+SzidSd3t3j zVK#{QhJ2shL?5_szWFBxLGfcMu=RS04o7}BkAlACYe}d(nAyZaTNx8WeG6RkQqCgQVGI7)ZY|V0U$aAoiTA7Xz(%{*QPxtdqczG!aEG+j+(h&O%nh8( z0W8^Bv}uCaP@TuufPQ6SV6xph2*Jr7J!^F+x`QJj8TwlI zc3}wOK^av*9+hChm(^fva_I6k$V$?ya_C%yq8=X>ZGp<-E2&tzuP*D?4d60=k%VO< zhQVMB+}?f>i;TtaB%QjIT-UOQaAurAqhZj!1&?h|@Ln2teUdPvMq6eAlu;j}%Pyl7 zwGTdGo{FdVX~0b?2Vu+2&Q7dCY#Oo{m`xC5o)UMLS(C+I zHMqaGMIxr4>vz9NBTe|#M2q1YzBPHZjD9~-lUUcnY9E}3siPBIN#=w-$mtjg3(iY3 zVc}zk+dSnV%2PCs1fVD&Tm()q;dod-mZ&uKRD=r}J9`n~*#c!2>byfy z2Sp7*N1U(8eKJn{Ac+K&6WI$uDUm-ZEI7|RwK~!!F==nn-)L}iU>q9EvXKxy=wK^q zPkZ}$H1l+gRz56kavKeoRv^nF3d7VpwPrc3rJxo3Zx=NsNfatbEL`R(&1nvgw#*gw zU|uyN1+WCW=?tcMr{{9iMF*J`n%<~sO90oJ_6}U;DMcFCU89*60Ydd9)ktW8B%^x; zn{HE-Xwx~upV=LW6{X>iN{6zn0+b3SC+}}o>MAN}?*W_%Fksm5V_%CVwRjUfUnxGW z#j90qNfFEmjO?^sXqR+25aVs}T`eBk`Q{3(Qp^d~XK>o=)Ji@S$Ai@&OfU~~;(7Db z7%DZ@XdWW(0cx^`sR9tRoU8|+v_>J`h48wNbrM5(jf}U-=qFlxz*!t#J}lcuT>_=r zW#I|dXgFV)9Lf``1UM4wS&A8L(Zf}mSSW=B=eIW}UNBExjk?9gbb6vWFad|tcGJ@3 zUI?CQeG1N;U`{kG6c0jpYu{<`YS|tSS1F~XBDppX(0eWygKP6T*g%_Co7ZUCl2FYF z7t%t}A`Laqk@ofz$-$OOSb!p3_)fuhO!Hkp1=n1z6B)I+rRFDqIkzl91C~I>LMNw% zcS5Zo{6oDT`TJ1R3gxvk7E)Yd|Kl(Pg8frG^ORlWv6~X%(K=8xT$ob&lSNaCc}kMT z{@Y6Y=bDG`%~RGx7C_`G@Mw{}BzT|{DJ(j8vS0z#|hvT)R zawGRt&x^F8Y)**Jy6?d<_6n^kOjQ7o4i^YY$IUVaRj!0=mX4BDwCIiK1`lW}m&9*j zJg7!>c(F`*f~CVg*v{ONE^IIgRK}=#3v)Oh{BH1O0)aiFEHRHZp)Au2(6!0;gnXa< zOulE5J-7Lb3So`A4a!e%9>pU57xn;1xh1dgW~{SKx5e>r9?+{0Vc?{cRdxgJXj23H zOYcoM63lOFVMXxRCg-?NhcZz5a|#{X=;TOHoB(br3n zN6C$IOWtLlBeSrH8*eY;#wZCJ39M3X+)bRV1Ic`}cwC3a#D$edD6*o>CBOZ5sKe=&|NUIBO{NoZNiyed|WS4~9q78(`aPQA4nV63)g)@z58=)pLA-56Q zVOB36_89X;cqC2hX1~H^{-Ubnf|jQmSmVYK-(h4*Zd?~G^9+o0>ilPcQ_hXSiUSGF zepqs2e;GyN#$$kv{_kB5lH9m2#V+N>xs>#jJ480xvO#+8Yjbluc(g$iFUHs7){I~R zfT6+C7-B`Zv}wcCR3eu$G`P)E7;3KQ2RbM#V~E!l%lP#qD)Et%0F?5w#}rn|P(5V) zbo2^zZ$>px^gif_DiL6aUur~tm-s~Fvww;Fpb;@otxr7)`z(8l{1LH~A&wx#*BD|O z!uPPwhNZQ`8*r7*gFPsW7-FMxTF23TuQJ365{2^M`i4qOJPMWANgRm)L#%>O%x&`! z*=}mI41V#GfcE+9U`(a}e;0rr@uX zAr1nxoFVr7ri>xB1{h@{hKLiC`n(Aawbs<<{{Al)fe$vuEc=2S(Wr*TMBZ*O;qwyp zc`#mAWDR(Y&eIS~l>^4O2u_VLZX}lnI}D4;AQ@u>mA;HI_Ms3D(<)e6&AtOyY0YAX zwE?f25eZ1q;ipt5ipB#UVM9wMm1y-q;Q!!}XUoD9ti^EtZ#;4z;7AuANiI$IX8=mm zJx5{XJTeH)@EVisNWoLBt6>q3Y%5wvf=9jquU3M3aFtT(D87m00l4_EJ(Ab;{AvMO z_|$wf$J7$Bq&D|$dK-{(Zds^#O1Y(7`pUTF1kFd>^5g=YI35XZSqCuZheXb=#O1=Y zl8;dUZi#=5TUta~LtY=BG+5S<_tBLI+`Frlu^A%&0CVca+t`dgh0W+^)}OUSz$Gl) z#RZawd(!IAGY9)+ST1>o+|-0<+R-BcIbbG7b5BAF1#j>uqXhz~GjEO-9?_J4W$Xt*&snV$a;Yh|;1cz{ro6dczf#m|#>4n| z%+Jp0BC;8`h~dq+2h?*vZH9$Rw%E`N8R#M|H{+vlF}Y)NwAn{M&MiTkVMG2@K{e`_v zz>=^$q-$*p_x`ITtE^kf95&Ig1+N7Cti%?4NsDDt=0MvZNh_U5(8)r1+YAN3oY?|x zgVO$;0HQ~7Pk9$(bKdlU2#n^nOx-DdarYCs7g9p7#U0IaJv@m0mkiH$?wu*-#6mwJ z3Llu$QPafmSUp=JYP95yjAy_coHIU`7-DEkzL~obWQQn><&{NrEL!Ni=orhJ^Y6h_ zoEuT8#}Xiv02XmPmV4rngWqH2n$sr^a{E7ym^gk&hby(lR{Ra!7)Q%iyax_w z9Sd9YLV9;+d?F^vzr~V7-q5sfHxxZej{(;^{z&BbcyznU*jViBEnkFooy!{KjTbNM z$CI;2SHFSi-G+zxdp*}f#V^amrHwV)i(Q~|*cN4ZE|#{zL~;Wk%f#X3zZWK~M}PrM z5_!CT5TSJRcnX>=m(ocS%S)=_d?#+V;Z@P+R2ycgv5pWMZ=tW*zC=&TyEIGNPtoz} za}S!%o2+;QjU9TUdbya~mfMXA{7^&`mD=%+Uf(<%!u?!Adm^a>s)!*d2u;xE_px7jN|W_wQyv;QY7+td&N&TRzFHbsy- zkKA?*-cxg1#fJ9WuR_-cNDdb#pNRbSJR4V%dcV!P;*E^WZ}YdHf%oif9)@>PYQ2LD z4tMl^2Q7e?RrYq^A($bZ9eDFtcPIww=oP5BqzwmB-#2t8I%!5^uqn}L7O~Ts;SS|!QM)&65=yabsD)m7o@NUh~ zzC0H9?ma)?UA@*!rM?k>%O^ONuP%mv!0CI8+dtsrFo{O>;~|x2UPaB|W6adl$mnEv z_lZ7}nFZgoLuuBCTmAUw`0h%2e{S*gU^(y6@UsJ)1soYe|X>{)&m*9P!5_?$=G zk9Z$_g~cNKBR(vo#&>9qEOrtqmm73a#jLR2YpxELb99I0)%t;2}@x`AAvTa9djl|$5#Zmn@k|?97`a(sRGHX0L1_Vogiq5!-wx!(+wZe4YEwYX+H8dZ4#uSdFVp~ z8>GST<&{CaCSKSbHi)k`Ujb#@n3o!0E=!iEH<yP^P}(_aS@<-qD!wF?ZLwxBmkJ)(=gG`E@9dHU18@V7uw1I5!j>XTR_n z#zXx)u}wqT$&vIp9`gGBKI#vT#5==yHDhZT;X{!+j7Osvu0;fo5r7qY5Yk8Dk73|= zhlR&*-oR&}Kt)UCPF#S1a%YxkH=GAnor{*iUGAHt5tHuc6n$y*pLbd6h|J-stIVo>o!ng zln7FXk~va;Q*=y&Y=X}UrSYZ}_W&o^eh=6`!36^N1bG^-hAxh4HDUTS1tR`E+;8?y z=at{=Kp6IWKza+V?LJy6jo@}R#CB$B1C*wMUQ4f`{e~*?h0dSolg?Wvy~L1{DxZJL zu}2v$hHHCekaBLpYNs@(7MasM=nV<>TwF#%O`pZUkq%4q0zAX1yA28ESvvQryp0Ip zUJjLbIg!oA<%6Kn+!EN0dXsD4jnS^f{Sxc$V! z(J23Uv1K%WKO+B=vg+9l7fAmKYr8LHHy-Pc(js@0*-aMlV|WJk1arplsE9Dar&~yt z>J+7lmO*#8oqg$ApVlF?%K8`|*W~q^_ZkaC${b3P1UKTgh2^Y3_;_+=-kvhq0dK6( zL|=I(W`OJ%e8y@lZ`@ivPU8vftYWstg@@vv*jgJxG*yjeH;rZr(VQ;Nb7iLtL+&9& zL4$RcaE;|vyw?4OA!ph~17T~FNo8O6fD9(SvL(K0W3n(#)a16Bt_WUVN zg$m|`PkCqPkDmAx67B%;=cl|WJ_r#wo=?F{ynH-Q!SemZcwR>j?fUQuycw>helUSQ zOB!>GQod+wu21u|PyP`T!Bn=>u2<6WCI{3iNR_>mC6!+9L+(yx|Iawn9V;jDIXaJD z_E6Y8Tfc}kj#iT}^U>5dnJ?1+vs(6u{Q zk&a(7!M$*^F<>e<+%QM%RDO!#MfOT|KG99@Hd=f+i+6nYJT^PfW6r>`Wp%xRme{K~ z|FmT#{tAP~IN0-tlz&q6O@tC7TPraV!SmTh&1r^ntL6-ZbEl)l7yN|YD{CY=75d#F zovpcPzockcpc0ZeLnpY^ux&jxtLvyoXgLerl9|fs%`6c2<-xG z)-U-)-x3Ev!(UTGy}3y*bcb=D#q}lM=b_J)tj;WTNWa4QJv1V|;z^ZkpP(KyOJ1gX zIxWyqMjydL;qxF4Sw!kQK2!I#0aCc>u65Lj%NWM6A2&l zL`ZS7GWc%5N7p3yKm7m?ErYKlxI4j56WmO$!*H3qu}pDG@aMW|jz7QVm+5{=?jr7| z^NZ|>S>!^JJqN6>xp$ghylW3w>n+EFZ}<;--+KcwmeN8V<;0~0Ih%YAA;9kd``xkO zJN~6!-|+)6bQuqH^#7h4b-HlJ$IJL4U4@4@DWo2Oj~uVyp|x)G)8kIprj>eSlI)0V z7o1VJezqJoO&JH-x1z@ithw5Xj1@e#t~=t_;&1Xqb3zWT>^%b-tS2%SI4J8w z!yKFsfu^F%G7M)ixa`uSmdjO?qDi1TMW?lVJeDlS*K%Jx6?StiPsW|JsC9fNRK4%4 z!*apl@cjvOj*E%)*Ykq`=O8@U?1r3231Q79VdAk%by(bJBQeNl1F!GVWQFWjfi6ow z(RKp{RY38~JQ}&r?Kf!r|v^(S8$mLFK*uX7GV@$H2`TszV*b zx-HyJMc>K;EmM}^?g6IS^y<#+YLX4OEOBD!R^HajG7p`+RH>%I9Fe<~XPZ_7MpHM` zMaD~Q& zzwV^NKbL<2B91i&cvZbFz>%AWWu|VSqw`_@Gu=VpNBNs>xOm?BINzz~pU=-n{T>zJ z`Fymlmt#pj);xZBG>Y+N3N3Ozn}JmA9n>tGDhHlKJ>!PON!$#X0vz1e&tjQy6bEAF z$zrK+X0efC)JbeS{3gCT$!DO`hMnSL{BxVVwnCxDXMP3<-8xh3IE4u$Tbw_|TeLbe z76UNz*~|2b2iXC*H3^{cWQ;^h=Cc>+l@GG@<=_bb+s_yKWj=cjC1|>Gd63P4?lVur zTd;>tV^?vAsB;E+E^s8C;aByffOVcX!o~0&=Xrw`_i@P)ZwuJ4r+hpLdC6i0fE2xn z{!RBBu;`i;lbDA5q*wY`w;h6|%h>?p>j4%i_MgWYj7{7)50=zMRKLKh)@JfjBDOY3 zF`YTR=1Z37CkaodO0+?#IZE`pfMHTBR$o9B{UFX>;BWY)K+_!EYYJYxL51Kd9LeKu z<3;dA{(V53Sj=lx5%&#ppg~v&Ij{o7-L1ll=wp8fk4spgG!e}%@fiWhEj9cm(c}Pr zlRD%8ev_)=_e)q)LkRwz_jl8cSH!(Zyqd`Woma_tGhA+ad^neK-7W~59gQ?dXAKet zNSFqR*B~gTsk#Pfph21eQdxsoHAoyF?i$2HgV+F3G)M^^utHh`0r6_Cf&SD$sQ}@L zOWKDyqd~?3@-$3B_DP6+5>-~T2^&|Jd1c=MEo^}nCO1Z+O{c`+%e=d;$WiMLzRL|? z2rMkb9!t`VnvzcKnKF45L@sHN${NHQkP{k2uR&4(F$T+6cd_|{O!oogg-E@I^?p0Y z-fR4(u0j7G5)Pgv;Sqd0dmo-8d}9R8o|=3=i#a~&5-0}z z#rxxu$dSMJpSTXO>2HqDmx++uXxU=X={9=pHZk=!{|s9(>K({MxD#^+VQs{$JJ^Z! z7y7$E>Emc}m;2*Vo}=S^zQGL-6zd=Hrxn#G$dQ2;Ub--m#DmK#QNrsnAB?+u;~t|Q zKXWX6j0p{@hmW7&U?oySl<<#q`Hp!d@L}b9Ke}Ks^<~iSp`>}VP zV+((bsQv<*Sm7e=1uEp6IPe0q+8?6nOUQN=h5aQzi8pt8yMR*U*zDp4olkN&a@6m* z%u!3^C}G|qV@=)0d4Cz}`Az8}nSk5}B&94&-VkADi3U33+qyubyN?d`Ac&}N-P(ZOKsfoCh$8jSwfl*=<1Z&myL9rU}YG~30s zfqYvk>Eqs5q&Uiq(YVa1a${qvAa3joE!R2R7>{qLoZ`lNSgPk5jXAoNj_IlqA5FoP zwF<^7c!*_#yYW3R1rHD7JvY7DQoQss3SCpje6tZZvrY)lipCyQ(i4#`q(pi+41#%j zl&zl`3-z}}Mnz*lluv@>&o6&@=_>jib5s&Bh;I-DmDkZ_x!;uqodRiYr~E2db9b|f=zr;OgxL3=NHg@u=bOhUml39CI5QKh=9(3Bl^H-(A!{gygxxzp=5Y z$3nm~KnF*!#zwOaOnzt+W01uhMrT4{q>LDGDwNy}B94gfn;3&L9>a^1qL2)U(x8bE zBgZ`DJbEbIUg-{>c6;Rt@SwKgg!P}>D-RLV{Mi-MV%hDL){<7SDH=9bo}15*$`+2* z;>*s}kQcfWF(h1PMu@jH6Ns=)?ZU+F%gnb&XX#Hd`AfT8K}}w03Dv^r?2Ysfp_Aqv z@ue(8cT+pfe*KmUZzze=Ef?>Q?qdHN#>fzxMC{2rNL#A-m)~$n)-n^(UsP>s4378K z(u)Yw@kz;x~!>T><(o=kHD z%X>0GGDE38gNT>x-$B`?a{sYRzo4I=)8ZJrVj8RXxKGS|@dbWz5i@NrRQ z8QD?6Uhc z?~$kUehu`QTNwQ+oUJLlfjLBc(ZU$=exByNft)%6hR~VeYnN&kAXr|inM4li2S313 zc1dIt#kx5dy~jX$5wFCBWP0?dE9AbY6m1-;o9UPwjd@#ty1G~wZmcRcy=iQK&%<4N z)5zR#r?)89*g&tFBC57Bey8i=*xt&x&j{8up{?=V@Nq@hp^y9Zg-g44UK}r9*ur;! zve=_rm{LjpkMnj}mWtSn~hJ21x!2#Kx}1F^#K)F%7NM{+(V70fOOE&91ePOMjnI zyKzfnoanpASXrdLYphavNpCH9N)s)$X5*O*uI1SCu5oOzF2&LO6XPAvswwdrxiWiC zmMY0^cEnFNjxl$;8dLG=JDs&0Z3ulgX6X zUHmlowo>~WA1yoEO6@YbQ%dPNKhf}OeJbsmifx7lm{MwAKcuxqSpr{+j@ON$)n=B) zF9Qda`k#+-%)M@GIXh#ZMT@s*zE*u3{*N~EK37`JXEnR59^*>=|5uw8oYwH~o+`CV z+qyJ<&GN48EX_cN(hS)aY8mP&Mx?9JZZjO;iuLJgRp~fV>Tvv-t~Rff(DZ~sNrh3~ zF)DpvHoz3X1a&Yfvtd$W4T|Bcq7>MSiYNBPJ9SRzJlqud!`y+Z<5xeJxu`|L!@8n> zmfF)NvVxmZKkdV@X|;ypJ#s}^B2HwfmGIIk2tpfO3mU8JaXidYqYY4AX*f#_j>&Jx zls-#T<$J^k8wAH_7=veOfkElhi2nDu4^Z;;k@)1pMiNJ>x*HVt#$0i4#8Xd;IkVKz zmZxKxvInuk4&ko^rlOaUWK`>0RQj8QzjgZS;?XR1bOL2# z>{3UGYCX}IYjDpd7DI#^Y8djY`mjf`8Lf65u1I8e8 zw4_n0*g9LSE-4fM+=_6D;J6EeT#LVEs{zPKg*j>{hJ3?0s&6Ibib1*Ci2gUo|I|i` zcyEr{BA60dvP@MzCnBrh*a^dBLisJ1;O^81slqWwZ75Uw2VtGSD#BjCVOTCxn?G0W zFUy+>zpTJrP=}&=kt~7TUGV}8B#Eq+y&ANToLz`8d;fo z-`JJteUtGw9Y*i9L`?Zg4MY5OU#S6Rii3wYq{Uk*;`~=?J-n&J=BagM|{8$z<7JbC8Iv60t($)#8qO7mZiR0NelHY@++b-Wj6b| zwa6D6=c%o$QVyRZb{P9nReWI3EFe>Fi7?GqLuD<;0g7{DB`gV!cL~LF$w`CK0fp=| zUwuP1{Z|0XKC&2&Du-8vkq6)`C*|3JH8qsV#;h7sgYj7GK)r>=UAf4lsLW*_4)J7#1YXMq}P0asBDz!a1QNx!fx zRD+v?=__x+1gzC!z2;|ng{5(&0O9=7zc|t_Ml4kQYEy@qji_M@@V61h%d5lNMkP%3 zolVxTN%*gSUHr6A^+iX{U8vSYcJD1zo5B~qNDYS7evyjXSbrLnjxfzICsXF7Uo2jv z24-vk_&Ch+bqJyyHTIJJYEHBh!BoAX?)O&6KNu#j4DWOW>7NeR?*s!`3V+rAS{#H^ zI^}fXN7{PjxQO{i4G!;6WKhbe&dfks!y{;+}CbGU!{lholYUnAL*`?^O`h8yG zOvga|-PFGf3Lcv-uYgzmKHeD5jVmeMKYQMFFHlpBeRv0|_^|b;_=fmv3!{2nPhd(T z1y@o!G$MY6@sujwTCCQtM!0E&I{|;6!x-ENVK#>Bw8d)u_8smTlm#$fA*crF)}F?@ zC}|#w(%)TqJxqDcU)5Jtd>dO7-;)*ZdKY-@@l5sTb6V)WReh~{@By2+$YyU-p6b(| zUavPqZoo|7Gf5GRzg6QJ7W`vSYClA70hOulFHNpzcf5x;+1dL3#N? ze7;1j=Bv3eeoN6x!*(oD>o5fma@H3`poT3cIAQjbqP^;`%Jm9wq>setS*q5R!>{Ki zwCsoYn*gJFMygEF>08JK7^YRf_++X22C8J^Qq@0@I>Tv-av6WOVYs`*ZCQ$2yi~0U zT=u;hh%XL>zzU}*$(vQBS$F)6gjozzQFT|mnUWf3)9gtz+!X=Qq`H}8LcMMhiG{Fc zi-q5-tr`=J>qO%o{tR1G#RB6llkV`}e&UHB*-yNesg2uvBbDYbVSvhh@(-4J{c(-D z3r59jVan_NN?fS~Trc1<;7;;k$|^Bu8Cq33;nhegr9r?SB|odJVa04xJHwi@NfOH0B!O(Rw30UCfMB4Q zuvzT~t8lXuK4Q#qxX73t$PdjJ_em)XoWdL406bUH`Sp=_38p{mjYs7 z^GXFd+o82P@zjAGF%<}2Tsf4kj{Z4dELM87Qfd4KHauefrqH4Q{c{{;4yNF{u zRS{E$X#N~@V8)^Z^z*S`Y+>@YVDh#!uAo>t`4p7l{tY}gJ8;F)U083Gfw#`YWCOEI zomX4-u(iS#lN6GNl#F-Ol2zUokOt5fgsJWYa|~{#B-)qggk8RikQ99ICm4mr=?; zm}2Z=RQkhS1OH&yHSs+kwRMv+(or{<5^)pF2Q*n3W`knJ642bpLv}r?+3&AGwugxp z8~3Qu<$3<$5mRP7X39A6Vvkz49IQSBHJEXtd5#)d4(|IB3>Idt81X82GPviLFl)uC z95t{Udk^Ev1(*ZkLXH}Zl3MnvP0K^y;9O}9vsU!ltNLe@m1VFeSJGj2mNl#_i>jDA zX=R~m8D{2+hc{RLC@U}Ajb8QtFXf-_!?A^iVe@S39Cf?03=oIK>?aRv3*pDkMVV0GZr?RS4?(d~kZtSU49_fA8 ztH85-dYJ3WmGdxlN|Wyj_f41tv2@=n^;)?aSF&Jwi4*%|y_)u`4J?ytaHXgwS1O;? zxUuw$j{DU%wP`rDO)8@4@IIYsF7NPP^chf^-wJa>#OKLbYhIq3Sw8bT z`;KER%W3ARb4aa@22VPK#Yb6w=da<)Vwji6%VM$MkerQvIixlyClCnz-*;g^;N>B8 zaCrk-_Hrc^X08}_SSEYyu$iSGz$m?pFMDI?4h`i79(R^o)sSV26QKrSH`~cJXU2WpfQJ)>D@1QMtJmp|1tM7ikMrAro zYZ3pO9DeD)sddB4LI*c9Dx+YiHOQ_S$P|-qhQbRBd-Spb4*jMES`>V2uLsPw0&TQQ zzj*PR8fuAbVN}|{7z(u@=@-q9BUV`=Lm>w&A%pBL5krro@q$FoarGlSC?1{<3!lfx zSB0*bBm9KA=KT!X>ga-1G}+H!3|Ox!Sa>^O#smK9BAgcE+hCRhPWEN;!;QUKCF(2| zs&K!$GN%=KPrQx(1aPwRVLY*wX|We zMyV}rlw^L8(uzikNs4b&nAaksWb6I?@0{m(Z_o4R_dj!H=FFU#Gv}T;b29RIUC-?W zD3frJ31pLt7e7L(Ksziv z^5I{T0xM8H;o?eEgcr*seB=~>^B)4cPjel!Lo__;x8Ow|3gIJX14a|}E>i$8Jj;ta zP!e9;gEH`u(*nN`mi8+JB3#TsrFe1rue5(H8#!!jMrx-9*zNkri2_X^RQ2(iX5x#r zD1;Z^Mln43>$$%d#pBHxUXyz!4_Nq8_ySV?weWh6H+rcts2nfyuQQoCyym~JSWf~2~yI%8ci;zxf1#ET0#ft}X zmnS?PW+SB)%Uv%XM#OPUJ7!p{O^^r!D3%1`T-WEpRjx0EZ@Rt?-f%u`$wU7rxDja> zu7fcb*b0aNq(WrK58)}7_~OYg0 zi!Zc35w1syUkL|ZWPL1Lhe8~<0WRj&uQ)*mvmu@XGY3%%j}P^lIDGUa^me2s5EC!; zno)#{zoI1h1h4rMQXyu+nZr26ga_gCr~zLMJCF|61qUa(1%kVgqaDqdcBG8NpIqMy z@4bS~LPq)UF{C&p@I%*chv!{sGaUfeyS@^p4ELHI(u&zg#}b#gzIeFTF(0@ajqo7S z0a$lnYOb=i7h90R#pK`FjKt?$UjYxHa0TGFt8JVd_&SQ;$=QWduHj7L^^H zHY(v?rf^#E`ZYa&Dm@=>GQH+L)Q-=GG1IuD@Z#@~3X}x1TrbXZeFglN>+9h@*SErT z)2W!F-*K2@+90D&c=c^=rtntRXTxz>UenEi)8LJ_Q;?4t#bDn%xOd>A;UQFkZ-)nS zxL@Gg;I2Q>C-6j4HR;zYxrP#eA%7R`5Wy9Hj;Z-LiDH8K9jU_M3hL<%YJL2f3L zGzOlB+VJskC~C)N!<9&Q}eE1bofx6%s58DH?Xv*+!bA-ndRzjJl zQ1~pugGlj{okzI7gVdUg0x<4LP9-oyZAyI?UV>yCV~luw*$nD&(Q;&zlpICRXVWp+mbT!R*}qYTD8ZBLiD%Jrpi z@mfaAJ>2Esaij`_;QVzQgzy6RJ!-;t!!w_yK-_jca8QLUTr9lcd4)6n$6;QqwCz*{ zFMP@Rc(@9w%}T{8>&3OMFNasXY?~knzV?dsHE>w9^@(ujtJXKc8*8XNg$uyw(vlW6bZn9^h3QpWiK?zTX-)ymk z?t&k^WAoe&v;JkhBXd!`-H3-ZNF7Ri^j$g*2P=Xz{%w6WobVozg7JRMeVrO@~=KcxLbbesVnaus}JJ5d0>hSb|@;L#m6oP}zp z?@n8|ICu(GQwX!mYwkvBrhIrDwG!R~?`v|y;jWJvO9*d)5AWtig)iLA_5UmzxqS9q z0e88+3HIM(50(U5QS2vlDA@Z6H!8f?XD?R--UH)XtQXhpOWKr9z!}qoiOvTOOzdh8FAJorTq?XTK*u;H90 z0f~cf>@W6Ir@^;SCgGdmj9+O#d^Q}!YY{a;EF6uLPb&NeDj`k{tmpqXt#|a|n`baR zPk22X#=`#>r{c=kY_WA?J4 z(zU>g2N8+H!(q%|YCt4$Dhl9P{c0+Z;;;hNoN)c{SY8gC&l?uv41k~W3Z)v~4$mE8 z3lsy#xIPs=5cc~0k9o=6Q3V(Bwxx^2k#Ak}_9gBzpGoEoj5rwu@EPz^qzbgddHhdl zvIq~to6>1kd=A`zbcSl-w>NVP!b5O~Guf6d4lcOGXNuXe5av#?J|EViaAMejN{J)R zo60M;S~?m$i4-R;(`PnLqsfR<2M12KXDb#iy^XvGFM;19#do?fKW5RE?C60bXZTDT zeiWRJ)RtNB0oND68rOSn_nAdVPfLYxJJOjDe?&^#14rCpeF_}R3nTL>R}CDSP5Za9 zk;ca2JL$>zAneCWsV003T!ZujgvI6NOH@O6CtP+n&BSO}0>{p@6-a{{kore0yzh_p z!1*w5w$H?pR{R8|;9F)pyyo}|osA7~+8iR{v*6*mGy%RHUUWb0jZcJAk!qF=*P-F9 z{DgF`aY&Qb>hi>w#Fl&8H}WNwB&Y%9P*b90mH18@map2e^UDIakr zuh9xWWBi|m@hrBZl6W&x?K9vhltD>*6i!nqaRz+Z_0{mdt~Wu>2vUJW^Qi5Z;(Vm= z0@#Ig)rhw~<|fX3jP^$A$?b5@r6=zg{j-~nLakQNsEYCNMNHrFdm)Zk} z{DaYdf*(S_<8VgH@pZw?YJ9Nup23oIAa5+j!d)Rz}MZH z!7*>pp$Jcf^J}fIgqQr&o-Mx2G0mt^1%e@@W)fpIS}(qWnuz1nVghg44ROI+^o2G$ z6kM>G(Mle!+QRLX1f}qYcPS|0J@EPW?3t^EH4Q$KPPkb1zAd!)15(9$V9^KkA>xPw zx6=OlITgE=Q;Kw|Ghxz)^iCp)IolZZ@Zw^m+63Xo9dtCp>tN+hdj*MqXyQx~o(iLO zvnm2FZrMX+4)OB~4&KXPhmYOs_{{5Uq_I&8TUuymymvwx(&H21dr0{-z@1-lm64Y3l#J&D1;vX_ zK7TYmi<7^j<1i3qz*mqir)t>!193PagO=nbcJ!e$E_DTiqrxb(j^(-L^uFV-i*gMIv_m&9#w+ZlcnNBr%u@J!x^ zH!~i<4wON-_=txOdbkA#;op3GheO&*SmO7adg6#Pq8z^L;WTDP`As*H7gNsmn;?RC#23M9&#?zfhKF6>4(IgqhwmME@TVA7bP?Zkp5Hu!)C7E{#V=^SEF%9#nAP8g zXYuL0`8x`qYIy%|{NcIVe0b{sfA|+pCVT=ZaWOoX)d(75W8k-_hl7RSZdM*7v~%6V zKc3G)sQoN>?-0KU5S|aOiE}Few<1RwHDXR7U0OZx%Xq(OBhyZJ!B86>2M;1$1#NKr z2*1fD(*S%NX~g8aKU0Om9TPUAAaP=@qd-V$H^a#z{ic}kjFEoFT*7(=o%YDJ4O-)H z8Vz8bgV>9b@R3U+v_xX?XbwU~BHtpKZoD`NsSxS#6jJ^@@PRQjExrJjq1-JFy%e)7 z)gS%^Tmoy5N-FlaUJQ)2;TiDsO|&-!%3-C&29%E13d}zTY(L0_tI_5c7+2s%RIM8l z+>dJUhR>nm9sYQTq;I3PxxN{ma=qajqRUV?4&3H?eOu(4NO2r}-0+CIVOZyU7Yfj0b6}b4^AHI~|oEMMjQKLd`|v1+Ah5nj|PR3#9#kX7O0G_;Us zfiPXKWujVvr}&~)7s`wKT`z`QFKW@H;`lQiO6qQiS~;d2qLy6Bix0V8T;qDN#`WSh z*Na-dsDg@GmZ*G0tv-|&wG`0fupyJ??hx;Ey|_>!BXOl0E^5i1G7`0#PF~ciGkH<# zjO4{Drduy+C6mI%aclV#*G>n7e5D)S(FBLxhUY3sgtL(@r(9T%a(JiL0{dq%{O*X_ z#Fxj{^l?^B@S5dl6M7Prp(<2|icmc&N6n}Km7+>ii-M>XMgBK>BGXxum=K0zZWXz_jhQ2X Date: Wed, 28 Jun 2023 12:50:02 +0200 Subject: [PATCH 084/226] [debugger] Prevent long 'getAllClasses' calls for obsolete breakpoint requests Check if breakpoint request has been removed before calling processing methods GitOrigin-RevId: 106008787c70207ff21bb9c17c07e4167a864794 --- .../src/com/intellij/debugger/ui/breakpoints/Breakpoint.java | 2 +- .../debugger/ui/breakpoints/BreakpointWithHighlighter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java index 74dcb6a46d5c..a7422f1ac620 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java @@ -252,7 +252,7 @@ public abstract class Breakpoint

implements protected void createOrWaitPrepare(final DebugProcessImpl debugProcess, @NotNull final SourcePosition classPosition) { debugProcess.getRequestsManager().callbackOnPrepareClasses(this, classPosition); - if (debugProcess.getVirtualMachineProxy().canBeModified()) { + if (debugProcess.getVirtualMachineProxy().canBeModified() && !isObsolete()) { processClassesPrepare(debugProcess, debugProcess.getPositionManager().getAllClasses(classPosition).stream().distinct()); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java index a1275a981dc3..12976f805c1d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java @@ -119,7 +119,7 @@ public abstract class BreakpointWithHighlighter

Date: Wed, 28 Jun 2023 13:25:51 +0200 Subject: [PATCH 085/226] [debugger] IDEA-322970 Fix freeze on breakpoint in inline function Search for inline function callers is done in a non-blocking read action, that must be cancellable. In this commit, we make sure that the outer progress indicator is not replaced by a new one during the call. Cancellable read action lets a concurrent write action to execute successfully, so the UI is not freezed anymore. GitOrigin-RevId: 9cbf218ee3955b4bf0593daabaa4e0abd9839525 --- .../idea/debugger/core/ClassNameProvider.kt | 9 ++++++++- .../debugger/core/KotlinPositionManager.kt | 20 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/ClassNameProvider.kt b/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/ClassNameProvider.kt index 64cecccdba42..341af3e32f4e 100644 --- a/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/ClassNameProvider.kt +++ b/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/ClassNameProvider.kt @@ -168,7 +168,14 @@ class ClassNameProvider( ProgressManager.getInstance().runProcessWithProgressSynchronously(task, progressMessage, true, project) } else { try { - ProgressManager.getInstance().runProcess(task, ProgressIndicatorBase()) + // We should not create new indicator when already running in a process, + // as it will make the outer process not cancellable + val currentIndicator = ProgressManager.getInstance().progressIndicator + if (currentIndicator != null) { + task.run() + } else { + ProgressManager.getInstance().runProcess(task, ProgressIndicatorBase()) + } true } catch (e: InterruptedException) { false diff --git a/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/KotlinPositionManager.kt b/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/KotlinPositionManager.kt index e95ab99fa7fa..d2a651552b33 100644 --- a/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/KotlinPositionManager.kt +++ b/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/KotlinPositionManager.kt @@ -16,11 +16,13 @@ import com.intellij.debugger.impl.DebuggerUtilsAsync import com.intellij.debugger.impl.DebuggerUtilsEx import com.intellij.debugger.jdi.StackFrameProxyImpl import com.intellij.debugger.requests.ClassPrepareRequestor +import com.intellij.debugger.ui.breakpoints.Breakpoint import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl import com.intellij.openapi.application.ReadAction import com.intellij.openapi.application.runReadAction import com.intellij.openapi.components.serviceOrNull import com.intellij.openapi.fileTypes.FileType +import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiElement @@ -31,8 +33,10 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.childrenOfType import com.intellij.psi.util.parentOfType import com.intellij.util.ThreeState +import com.intellij.util.asSafely import com.intellij.util.concurrency.annotations.RequiresReadLock import com.intellij.xdebugger.frame.XStackFrame +import com.intellij.xdebugger.impl.XDebugSessionImpl import com.jetbrains.jdi.LocalVariableImpl import com.sun.jdi.* import com.sun.jdi.request.ClassPrepareRequest @@ -563,7 +567,7 @@ class KotlinPositionManager(private val debugProcess: DebugProcess) : MultiReque } val isInsideProjectWithCompose = position.isInsideProjectWithCompose() - return ReadAction.nonBlocking> { + var nonBlocking = ReadAction.nonBlocking> { val kotlinRequests = createKotlinClassPrepareRequests(requestor, position) if (isInsideProjectWithCompose) { val singletonRequest = getClassPrepareRequestForComposableSingletons(debugProcess, requestor, file) @@ -574,7 +578,19 @@ class KotlinPositionManager(private val debugProcess: DebugProcess) : MultiReque } else { kotlinRequests } - }.inSmartMode(debugProcess.project).executeSynchronously() + } + .inSmartMode(debugProcess.project) + + val xBreakpoint = requestor.safeAs>()?.xBreakpoint + val xSession = debugProcess.asSafely()?.xdebugProcess?.session.asSafely() + if (xBreakpoint != null && xSession != null) { + nonBlocking = nonBlocking.expireWhen { !xSession.isBreakpointActive(xBreakpoint) } + } + try { + return nonBlocking.executeSynchronously() + } catch (_: ProcessCanceledException) { + return emptyList() + } } @RequiresReadLock From 8b727fbb98500415912ecfb9357c7c7da8a16db8 Mon Sep 17 00:00:00 2001 From: Sergei Tachenov Date: Fri, 30 Jun 2023 20:58:00 +0300 Subject: [PATCH 086/226] IDEA-321134 Place More Tool Windows popup to the left if the button is on the right stripe Not only it fixes the bug (it would go to the monitor on the right if the coordinate space is continuous), but also it looks much better this way, even if the IDE frame is not maximized. GitOrigin-RevId: 75ca572a389c0b633817a0458531f3df0d1cfc1a --- .../intellij/toolWindow/MoreSquareStripeButton.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt b/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt index eb188c0139f6..f58ee5f71d3f 100644 --- a/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt +++ b/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt @@ -89,11 +89,16 @@ private fun createAction(toolWindowToolbar: ToolWindowToolbar): DumbAwareAction override fun actionPerformed(e: AnActionEvent) { val actions = ToolWindowsGroup.getToolWindowActions(e.project ?: return, true) val popup = JBPopupFactory.getInstance().createActionGroupPopup(null, DefaultActionGroup(actions), e.dataContext, null, true) - popup.setMinimumSize(Dimension(300, -1)) - - + val minimumPopupWidth = 300 + popup.setMinimumSize(Dimension(minimumPopupWidth, -1)) val moreSquareStripeButton = toolWindowToolbar.moreButton - popup.show(RelativePoint(toolWindowToolbar, Point(toolWindowToolbar.width, moreSquareStripeButton.y))) + val x = if (toolWindowToolbar is ToolWindowLeftToolbar) { + toolWindowToolbar.width + } + else { + -minimumPopupWidth + } + popup.show(RelativePoint(toolWindowToolbar, Point(x, moreSquareStripeButton.y))) } override fun getActionUpdateThread() = ActionUpdateThread.EDT From 15ad3ded2f7bddefbd434117b7491177a202a50d Mon Sep 17 00:00:00 2001 From: "Victoria.Petrakovich" Date: Fri, 30 Jun 2023 20:50:38 +0000 Subject: [PATCH 087/226] [kotlin] Fix Kotlin conversion failure because of lack of dependencies Quick fixes because otherwise, it's a dependency hell ^KTIJ-26088 Fixed Merge-request: IJ-MR-109867 Merged-by: Victoria Petrakovich GitOrigin-RevId: 767f6bb9fc4e693178382e57cd16fb0af61e0c82 --- .../project-configuration/kotlin.project-configuration.iml | 1 - .../idea/configuration/ConfigureKotlinInProjectUtils.kt | 6 ++++-- .../framework/ui/ConfigureDialogWithModulesAndVersion.java | 7 +++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/kotlin/project-configuration/kotlin.project-configuration.iml b/plugins/kotlin/project-configuration/kotlin.project-configuration.iml index 39723fa8ca5a..bdce6644f29c 100644 --- a/plugins/kotlin/project-configuration/kotlin.project-configuration.iml +++ b/plugins/kotlin/project-configuration/kotlin.project-configuration.iml @@ -36,6 +36,5 @@ - \ No newline at end of file diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt index b66c73b0a43d..60ccb53f2c96 100644 --- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.application.ReadAction import com.intellij.openapi.application.runReadAction import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.externalSystem.model.ProjectSystemId import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.module.Module import com.intellij.openapi.progress.ProgressManager @@ -58,7 +59,6 @@ import org.jetbrains.kotlin.platform.isJs import org.jetbrains.kotlin.platform.isWasm import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.konan.isNative -import org.jetbrains.plugins.gradle.util.GradleUtil private val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtils") @@ -486,7 +486,9 @@ fun getTargetBytecodeVersionFromModule( module: Module, kotlinVersion: IdeKotlinVersion ): String? { - return GradleUtil.findGradleModuleData(module)?.let { moduleDataNode -> + val projectPath = ExternalSystemApiUtil.getExternalProjectPath(module) ?: return null + val project = module.project + return ExternalSystemApiUtil.findModuleNode(project, ProjectSystemId("GRADLE"), projectPath)?.let { moduleDataNode -> val javaModuleData = ExternalSystemApiUtil.find(moduleDataNode, JavaModuleData.KEY) javaModuleData?.let { javaModuleData.data.targetBytecodeVersion diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.java b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.java index 34ebc71387e3..431afbf656ac 100644 --- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.java +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.java @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator; import org.jetbrains.kotlin.idea.projectConfiguration.KotlinProjectConfigurationBundle; import org.jetbrains.kotlin.idea.projectConfiguration.RepositoryDescription; import org.jetbrains.kotlin.idea.statistics.KotlinJ2KOnboardingFUSCollector; -import org.jetbrains.kotlin.tools.projectWizard.Versions; import javax.swing.*; import java.awt.*; @@ -48,6 +47,10 @@ public class ConfigureDialogWithModulesAndVersion extends DialogWrapper { private static final String VERSIONS_LIST_URL = "https://search.maven.org/solrsearch/select?q=g:%22org.jetbrains.kotlin%22+AND+a:%22kotlin-stdlib%22&core=gav&rows=20&wt=json"; + /* We define the version here because we cannot properly use such a constant from org.jetbrains.kotlin.tools.projectWizard Versions + because the current package is not a plugin and there are dependency issues if trying to make it a plugin */ + private static final String DEFAULT_KOTLIN_VERSION = "1.8.21"; + @NotNull private final String minimumVersion; private final Map> kotlinVersionsAndModules; @@ -105,7 +108,7 @@ public class ConfigureDialogWithModulesAndVersion extends DialogWrapper { Pair>, Map> pair = getModulesTargetingUnsupportedJvmAndTargetsForAllModules(chooseModulePanel.getModules(), - IdeKotlinVersion.get(Versions.INSTANCE.getKOTLIN().toString())); + IdeKotlinVersion.get(DEFAULT_KOTLIN_VERSION)); jvmModulesTargetingUnsupportedJvm = pair.getFirst(); modulesAndJvmTargets = pair.getSecond(); From 1a810f1492074c1c0b638bac1d28c822e659c76d Mon Sep 17 00:00:00 2001 From: Sergey Pak Date: Fri, 30 Jun 2023 20:36:29 +0200 Subject: [PATCH 088/226] Don't try to add action to all keymaps, only to the active ones (relates to IDEA-300250) GitOrigin-RevId: f0a8a2d56f0711e00817d5c67e3c75ea47c37e6e --- .../config/impl/AntShortcutStartupActivity.kt | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntShortcutStartupActivity.kt b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntShortcutStartupActivity.kt index 22fe00933b24..c49caa3e3ed4 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntShortcutStartupActivity.kt +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntShortcutStartupActivity.kt @@ -10,6 +10,8 @@ import com.intellij.openapi.actionSystem.ex.ActionManagerEx import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.serviceAsync import com.intellij.openapi.extensions.ExtensionNotApplicableException +import com.intellij.openapi.keymap.Keymap +import com.intellij.openapi.keymap.KeymapManagerListener import com.intellij.openapi.keymap.ex.KeymapManagerEx import com.intellij.openapi.project.Project import com.intellij.openapi.startup.ProjectActivity @@ -23,15 +25,19 @@ private class AntShortcutStartupActivity : ProjectActivity { } override suspend fun execute(project: Project) { - val prefix = AntConfiguration.getActionIdPrefix(project) - val actionManager = ApplicationManager.getApplication().serviceAsync() - for (keymap in KeymapManagerEx.getInstanceEx().allKeymaps) { - for (id in keymap.actionIdList) { - if (id.startsWith(prefix) && actionManager.getAction(id) == null) { - actionManager.registerAction(id, TargetActionStub(id, project)) - } - } - } + val listenerDisposable = Disposer.newDisposable() + Disposer.register(AntDisposable.getInstance(project), listenerDisposable) + val actionManager: ActionManager = ApplicationManager.getApplication().serviceAsync() + registerActionForKeymap(project, actionManager, KeymapManagerEx.getInstanceEx().activeKeymap) + ApplicationManager.getApplication().getMessageBus().connect(listenerDisposable) + .subscribe(KeymapManagerListener.TOPIC, + object : KeymapManagerListener { + override fun activeKeymapChanged(keymap: Keymap?) { + if (keymap == null) + return + registerActionForKeymap(project, actionManager, keymap) + } + }) Disposer.register(AntDisposable.getInstance(project), Disposable { unregisterAction(project) @@ -39,6 +45,15 @@ private class AntShortcutStartupActivity : ProjectActivity { } } +private fun registerActionForKeymap(project: Project, actionManager: ActionManager, keymap: Keymap) { + val prefix: String = AntConfiguration.getActionIdPrefix(project) + for (id in keymap.actionIdList) { + if (id.startsWith(prefix) && actionManager.getAction(id) == null) { + actionManager.registerAction(id, TargetActionStub(id, project)) + } + } +} + private fun unregisterAction(project: Project) { val actionManager = ActionManagerEx.getInstanceEx() for (oldId in actionManager.getActionIdList(AntConfiguration.getActionIdPrefix(project))) { From 9cbd7b314f07bd12daf46d686d83915f85704c93 Mon Sep 17 00:00:00 2001 From: Piotr Tomiak Date: Fri, 30 Jun 2023 15:18:11 +0200 Subject: [PATCH 089/226] WEB-24744 WEB-28896 WI-52290 WEB-53029 WEB-57923 Fix formatting of raw text blocks. GitOrigin-RevId: 9c57cea75053d2a570b2ed9848e6a1ad891f13ba --- .../openapi/util/text/StringUtil.java | 43 +++++++++++++++++-- .../psi/formatter/xml/AbstractXmlBlock.java | 21 +++++++++ .../psi/formatter/HtmlFormatterTest.java | 16 ++++--- .../html/unknownScriptFormatting.html | 16 +++++++ .../html/unknownScriptFormatting_after.html | 16 +++++++ 5 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 xml/tests/testData/psi/formatter/html/unknownScriptFormatting.html create mode 100644 xml/tests/testData/psi/formatter/html/unknownScriptFormatting_after.html diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 38bf0603beb5..7077ed379591 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -3056,8 +3056,9 @@ public class StringUtil extends StringUtilRt { /** * Finds the next position in the supplied CharSequence which is neither a space nor a tab. + * * @param text text - * @param pos starting position + * @param pos starting position * @return position of the first non-whitespace character after or equal to pos; or the length of the CharSequence * if no non-whitespace character found */ @@ -3070,9 +3071,26 @@ public class StringUtil extends StringUtilRt { } /** - * Finds the previous position in the supplied CharSequence which is neither a space nor a tab. + * Finds the next position in the supplied CharSequence which is neither a space, a new line nor a tab. + * * @param text text - * @param pos starting position + * @param pos starting position + * @return position of the first non-whitespace character after or equal to pos; or the length of the CharSequence + * if no non-whitespace character found + */ + public static int skipWhitespaceOrNewLineForward(@NotNull CharSequence text, int pos) { + int length = text.length(); + while (pos < length && isWhitespaceTabOrNewLine(text.charAt(pos))) { + pos++; + } + return pos; + } + + /** + * Finds the previous position in the supplied CharSequence which is neither a space nor a tab. + * + * @param text text + * @param pos starting position * @return position of the character before or equal to pos which has no space or tab before; * or zero if no non-whitespace character found */ @@ -3083,10 +3101,29 @@ public class StringUtil extends StringUtilRt { return pos; } + /** + * Finds the previous position in the supplied CharSequence which is neither a space, a new line nor a tab. + * + * @param text text + * @param pos starting position + * @return position of the character before or equal to pos which has no space or tab before; + * or zero if no non-whitespace character found + */ + public static int skipWhitespaceOrNewLineBackward(@NotNull CharSequence text, int pos) { + while (pos > 0 && isWhitespaceTabOrNewLine(text.charAt(pos - 1))) { + pos--; + } + return pos; + } + private static boolean isWhitespaceOrTab(char c) { return c == ' ' || c == '\t'; } + private static boolean isWhitespaceTabOrNewLine(char c) { + return c == ' ' || c == '\t' || c == '\n'; + } + /** * @deprecated use {@link com.intellij.ide.nls.NlsMessages#formatAndList(java.util.Collection)} instead to get properly localized concatenation */ diff --git a/xml/impl/src/com/intellij/psi/formatter/xml/AbstractXmlBlock.java b/xml/impl/src/com/intellij/psi/formatter/xml/AbstractXmlBlock.java index 37162a481e7a..109f78da6d35 100644 --- a/xml/impl/src/com/intellij/psi/formatter/xml/AbstractXmlBlock.java +++ b/xml/impl/src/com/intellij/psi/formatter/xml/AbstractXmlBlock.java @@ -8,6 +8,7 @@ import com.intellij.ide.highlighter.XmlFileType; import com.intellij.lang.*; import com.intellij.lang.xml.XMLLanguage; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.formatter.FormatterUtil; @@ -280,11 +281,31 @@ public abstract class AbstractXmlBlock extends AbstractBlock { } ); } + else if (child.getElementType() == XmlTokenType.XML_DATA_CHARACTERS + && child.getTreeParent().getElementType() != XmlElementType.XML_CDATA + && child.textContains('\n')) { + result.add(createRawTextChild(child, indent, wrap, alignment)); + } else { result.add(createSimpleChild(child, indent, wrap, alignment, null)); } } + protected @NotNull XmlBlock createRawTextChild(@NotNull ASTNode child, @Nullable Indent indent, + @Nullable Wrap wrap, @Nullable Alignment alignment) { + var text = child.getText(); + var textStart = StringUtil.skipWhitespaceOrNewLineForward(text, 0); + var textEnd = StringUtil.skipWhitespaceOrNewLineBackward(text, text.length()); + TextRange textRange; + if (textStart < textEnd) { + textRange = child.getTextRange(); + textRange = new TextRange(textRange.getStartOffset() + textStart, textRange.getStartOffset() + textEnd); + } else { + textRange = null; + } + return new XmlBlock(child, wrap, alignment, myXmlFormattingPolicy, indent, textRange, isPreserveSpace()); + } + protected @NotNull XmlBlock createSimpleChild(@NotNull ASTNode child, @Nullable Indent indent, @Nullable Wrap wrap, @Nullable Alignment alignment, @Nullable TextRange range) { return new XmlBlock(child, wrap, alignment, myXmlFormattingPolicy, indent, range, isPreserveSpace()); diff --git a/xml/tests/src/com/intellij/psi/formatter/HtmlFormatterTest.java b/xml/tests/src/com/intellij/psi/formatter/HtmlFormatterTest.java index 3919c1fff4d1..caa514263f55 100644 --- a/xml/tests/src/com/intellij/psi/formatter/HtmlFormatterTest.java +++ b/xml/tests/src/com/intellij/psi/formatter/HtmlFormatterTest.java @@ -37,7 +37,7 @@ public class HtmlFormatterTest extends XmlFormatterTestBase { protected String getFileExtension() { return "html"; } - + public void test1() throws Exception { final HtmlCodeStyleSettings settings = getHtmlSettings(); settings.HTML_KEEP_BLANK_LINES = 0; @@ -49,7 +49,7 @@ public class HtmlFormatterTest extends XmlFormatterTestBase { settings.HTML_KEEP_LINE_BREAKS_IN_TEXT = false; settings.HTML_KEEP_WHITESPACES = false; - doTest(); + doTest(); } public void test2() throws Exception { @@ -261,7 +261,11 @@ public class HtmlFormatterTest extends XmlFormatterTestBase { public void testTableformatting() throws Exception { doTest(); } - + + public void testUnknownScriptFormatting() throws Exception { + doTest(); + } + public void testHtmlReformatDoesntProduceAssertion() { @NonNls String fileText = """ @@ -298,7 +302,7 @@ public class HtmlFormatterTest extends XmlFormatterTestBase { bodyTag.getTextRange().getEndOffset()); } - + public void testInvalidChar() throws Exception { doTest(); } @@ -435,7 +439,7 @@ public class HtmlFormatterTest extends XmlFormatterTestBase { protected boolean doCheckDocumentUpdate() { return "Performance".equals(getTestName(false)); } - + public void test10809() { doTextTest( """ @@ -519,7 +523,7 @@ public class HtmlFormatterTest extends XmlFormatterTestBase { settings.HTML_ENFORCE_QUOTES = enforce; } } - + public void testWeb18213() { doTextTest( """ diff --git a/xml/tests/testData/psi/formatter/html/unknownScriptFormatting.html b/xml/tests/testData/psi/formatter/html/unknownScriptFormatting.html new file mode 100644 index 000000000000..57c798d2ef5f --- /dev/null +++ b/xml/tests/testData/psi/formatter/html/unknownScriptFormatting.html @@ -0,0 +1,16 @@ + + +

+
+ +
+ diff --git a/xml/tests/testData/psi/formatter/html/unknownScriptFormatting_after.html b/xml/tests/testData/psi/formatter/html/unknownScriptFormatting_after.html new file mode 100644 index 000000000000..507159541aef --- /dev/null +++ b/xml/tests/testData/psi/formatter/html/unknownScriptFormatting_after.html @@ -0,0 +1,16 @@ + + +
+ div/div +
+
+ +
+ From c488cb995bfcc392290d2ab36fdca7b9e1da162f Mon Sep 17 00:00:00 2001 From: Piotr Tomiak Date: Fri, 30 Jun 2023 19:24:16 +0200 Subject: [PATCH 090/226] WEB-61656 Allow lexers to veto raw text embedment for component tags GitOrigin-RevId: 2cd9dd1dd65a4c9fcdf49b94e5aeddd1df8aac06 --- xml/xml-psi-impl/src/com/intellij/lexer/BaseHtmlLexer.java | 4 ++++ .../com/intellij/lexer/HtmlDefaultEmbeddedContentSupport.kt | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/xml/xml-psi-impl/src/com/intellij/lexer/BaseHtmlLexer.java b/xml/xml-psi-impl/src/com/intellij/lexer/BaseHtmlLexer.java index dbd451b3be54..9d41051704cc 100644 --- a/xml/xml-psi-impl/src/com/intellij/lexer/BaseHtmlLexer.java +++ b/xml/xml-psi-impl/src/com/intellij/lexer/BaseHtmlLexer.java @@ -214,6 +214,10 @@ public abstract class BaseHtmlLexer extends DelegateLexer implements Restartable return true; } + public boolean isPossiblyComponentTag(@NotNull CharSequence tagName) { + return false; + } + private static class HtmlLexerPosition implements LexerPosition { private final int myOffset; diff --git a/xml/xml-psi-impl/src/com/intellij/lexer/HtmlDefaultEmbeddedContentSupport.kt b/xml/xml-psi-impl/src/com/intellij/lexer/HtmlDefaultEmbeddedContentSupport.kt index 78bae922e1f1..2f8053e9e56a 100644 --- a/xml/xml-psi-impl/src/com/intellij/lexer/HtmlDefaultEmbeddedContentSupport.kt +++ b/xml/xml-psi-impl/src/com/intellij/lexer/HtmlDefaultEmbeddedContentSupport.kt @@ -20,8 +20,10 @@ class HtmlDefaultEmbeddedContentSupport : HtmlEmbeddedContentSupport { class HtmlRawTextTagContentProvider(lexer: BaseHtmlLexer) : HtmlTagEmbeddedContentProvider(lexer) { override fun isInterestedInTag(tagName: CharSequence): Boolean = - namesEqual(tagName, HtmlUtil.TITLE_TAG_NAME) - || namesEqual(tagName, HtmlUtil.TEXTAREA_TAG_NAME) + (namesEqual(tagName, HtmlUtil.TITLE_TAG_NAME) + || namesEqual(tagName, HtmlUtil.TEXTAREA_TAG_NAME)) + && !lexer.isPossiblyComponentTag(tagName) + override fun isInterestedInAttribute(attributeName: CharSequence): Boolean = false override fun createEmbedmentInfo(): HtmlEmbedmentInfo = HtmlEmbeddedContentProvider.RAW_TEXT_FORMATTABLE_EMBEDMENT From 109938cb8a0af385fa0b54cb0f3b05d952ba1333 Mon Sep 17 00:00:00 2001 From: Ivan Semenov Date: Fri, 30 Jun 2023 18:48:50 +0200 Subject: [PATCH 091/226] [github] update PR statistics collector add project where possible rename fields to snake case GitOrigin-RevId: b3691cb09d4cf31cab06ce8e351c7cfcf8452823 --- .../pullrequest/GHPRStatisticsCollector.kt | 73 ++++++++++--------- .../data/GHPRDataContextRepository.kt | 2 +- .../data/service/GHPRStateServiceImpl.kt | 8 +- .../GHPRDetailsActionsComponentFactory.kt | 20 ++--- .../ui/details/GHPRDetailsComponentFactory.kt | 8 +- .../GHPRStatusChecksComponentFactory.kt | 6 +- .../ui/details/action/GHPRCloseAction.kt | 5 +- .../details/action/GHPRCommitMergeAction.kt | 5 +- .../ui/details/action/GHPRPostReviewAction.kt | 5 +- .../action/GHPRReRequestReviewAction.kt | 7 +- .../details/action/GHPRRebaseMergeAction.kt | 5 +- .../action/GHPRRemoveReviewerAction.kt | 2 + .../ui/details/action/GHPRReopenAction.kt | 5 +- .../details/action/GHPRRequestReviewAction.kt | 5 +- .../action/GHPRSetMyselfAsReviewerAction.kt | 5 +- .../details/action/GHPRSquashMergeAction.kt | 5 +- .../ui/details/model/GHPRBranchesViewModel.kt | 4 +- .../ui/details/model/GHPRStatusViewModel.kt | 9 ++- .../model/impl/GHPRCommitsViewModel.kt | 8 +- .../ui/filters/GHPRSearchPanelViewModel.kt | 4 +- .../ui/list/GHPRListPanelFactory.kt | 2 +- .../ui/toolwindow/GHPRViewComponentFactory.kt | 7 +- ...MultiTabGHPRToolWindowContentController.kt | 2 +- ...PRToolWindowRepositoryContentController.kt | 6 +- 24 files changed, 122 insertions(+), 86 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRStatisticsCollector.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRStatisticsCollector.kt index 2510f45f8394..fe96eafdbd3e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRStatisticsCollector.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRStatisticsCollector.kt @@ -25,7 +25,7 @@ import org.jetbrains.plugins.github.util.GHEnterpriseServerMetadataLoader import java.util.* internal object GHPRStatisticsCollector { - private val COUNTERS_GROUP = EventLogGroup("vcs.github.pullrequest.counters", 4) + private val COUNTERS_GROUP = EventLogGroup("vcs.github.pullrequest.counters", 5) class Counters : CounterUsagesCollector() { override fun getGroup() = COUNTERS_GROUP @@ -34,12 +34,12 @@ internal object GHPRStatisticsCollector { private val SELECTORS_OPENED_EVENT = COUNTERS_GROUP.registerEvent("selectors.opened") private val LIST_OPENED_EVENT = COUNTERS_GROUP.registerEvent("list.opened") - private val FILTER_SEARCH_PRESENT = EventFields.Boolean("hasSearch") - private val FILTER_STATE_PRESENT = EventFields.Boolean("hasState") - private val FILTER_AUTHOR_PRESENT = EventFields.Boolean("hasAuthor") - private val FILTER_ASSIGNEE_PRESENT = EventFields.Boolean("hasAssignee") - private val FILTER_REVIEW_PRESENT = EventFields.Boolean("hasReviewState") - private val FILTER_LABEL_PRESENT = EventFields.Boolean("hasLabel") + private val FILTER_SEARCH_PRESENT = EventFields.Boolean("has_search") + private val FILTER_STATE_PRESENT = EventFields.Boolean("has_state") + private val FILTER_AUTHOR_PRESENT = EventFields.Boolean("has_author") + private val FILTER_ASSIGNEE_PRESENT = EventFields.Boolean("has_assignee") + private val FILTER_REVIEW_PRESENT = EventFields.Boolean("has_review_state") + private val FILTER_LABEL_PRESENT = EventFields.Boolean("has_label") private val FILTERS_APPLIED_EVENT = COUNTERS_GROUP.registerVarargEvent("list.filters.applied", FILTER_SEARCH_PRESENT, @@ -80,19 +80,20 @@ internal object GHPRStatisticsCollector { private val DETAILS_ACTION_EVENT = COUNTERS_GROUP.registerEvent("details.additional.actions.invoked", - EventFields.Enum("action", GHPRAction::class.java), - EventFields.Boolean("isDefault")) + EventFields.Enum("action"), + EventFields.Boolean("is_default")) - fun logSelectorsOpened() { - SELECTORS_OPENED_EVENT.log() + fun logSelectorsOpened(project: Project) { + SELECTORS_OPENED_EVENT.log(project) } - fun logListOpened() { - LIST_OPENED_EVENT.log() + fun logListOpened(project: Project) { + LIST_OPENED_EVENT.log(project) } - fun logListFiltersApplied(filters: GHPRListSearchValue): Unit = + fun logListFiltersApplied(project: Project, filters: GHPRListSearchValue): Unit = FILTERS_APPLIED_EVENT.log( + project, EventPair(FILTER_SEARCH_PRESENT, filters.searchQuery != null), EventPair(FILTER_STATE_PRESENT, filters.state != null), EventPair(FILTER_AUTHOR_PRESENT, filters.author != null), @@ -101,12 +102,12 @@ internal object GHPRStatisticsCollector { EventPair(FILTER_LABEL_PRESENT, filters.label != null) ) - fun logDetailsOpened() { - DETAILS_OPENED_EVENT.log() + fun logDetailsOpened(project: Project) { + DETAILS_OPENED_EVENT.log(project) } - fun logNewPRViewOpened() { - NEW_OPENED_EVENT.log() + fun logNewPRViewOpened(project: Project) { + NEW_OPENED_EVENT.log(project) } fun logTimelineOpened(project: Project) { @@ -122,40 +123,40 @@ internal object GHPRStatisticsCollector { DIFF_OPENED_EVENT.log(project, count) } - fun logDetailsBranchesOpened() { - DETAILS_BRANCHES_EVENT.log() + fun logDetailsBranchesOpened(project: Project) { + DETAILS_BRANCHES_EVENT.log(project) } - fun logDetailsBranchCheckedOut() { - DETAILS_BRANCH_CHECKED_OUT_EVENT.log() + fun logDetailsBranchCheckedOut(project: Project) { + DETAILS_BRANCH_CHECKED_OUT_EVENT.log(project) } - fun logDetailsCommitChosen() { - DETAILS_COMMIT_CHOSEN_EVENT.log() + fun logDetailsCommitChosen(project: Project) { + DETAILS_COMMIT_CHOSEN_EVENT.log(project) } - fun logDetailsNextCommitChosen() { - DETAILS_NEXT_COMMIT_EVENT.log() + fun logDetailsNextCommitChosen(project: Project) { + DETAILS_NEXT_COMMIT_EVENT.log(project) } - fun logDetailsPrevCommitChosen() { - DETAILS_PREV_COMMIT_EVENT.log() + fun logDetailsPrevCommitChosen(project: Project) { + DETAILS_PREV_COMMIT_EVENT.log(project) } - fun logDetailsChecksOpened() { - DETAILS_CHECKS_EVENT.log() + fun logDetailsChecksOpened(project: Project) { + DETAILS_CHECKS_EVENT.log(project) } - fun logDetailsActionInvoked(action: GHPRAction, isDefault: Boolean) { - DETAILS_ACTION_EVENT.log(action, isDefault) + fun logDetailsActionInvoked(project: Project, action: GHPRAction, isDefault: Boolean) { + DETAILS_ACTION_EVENT.log(project, action, isDefault) } - fun logChangeSelected() { - DETAILS_CHANGE_EVENT.log() + fun logChangeSelected(project: Project) { + DETAILS_CHANGE_EVENT.log(project) } - fun logMergedEvent(method: GithubPullRequestMergeMethod) { - MERGED_EVENT.log(method) + fun logMergedEvent(project: Project, method: GithubPullRequestMergeMethod) { + MERGED_EVENT.log(project, method) } fun logEnterpriseServerMeta(project: Project, server: GithubServerPath, meta: GHEnterpriseServerMeta) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRDataContextRepository.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRDataContextRepository.kt index 54fe3e7cc746..5c77def0a52e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRDataContextRepository.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRDataContextRepository.kt @@ -126,7 +126,7 @@ internal class GHPRDataContextRepository(private val project: Project) : Disposa account, currentUser, currentUserTeams, repositoryInfo) val detailsService = GHPRDetailsServiceImpl(ProgressManager.getInstance(), requestExecutor, apiRepositoryCoordinates) - val stateService = GHPRStateServiceImpl(ProgressManager.getInstance(), securityService, + val stateService = GHPRStateServiceImpl(ProgressManager.getInstance(), project, securityService, requestExecutor, account.server, apiRepositoryPath) val commentService = GHPRCommentServiceImpl(ProgressManager.getInstance(), requestExecutor, apiRepositoryCoordinates) val changesService = GHPRChangesServiceImpl(ProgressManager.getInstance(), project, requestExecutor, diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateServiceImpl.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateServiceImpl.kt index 27586940e825..e7d2a0627880 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateServiceImpl.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateServiceImpl.kt @@ -6,6 +6,7 @@ import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.project.Project import org.jetbrains.plugins.github.api.* import org.jetbrains.plugins.github.api.data.GHBranchProtectionRules import org.jetbrains.plugins.github.api.data.GHRepositoryPermissionLevel @@ -18,6 +19,7 @@ import org.jetbrains.plugins.github.pullrequest.data.service.GHServiceUtil.logEr import java.util.concurrent.CompletableFuture class GHPRStateServiceImpl internal constructor(private val progressManager: ProgressManager, + private val project: Project, private val securityService: GHPRSecurityService, private val requestExecutor: GithubApiRequestExecutor, private val serverPath: GithubServerPath, @@ -91,7 +93,7 @@ class GHPRStateServiceImpl internal constructor(private val progressManager: Pro requestExecutor.execute(it, GithubApiRequests.Repos.PullRequests.merge(serverPath, repoPath, pullRequestId.number, commitMessage.first, commitMessage.second, currentHeadRef)) - GHPRStatisticsCollector.logMergedEvent(GithubPullRequestMergeMethod.merge) + GHPRStatisticsCollector.logMergedEvent(project, GithubPullRequestMergeMethod.merge) return@submitIOTask }.logError(LOG, "Error occurred while merging PR ${pullRequestId.number}") @@ -102,7 +104,7 @@ class GHPRStateServiceImpl internal constructor(private val progressManager: Pro requestExecutor.execute(it, GithubApiRequests.Repos.PullRequests.rebaseMerge(serverPath, repoPath, pullRequestId.number, currentHeadRef)) - GHPRStatisticsCollector.logMergedEvent(GithubPullRequestMergeMethod.rebase) + GHPRStatisticsCollector.logMergedEvent(project, GithubPullRequestMergeMethod.rebase) return@submitIOTask }.logError(LOG, "Error occurred while rebasing PR ${pullRequestId.number}") @@ -113,7 +115,7 @@ class GHPRStateServiceImpl internal constructor(private val progressManager: Pro GithubApiRequests.Repos.PullRequests.squashMerge(serverPath, repoPath, pullRequestId.number, commitMessage.first, commitMessage.second, currentHeadRef)) - GHPRStatisticsCollector.logMergedEvent(GithubPullRequestMergeMethod.squash) + GHPRStatisticsCollector.logMergedEvent(project, GithubPullRequestMergeMethod.squash) return@submitIOTask }.logError(LOG, "Error occurred while squash-merging PR ${pullRequestId.number}") diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRDetailsActionsComponentFactory.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRDetailsActionsComponentFactory.kt index de98193cd6bc..bbec0f05caac 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRDetailsActionsComponentFactory.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRDetailsActionsComponentFactory.kt @@ -18,6 +18,7 @@ import com.intellij.openapi.actionSystem.DefaultActionGroup import com.intellij.openapi.actionSystem.Presentation import com.intellij.openapi.actionSystem.ex.CustomComponentAction import com.intellij.openapi.actionSystem.impl.SimpleDataContext +import com.intellij.openapi.project.Project import com.intellij.ui.components.JBOptionButton import com.intellij.ui.components.panels.Wrapper import kotlinx.coroutines.CoroutineScope @@ -39,20 +40,21 @@ internal object GHPRDetailsActionsComponentFactory { fun create( scope: CoroutineScope, + project: Project, reviewRequestState: Flow, reviewFlowVm: GHPRReviewFlowViewModel, dataProvider: GHPRDataProvider ): JComponent { val reviewActions = CodeReviewActions( - requestReviewAction = GHPRRequestReviewAction(scope, reviewFlowVm), - reRequestReviewAction = GHPRReRequestReviewAction(scope, reviewFlowVm), - closeReviewAction = GHPRCloseAction(scope, reviewFlowVm), - reopenReviewAction = GHPRReopenAction(scope, reviewFlowVm), - setMyselfAsReviewerAction = GHPRSetMyselfAsReviewerAction(scope, reviewFlowVm), - postReviewAction = GHPRPostReviewAction(scope, reviewFlowVm), - mergeReviewAction = GHPRCommitMergeAction(scope, reviewFlowVm), - mergeSquashReviewAction = GHPRSquashMergeAction(scope, reviewFlowVm), - rebaseReviewAction = GHPRRebaseMergeAction(scope, reviewFlowVm) + requestReviewAction = GHPRRequestReviewAction(scope, project, reviewFlowVm), + reRequestReviewAction = GHPRReRequestReviewAction(scope, project, reviewFlowVm), + closeReviewAction = GHPRCloseAction(scope, project, reviewFlowVm), + reopenReviewAction = GHPRReopenAction(scope, project, reviewFlowVm), + setMyselfAsReviewerAction = GHPRSetMyselfAsReviewerAction(scope, project, reviewFlowVm), + postReviewAction = GHPRPostReviewAction(scope, project, reviewFlowVm), + mergeReviewAction = GHPRCommitMergeAction(scope, project, reviewFlowVm), + mergeSquashReviewAction = GHPRSquashMergeAction(scope, project, reviewFlowVm), + rebaseReviewAction = GHPRRebaseMergeAction(scope, project, reviewFlowVm) ) val moreActionsGroup = DefaultActionGroup(GithubBundle.message("pull.request.merge.commit.action"), true) diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRDetailsComponentFactory.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRDetailsComponentFactory.kt index c3afd38239e3..1224c30c0098 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRDetailsComponentFactory.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRDetailsComponentFactory.kt @@ -12,6 +12,7 @@ import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionPlaces import com.intellij.openapi.actionSystem.ex.ActionUtil import com.intellij.openapi.actionSystem.impl.SimpleDataContext +import com.intellij.openapi.project.Project import com.intellij.ui.PopupHandler import kotlinx.coroutines.CoroutineScope import net.miginfocom.layout.AC @@ -35,6 +36,7 @@ internal object GHPRDetailsComponentFactory { fun create( scope: CoroutineScope, + project: Project, reviewDetailsVm: CodeReviewDetailsViewModel, branchesVm: CodeReviewBranchesViewModel, reviewStatusVm: GHPRStatusViewModel, @@ -57,8 +59,10 @@ internal object GHPRDetailsComponentFactory { .add(GHPRActionKeys.REVIEW_BRANCH_VM, branchesVm) .build())) } - val statusChecks = GHPRStatusChecksComponentFactory.create(scope, reviewStatusVm, reviewFlowVm, securityService, avatarIconsProvider) - val actionsComponent = GHPRDetailsActionsComponentFactory.create(scope, reviewDetailsVm.reviewRequestState, reviewFlowVm, dataProvider) + val statusChecks = GHPRStatusChecksComponentFactory.create(scope, project, reviewStatusVm, reviewFlowVm, securityService, + avatarIconsProvider) + val actionsComponent = GHPRDetailsActionsComponentFactory.create(scope, project, reviewDetailsVm.reviewRequestState, reviewFlowVm, + dataProvider) val actionGroup = ActionManager.getInstance().getAction("Github.PullRequest.Details.Popup") as ActionGroup return JPanel(MigLayout( diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRStatusChecksComponentFactory.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRStatusChecksComponentFactory.kt index 19739e20f8d3..134fd8bf87ad 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRStatusChecksComponentFactory.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/GHPRStatusChecksComponentFactory.kt @@ -8,6 +8,7 @@ import com.intellij.collaboration.ui.util.bindTextIn import com.intellij.collaboration.ui.util.toAnAction import com.intellij.icons.AllIcons import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.project.Project import com.intellij.ui.ScrollPaneFactory import com.intellij.ui.components.panels.Wrapper import com.intellij.util.childScope @@ -28,6 +29,7 @@ import javax.swing.JScrollPane internal object GHPRStatusChecksComponentFactory { fun create( parentScope: CoroutineScope, + project: Project, reviewStatusVm: GHPRStatusViewModel, reviewFlowVm: GHPRReviewFlowViewModel, securityService: GHPRSecurityService, @@ -48,7 +50,9 @@ internal object GHPRStatusChecksComponentFactory { add(CodeReviewDetailsStatusComponentFactory.createNeedReviewerComponent(scope, reviewFlowVm.reviewerReviews)) add(CodeReviewDetailsStatusComponentFactory.createReviewersReviewStateComponent( scope, reviewFlowVm.reviewerReviews, - reviewerActionProvider = { reviewer -> DefaultActionGroup(GHPRRemoveReviewerAction(scope, reviewFlowVm, reviewer).toAnAction()) }, + reviewerActionProvider = { reviewer -> + DefaultActionGroup(GHPRRemoveReviewerAction(scope, project, reviewFlowVm, reviewer).toAnAction()) + }, reviewerNameProvider = { reviewer -> reviewer.getPresentableName() }, avatarKeyProvider = { reviewer -> reviewer.avatarUrl }, iconProvider = { iconKey, iconSize -> avatarIconsProvider.getIcon(iconKey, iconSize) } diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRCloseAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRCloseAction.kt index 57641b20dea2..d496d0edc601 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRCloseAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRCloseAction.kt @@ -1,6 +1,7 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.github.pullrequest.ui.details.action +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.i18n.GithubBundle @@ -11,7 +12,7 @@ import java.awt.event.ActionEvent import javax.swing.AbstractAction import javax.swing.JButton -internal class GHPRCloseAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRCloseAction(scope: CoroutineScope, private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(GithubBundle.message("pull.request.close.action")) { init { @@ -23,7 +24,7 @@ internal class GHPRCloseAction(scope: CoroutineScope, private val reviewFlowVm: } override fun actionPerformed(e: ActionEvent?) { - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.CLOSE, e?.source is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.CLOSE, e?.source is JButton) reviewFlowVm.closeReview() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRCommitMergeAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRCommitMergeAction.kt index 6b3cb7ffb672..c19ede7b9fc1 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRCommitMergeAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRCommitMergeAction.kt @@ -3,6 +3,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.details.action import com.intellij.collaboration.async.combineAndCollect import com.intellij.collaboration.messages.CollaborationToolsBundle +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.pullrequest.GHPRAction @@ -12,7 +13,7 @@ import java.awt.event.ActionEvent import javax.swing.AbstractAction import javax.swing.JButton -internal class GHPRCommitMergeAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRCommitMergeAction(scope: CoroutineScope, private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(CollaborationToolsBundle.message("review.details.action.merge")) { init { @@ -24,7 +25,7 @@ internal class GHPRCommitMergeAction(scope: CoroutineScope, private val reviewFl } override fun actionPerformed(e: ActionEvent?) { - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.MERGE, e?.source is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.MERGE, e?.source is JButton) reviewFlowVm.mergeReview() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRPostReviewAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRPostReviewAction.kt index 2d2a350dade1..8c0c578cf535 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRPostReviewAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRPostReviewAction.kt @@ -1,6 +1,7 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.plugins.github.pullrequest.ui.details.action +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.i18n.GithubBundle @@ -11,7 +12,7 @@ import java.awt.event.ActionEvent import javax.swing.AbstractAction import javax.swing.JButton -internal class GHPRPostReviewAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRPostReviewAction(scope: CoroutineScope, private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(GithubBundle.message("pull.request.post.action")) { init { @@ -23,7 +24,7 @@ internal class GHPRPostReviewAction(scope: CoroutineScope, private val reviewFlo } override fun actionPerformed(e: ActionEvent?) { - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.POST_REVIEW, e?.source is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.POST_REVIEW, e?.source is JButton) reviewFlowVm.postDraftedReview() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRReRequestReviewAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRReRequestReviewAction.kt index 5831bf9a2cfc..58963e6f922d 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRReRequestReviewAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRReRequestReviewAction.kt @@ -2,6 +2,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.details.action import com.intellij.collaboration.messages.CollaborationToolsBundle +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.pullrequest.GHPRAction @@ -11,7 +12,9 @@ import java.awt.event.ActionEvent import javax.swing.AbstractAction import javax.swing.JButton -internal class GHPRReRequestReviewAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRReRequestReviewAction(scope: CoroutineScope, + private val project: Project, + private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(CollaborationToolsBundle.message("review.details.action.rerequest")) { init { @@ -23,7 +26,7 @@ internal class GHPRReRequestReviewAction(scope: CoroutineScope, private val revi } override fun actionPerformed(event: ActionEvent) { - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.RE_REQUEST_REVIEW, event.source is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.RE_REQUEST_REVIEW, event.source is JButton) reviewFlowVm.reRequestReview() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRebaseMergeAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRebaseMergeAction.kt index 9b208a9497b5..ad7474a3dd66 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRebaseMergeAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRebaseMergeAction.kt @@ -3,6 +3,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.details.action import com.intellij.collaboration.async.combineAndCollect import com.intellij.collaboration.messages.CollaborationToolsBundle +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.pullrequest.GHPRAction @@ -12,7 +13,7 @@ import java.awt.event.ActionEvent import javax.swing.AbstractAction import javax.swing.JButton -internal class GHPRRebaseMergeAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRRebaseMergeAction(scope: CoroutineScope, private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(CollaborationToolsBundle.message("review.details.action.rebase")) { init { @@ -24,7 +25,7 @@ internal class GHPRRebaseMergeAction(scope: CoroutineScope, private val reviewFl } override fun actionPerformed(e: ActionEvent?) { - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.REBASE_MERGE, e?.source is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.REBASE_MERGE, e?.source is JButton) reviewFlowVm.rebaseReview() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRemoveReviewerAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRemoveReviewerAction.kt index 9b546e891722..7ab34de6ceb1 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRemoveReviewerAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRemoveReviewerAction.kt @@ -2,6 +2,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.details.action import com.intellij.collaboration.messages.CollaborationToolsBundle +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.api.data.pullrequest.GHPullRequestRequestedReviewer @@ -11,6 +12,7 @@ import javax.swing.AbstractAction internal class GHPRRemoveReviewerAction( scope: CoroutineScope, + private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel, private val reviewer: GHPullRequestRequestedReviewer ) : AbstractAction(CollaborationToolsBundle.message("review.details.action.remove.reviewer", reviewer.name ?: reviewer.shortName)) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRReopenAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRReopenAction.kt index ad28482bc15b..ca54c4cb5745 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRReopenAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRReopenAction.kt @@ -1,6 +1,7 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.github.pullrequest.ui.details.action +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.i18n.GithubBundle @@ -11,7 +12,7 @@ import java.awt.event.ActionEvent import javax.swing.AbstractAction import javax.swing.JButton -internal class GHPRReopenAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRReopenAction(scope: CoroutineScope, private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(GithubBundle.message("pull.request.reopen.action")) { init { @@ -23,7 +24,7 @@ internal class GHPRReopenAction(scope: CoroutineScope, private val reviewFlowVm: } override fun actionPerformed(e: ActionEvent?) { - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.REOPEN, e?.source is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.REOPEN, e?.source is JButton) reviewFlowVm.reopenReview() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRequestReviewAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRequestReviewAction.kt index 080269242be2..67e7b4698272 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRequestReviewAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRRequestReviewAction.kt @@ -2,6 +2,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.details.action import com.intellij.collaboration.messages.CollaborationToolsBundle +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.pullrequest.GHPRAction @@ -12,7 +13,7 @@ import javax.swing.AbstractAction import javax.swing.JButton import javax.swing.JComponent -internal class GHPRRequestReviewAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRRequestReviewAction(scope: CoroutineScope, private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(CollaborationToolsBundle.message("review.details.action.request")) { init { @@ -25,7 +26,7 @@ internal class GHPRRequestReviewAction(scope: CoroutineScope, private val review override fun actionPerformed(event: ActionEvent) { val parentComponent = event.source as JComponent - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.REQUEST_REVIEW, parentComponent is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.REQUEST_REVIEW, parentComponent is JButton) return reviewFlowVm.requestReview(parentComponent) } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRSetMyselfAsReviewerAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRSetMyselfAsReviewerAction.kt index 262d5f4ebe01..97528cc7e2af 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRSetMyselfAsReviewerAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRSetMyselfAsReviewerAction.kt @@ -2,6 +2,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.details.action import com.intellij.collaboration.messages.CollaborationToolsBundle +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.pullrequest.GHPRAction @@ -11,7 +12,7 @@ import java.awt.event.ActionEvent import javax.swing.AbstractAction import javax.swing.JButton -internal class GHPRSetMyselfAsReviewerAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRSetMyselfAsReviewerAction(scope: CoroutineScope, private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(CollaborationToolsBundle.message("review.details.action.set.myself.as.reviewer")) { init { @@ -23,7 +24,7 @@ internal class GHPRSetMyselfAsReviewerAction(scope: CoroutineScope, private val } override fun actionPerformed(event: ActionEvent) { - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.REQUEST_REVIEW_MYSELF, event.source is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.REQUEST_REVIEW_MYSELF, event.source is JButton) reviewFlowVm.setMyselfAsReviewer() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRSquashMergeAction.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRSquashMergeAction.kt index 209eb0fd5843..aa3aa95cd85e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRSquashMergeAction.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/action/GHPRSquashMergeAction.kt @@ -3,6 +3,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.details.action import com.intellij.collaboration.async.combineAndCollect import com.intellij.collaboration.messages.CollaborationToolsBundle +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.jetbrains.plugins.github.pullrequest.GHPRAction @@ -12,7 +13,7 @@ import java.awt.event.ActionEvent import javax.swing.AbstractAction import javax.swing.JButton -internal class GHPRSquashMergeAction(scope: CoroutineScope, private val reviewFlowVm: GHPRReviewFlowViewModel) +internal class GHPRSquashMergeAction(scope: CoroutineScope, private val project: Project, private val reviewFlowVm: GHPRReviewFlowViewModel) : AbstractAction(CollaborationToolsBundle.message("review.details.action.squash.and.merge")) { init { @@ -24,7 +25,7 @@ internal class GHPRSquashMergeAction(scope: CoroutineScope, private val reviewFl } override fun actionPerformed(e: ActionEvent?) { - GHPRStatisticsCollector.logDetailsActionInvoked(GHPRAction.SQUASH_MERGE, e?.source is JButton) + GHPRStatisticsCollector.logDetailsActionInvoked(project, GHPRAction.SQUASH_MERGE, e?.source is JButton) reviewFlowVm.squashAndMergeReview() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/GHPRBranchesViewModel.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/GHPRBranchesViewModel.kt index 7bdb5a05e109..9b658428a28b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/GHPRBranchesViewModel.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/GHPRBranchesViewModel.kt @@ -103,7 +103,7 @@ internal class GHPRBranchesViewModel( val branch = "${headRemote.name}/${headBranch}" invokeLater { GitBranchPopupActions.RemoteBranchActions.CheckoutRemoteBranchAction.checkoutRemoteBranch(project, listOf(repository), branch) - GHPRStatisticsCollector.logDetailsBranchCheckedOut() + GHPRStatisticsCollector.logDetailsBranchCheckedOut(project) } } } @@ -162,7 +162,7 @@ internal class GHPRBranchesViewModel( val source = _sourceBranch.value val target = _targetBranch.value _showBranchesRequests.emit(CodeReviewBranches(source, target)) - GHPRStatisticsCollector.logDetailsBranchesOpened() + GHPRStatisticsCollector.logDetailsBranchesOpened(project) } } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/GHPRStatusViewModel.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/GHPRStatusViewModel.kt index 243c5d541e1a..6b6d2a524712 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/GHPRStatusViewModel.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/GHPRStatusViewModel.kt @@ -6,6 +6,7 @@ import com.intellij.collaboration.async.modelFlow import com.intellij.collaboration.ui.codereview.details.data.CodeReviewCIJob import com.intellij.collaboration.ui.codereview.details.model.CodeReviewStatusViewModel import com.intellij.openapi.diagnostic.thisLogger +import com.intellij.openapi.project.Project import com.intellij.util.childScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* @@ -21,7 +22,11 @@ interface GHPRStatusViewModel : CodeReviewStatusViewModel { val requiredApprovingReviewsCount: Flow } -class GHPRStatusViewModelImpl(parentCs: CoroutineScope, stateModel: GHPRStateModel) : GHPRStatusViewModel { +class GHPRStatusViewModelImpl( + parentCs: CoroutineScope, + private val project: Project, + stateModel: GHPRStateModel +) : GHPRStatusViewModel { private val cs = parentCs.childScope() override val viewerDidAuthor: Boolean = stateModel.viewerDidAuthor @@ -59,7 +64,7 @@ class GHPRStatusViewModelImpl(parentCs: CoroutineScope, stateModel: GHPRStateMod cs.launchNow { val jobs = ciJobs.first() _showJobsDetailsRequests.emit(jobs) - GHPRStatisticsCollector.logDetailsChecksOpened() + GHPRStatisticsCollector.logDetailsChecksOpened(project) } } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/impl/GHPRCommitsViewModel.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/impl/GHPRCommitsViewModel.kt index 1dafedad486f..8f4402562ac4 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/impl/GHPRCommitsViewModel.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/details/model/impl/GHPRCommitsViewModel.kt @@ -2,6 +2,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.details.model.impl import com.intellij.collaboration.ui.codereview.details.model.CodeReviewChangesViewModelBase +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -17,6 +18,7 @@ import org.jetbrains.plugins.github.pullrequest.ui.toolwindow.GHPRDiffController internal class GHPRCommitsViewModel( scope: CoroutineScope, + private val project: Project, commitsLoadingModel: GHSimpleLoadingModel>, securityService: GHPRSecurityService, private val diffBridge: GHPRDiffController @@ -39,16 +41,16 @@ internal class GHPRCommitsViewModel( diffBridge.activeTree = GHPRDiffController.ActiveTree.FILES } super.selectCommit(index) - GHPRStatisticsCollector.logDetailsCommitChosen() + GHPRStatisticsCollector.logDetailsCommitChosen(project) } override fun selectNextCommit() { super.selectNextCommit() - GHPRStatisticsCollector.logDetailsNextCommitChosen() + GHPRStatisticsCollector.logDetailsNextCommitChosen(project) } override fun selectPreviousCommit() { super.selectPreviousCommit() - GHPRStatisticsCollector.logDetailsPrevCommitChosen() + GHPRStatisticsCollector.logDetailsPrevCommitChosen(project) } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/filters/GHPRSearchPanelViewModel.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/filters/GHPRSearchPanelViewModel.kt index 313a8a33798b..9a3b3917939c 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/filters/GHPRSearchPanelViewModel.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/filters/GHPRSearchPanelViewModel.kt @@ -4,6 +4,7 @@ package org.jetbrains.plugins.github.pullrequest.ui.filters import com.intellij.collaboration.async.launchNow import com.intellij.collaboration.ui.codereview.list.search.ReviewListQuickFilter import com.intellij.collaboration.ui.codereview.list.search.ReviewListSearchPanelViewModelBase +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce @@ -18,6 +19,7 @@ import org.jetbrains.plugins.github.pullrequest.ui.filters.GHPRListQuickFilter.* @OptIn(FlowPreview::class) internal class GHPRSearchPanelViewModel( scope: CoroutineScope, + private val project: Project, private val repositoryDataService: GHPRRepositoryDataService, historyViewModel: GHPRSearchHistoryModel, currentUser: GHUser @@ -62,7 +64,7 @@ internal class GHPRSearchPanelViewModel( scope.launchNow { // with debounce to avoid collecting intermediate state searchState.drop(1).debounce(5000).collect { - GHPRStatisticsCollector.logListFiltersApplied(it) + GHPRStatisticsCollector.logListFiltersApplied(project, it) } } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/list/GHPRListPanelFactory.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/list/GHPRListPanelFactory.kt index 5c81be284a89..2064e7da3c33 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/list/GHPRListPanelFactory.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/list/GHPRListPanelFactory.kt @@ -57,7 +57,7 @@ internal class GHPRListPanelFactory(private val project: Project, val actionManager = ActionManager.getInstance() val historyModel = GHPRSearchHistoryModel(project.service()) - val searchVm = GHPRSearchPanelViewModel(scope, repositoryDataService, historyModel, securityService.currentUser) + val searchVm = GHPRSearchPanelViewModel(scope, project, repositoryDataService, historyModel, securityService.currentUser) scope.launch { searchVm.searchState.collectLatest { listLoader.searchQuery = it.toQuery() diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/GHPRViewComponentFactory.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/GHPRViewComponentFactory.kt index bb8f17bf1204..db71fe9782b7 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/GHPRViewComponentFactory.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/GHPRViewComponentFactory.kt @@ -182,7 +182,7 @@ internal class GHPRViewComponentFactory(private val actionManager: ActionManager val scope = DisposingScope(disposable, SupervisorJob() + Dispatchers.Main.immediate) val reviewDetailsVm = GHPRDetailsViewModelImpl(detailsModel, stateModel) val reviewBranchesVm = GHPRBranchesViewModel(scope, project, branchesModel, dataProvider.detailsData) - val reviewStatusVm = GHPRStatusViewModelImpl(scope, stateModel) + val reviewStatusVm = GHPRStatusViewModelImpl(scope, project, stateModel) val reviewFlowVm = GHPRReviewFlowViewModelImpl(scope, metadataModel, stateModel, @@ -191,9 +191,10 @@ internal class GHPRViewComponentFactory(private val actionManager: ActionManager dataProvider.detailsData, dataProvider.reviewData, disposable) - val commitsVm = GHPRCommitsViewModel(scope, commitsLoadingModel, dataContext.securityService, diffBridge) + val commitsVm = GHPRCommitsViewModel(scope, project, commitsLoadingModel, dataContext.securityService, diffBridge) GHPRDetailsComponentFactory.create(scope, + project, reviewDetailsVm, reviewBranchesVm, reviewStatusVm, reviewFlowVm, commitsVm, dataProvider, dataContext.securityService, dataContext.avatarIconsProvider, @@ -275,7 +276,7 @@ internal class GHPRViewComponentFactory(private val actionManager: ActionManager tree.addSelectionListener { if (tree.isFocusOwner) { - GHPRStatisticsCollector.logChangeSelected() + GHPRStatisticsCollector.logChangeSelected(project) } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/MultiTabGHPRToolWindowContentController.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/MultiTabGHPRToolWindowContentController.kt index fbdfa60b258a..c56ee3ec73a2 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/MultiTabGHPRToolWindowContentController.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/MultiTabGHPRToolWindowContentController.kt @@ -69,7 +69,7 @@ internal class MultiTabGHPRToolWindowContentController(parentDisposable: Disposa _contentController = CompletableFuture() } showSelectorsTab(requestFocus) - GHPRStatisticsCollector.logSelectorsOpened() + GHPRStatisticsCollector.logSelectorsOpened(project) } else { val controller = showRepositoryContent(conn, requestFocus) diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/MultiTabGHPRToolWindowRepositoryContentController.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/MultiTabGHPRToolWindowRepositoryContentController.kt index 6e325fcf2503..9befeccac331 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/MultiTabGHPRToolWindowRepositoryContentController.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/ui/toolwindow/MultiTabGHPRToolWindowRepositoryContentController.kt @@ -56,7 +56,7 @@ internal class MultiTabGHPRToolWindowRepositoryContentController( it.type == TabType.New } ?: createAndAddNewPRContent() contentManager.setSelectedContent(content, requestFocus) - GHPRStatisticsCollector.logNewPRViewOpened() + GHPRStatisticsCollector.logNewPRViewOpened(project) } private fun createAndAddNewPRContent(): Content { @@ -90,7 +90,7 @@ internal class MultiTabGHPRToolWindowRepositoryContentController( it.type == TabType.List } ?: createAndAddListContent() contentManager.setSelectedContent(content, requestFocus) - GHPRStatisticsCollector.logListOpened() + GHPRStatisticsCollector.logListOpened(project) } private fun createAndAddListContent(): Content { @@ -143,7 +143,7 @@ internal class MultiTabGHPRToolWindowRepositoryContentController( (it.type as? TabType.PR)?.id == id } ?: createAndAddPRContent(id) contentManager.setSelectedContent(content, requestFocus) - GHPRStatisticsCollector.logDetailsOpened() + GHPRStatisticsCollector.logDetailsOpened(project) return UIUtil.findComponentOfType(content.component, ChangesTree::class.java)?.let { ClientProperty.get(it, GHPRCommitBrowserComponentController.KEY) From 208a3d0341fab41fc2fd6d1f99a08b96a42ce229 Mon Sep 17 00:00:00 2001 From: Ivan Semenov Date: Fri, 30 Jun 2023 18:50:05 +0200 Subject: [PATCH 092/226] [github] use provided scope instead of a disposable one GitOrigin-RevId: 17973de488a9b2b772698980678938779b865b96 --- .../github/pullrequest/GHPRStatisticsCollector.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRStatisticsCollector.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRStatisticsCollector.kt index fe96eafdbd3e..68ea0ec41707 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRStatisticsCollector.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRStatisticsCollector.kt @@ -1,19 +1,19 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.plugins.github.pullrequest -import com.intellij.collaboration.async.disposingScope import com.intellij.internal.statistic.eventLog.EventLogGroup import com.intellij.internal.statistic.eventLog.FeatureUsageData import com.intellij.internal.statistic.eventLog.events.EventFields import com.intellij.internal.statistic.eventLog.events.EventPair import com.intellij.internal.statistic.eventLog.events.PrimitiveEventField import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector -import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.startup.ProjectActivity +import com.intellij.util.childScope +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.future.await import kotlinx.coroutines.launch import org.jetbrains.plugins.github.api.GithubServerPath @@ -176,10 +176,13 @@ enum class GHPRAction { REBASE_MERGE } -@Service -private class GHServerVersionsCollector(private val project: Project) : Disposable { +@Service(Service.Level.PROJECT) +private class GHServerVersionsCollector( + private val project: Project, + parentCs: CoroutineScope +) { - private val scope = disposingScope() + private val scope = parentCs.childScope() init { val accountsFlow = project.service().accountsState @@ -207,6 +210,4 @@ private class GHServerVersionsCollector(private val project: Project) : Disposab project.service() } } - - override fun dispose() = Unit } From 496959a3bf642b086c156c324c8c84d87a558899 Mon Sep 17 00:00:00 2001 From: Ivan Semenov Date: Fri, 30 Jun 2023 19:49:29 +0200 Subject: [PATCH 093/226] [gitlab] update statistics collector add project where possible rename fields to snake case GitOrigin-RevId: 5d3bd2a4110f33400c463d3ce81f9987a1231938 --- .../mergerequest/data/GitLabDiscussion.kt | 14 ++++---- .../mergerequest/data/GitLabMergeRequest.kt | 21 +++++------ .../GitLabMergeRequestDiscussionsContainer.kt | 34 ++++++++++-------- .../gitlab/mergerequest/data/GitLabNote.kt | 12 ++++--- .../diff/GitLabMergeRequestDiffExtension.kt | 2 +- .../GitLabMergeRequestsFiltersViewModel.kt | 4 ++- .../GitLabReviewListTabComponentDescriptor.kt | 1 + .../GitLabReviewTabComponentFactory.kt | 6 ++-- .../plugins/gitlab/util/gitLabStatistics.kt | 36 ++++++++++--------- ...abMergeRequestsFiltersViewModelImplTest.kt | 18 ++++++---- 10 files changed, 84 insertions(+), 64 deletions(-) diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabDiscussion.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabDiscussion.kt index b4107379db88..8ff40c103869 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabDiscussion.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabDiscussion.kt @@ -4,6 +4,7 @@ package org.jetbrains.plugins.gitlab.mergerequest.data import com.intellij.collaboration.async.mapCaching import com.intellij.collaboration.async.modelFlow import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.project.Project import com.intellij.util.childScope import kotlinx.coroutines.* import kotlinx.coroutines.flow.* @@ -47,8 +48,9 @@ private val LOG = logger() @OptIn(ExperimentalCoroutinesApi::class) class LoadedGitLabDiscussion( parentCs: CoroutineScope, + private val project: Project, private val api: GitLabApi, - private val project: GitLabProjectCoordinates, + private val glProject: GitLabProjectCoordinates, private val eventSink: suspend (GitLabDiscussionEvent) -> Unit, private val mr: GitLabMergeRequest, discussionData: GitLabDiscussionDTO, @@ -101,7 +103,7 @@ class LoadedGitLabDiscussion( loadedNotes .mapCaching( GitLabNoteDTO::id, - { note -> MutableGitLabMergeRequestNote(this, api, project, mr, noteEvents::emit, note) }, + { note -> MutableGitLabMergeRequestNote(this, project, api, glProject, mr, noteEvents::emit, note) }, MutableGitLabMergeRequestNote::destroy, MutableGitLabMergeRequestNote::update ).combine(draftNotes) { notes, draftNotes -> @@ -123,25 +125,25 @@ class LoadedGitLabDiscussion( operationsGuard.withLock { val resolved = resolved.first() val result = withContext(Dispatchers.IO) { - api.graphQL.changeMergeRequestDiscussionResolve(project, apiId, !resolved).getResultOrThrow() + api.graphQL.changeMergeRequestDiscussionResolve(glProject, apiId, !resolved).getResultOrThrow() } noteEvents.emit(GitLabNoteEvent.Changed(result.notes)) } } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.CHANGE_DISCUSSION_RESOLVE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.CHANGE_DISCUSSION_RESOLVE) } override suspend fun addNote(body: String) { withContext(cs.coroutineContext) { withContext(Dispatchers.IO) { - api.graphQL.createReplyNote(project, mr.gid, id, body).getResultOrThrow() + api.graphQL.createReplyNote(glProject, mr.gid, id, body).getResultOrThrow() }.also { withContext(NonCancellable) { noteEvents.emit(GitLabNoteEvent.Added(it)) } } } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.ADD_DISCUSSION_NOTE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.ADD_DISCUSSION_NOTE) } fun update(data: GitLabDiscussionDTO) { diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt index db85d14ac04b..20db2f829a4d 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt @@ -218,7 +218,7 @@ internal class LoadedGitLabMergeRequest( mergeRequestDetailsState.value = GitLabMergeRequestFullDetails.fromGraphQL(updatedMergeRequest) } discussionsContainer.checkUpdates() - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.MERGE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.MERGE) } override suspend fun squashAndMerge(commitMessage: String) { @@ -232,7 +232,7 @@ internal class LoadedGitLabMergeRequest( mergeRequestDetailsState.value = GitLabMergeRequestFullDetails.fromGraphQL(updatedMergeRequest) } discussionsContainer.checkUpdates() - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.SQUASH_MERGE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.SQUASH_MERGE) } override suspend fun rebase() { @@ -246,7 +246,7 @@ internal class LoadedGitLabMergeRequest( while (updatedMergeRequest.rebaseInProgress) } discussionsContainer.checkUpdates() - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.REBASE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.REBASE) } override suspend fun approve() { @@ -264,7 +264,7 @@ internal class LoadedGitLabMergeRequest( } } discussionsContainer.checkUpdates() - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.APPROVE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.APPROVE) } override suspend fun unApprove() { @@ -282,7 +282,7 @@ internal class LoadedGitLabMergeRequest( } } discussionsContainer.checkUpdates() - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.UNAPPROVE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.UNAPPROVE) } override suspend fun close() { @@ -292,7 +292,7 @@ internal class LoadedGitLabMergeRequest( mergeRequestDetailsState.value = GitLabMergeRequestFullDetails.fromGraphQL(updatedMergeRequest) stateEventsLoader.checkForUpdates() } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.CLOSE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.CLOSE) } override suspend fun reopen() { @@ -302,7 +302,7 @@ internal class LoadedGitLabMergeRequest( mergeRequestDetailsState.value = GitLabMergeRequestFullDetails.fromGraphQL(updatedMergeRequest) stateEventsLoader.checkForUpdates() } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.REOPEN) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.REOPEN) } override suspend fun postReview() { @@ -312,7 +312,7 @@ internal class LoadedGitLabMergeRequest( mergeRequestDetailsState.value = GitLabMergeRequestFullDetails.fromGraphQL(updatedMergeRequest) } discussionsContainer.checkUpdates() - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.POST_REVIEW) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.POST_REVIEW) } override suspend fun setReviewers(reviewers: List) { @@ -322,10 +322,11 @@ internal class LoadedGitLabMergeRequest( mergeRequestDetailsState.value = GitLabMergeRequestFullDetails.fromGraphQL(updatedMergeRequest) } discussionsContainer.checkUpdates() - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.SET_REVIEWERS) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.SET_REVIEWERS) } - private val discussionsContainer = GitLabMergeRequestDiscussionsContainerImpl(parentCs, api, projectMapping.repository, this) + private val discussionsContainer = + GitLabMergeRequestDiscussionsContainerImpl(parentCs, project, api, projectMapping.repository, this) override val discussions: Flow> = discussionsContainer.discussions override val systemNotes: Flow> = discussionsContainer.systemNotes diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDiscussionsContainer.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDiscussionsContainer.kt index 73bb552209d8..551e38db869f 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDiscussionsContainer.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDiscussionsContainer.kt @@ -8,6 +8,7 @@ import com.intellij.collaboration.async.mapCaching import com.intellij.collaboration.async.mapFiltered import com.intellij.collaboration.async.modelFlow import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.project.Project import com.intellij.util.childScope import kotlinx.coroutines.* import kotlinx.coroutines.channels.BufferOverflow @@ -48,8 +49,9 @@ private val LOG = logger() @OptIn(ExperimentalCoroutinesApi::class) class GitLabMergeRequestDiscussionsContainerImpl( parentCs: CoroutineScope, + private val project: Project, private val api: GitLabApi, - private val project: GitLabProjectCoordinates, + private val glProject: GitLabProjectCoordinates, private val mr: GitLabMergeRequest ) : GitLabMergeRequestDiscussionsContainer { @@ -72,7 +74,7 @@ class GitLabMergeRequestDiscussionsContainerImpl( val discussionsGuard = Mutex() var lastCursor: String? = null ApiPageUtil.createGQLPagesFlow { - api.graphQL.loadMergeRequestDiscussions(project, mr.id, it) + api.graphQL.loadMergeRequestDiscussions(glProject, mr.id, it) }.collect { page -> discussionsGuard.withLock { for (dto in page.nodes.filter { it.notes.isNotEmpty() }) { @@ -84,7 +86,7 @@ class GitLabMergeRequestDiscussionsContainerImpl( if (lastCursor != null) { launchNow { updateRequests.collect { - val page = api.graphQL.loadMergeRequestDiscussions(project, mr.id, GraphQLRequestPagination(lastCursor!!)) + val page = api.graphQL.loadMergeRequestDiscussions(glProject, mr.id, GraphQLRequestPagination(lastCursor!!)) val newDiscussions = page?.nodes if (newDiscussions != null) { discussionsGuard.withLock { @@ -129,7 +131,9 @@ class GitLabMergeRequestDiscussionsContainerImpl( .mapFiltered { !it.notes.first().system } .mapCaching( GitLabDiscussionDTO::id, - { disc -> LoadedGitLabDiscussion(this, api, project, { discussionEvents.emit(it) }, mr, disc, getDiscussionDraftNotes(disc.id)) }, + { disc -> + LoadedGitLabDiscussion(this, project, api, glProject, { discussionEvents.emit(it) }, mr, disc, getDiscussionDraftNotes(disc.id)) + }, LoadedGitLabDiscussion::destroy, LoadedGitLabDiscussion::update ) @@ -153,16 +157,16 @@ class GitLabMergeRequestDiscussionsContainerImpl( private suspend fun FlowCollector>.collectDraftNotes() { supervisorScope { // we shouldn't get another user's draft notes - val currentUser = api.graphQL.getCurrentUser(project.serverPath) ?: error("Unable to load current user") + val currentUser = api.graphQL.getCurrentUser(glProject.serverPath) ?: error("Unable to load current user") val notesGuard = Mutex() val draftNotes = LinkedHashMap() var lastETag: String? = null - val uri = getMergeRequestDraftNotesUri(project, mr.id) + val uri = getMergeRequestDraftNotesUri(glProject, mr.id) ApiPageUtil.createPagesFlowByLinkHeader(uri) { api.rest.loadUpdatableJsonList( - project.serverPath, GitLabApiRequestName.REST_GET_DRAFT_NOTES, it + glProject.serverPath, GitLabApiRequestName.REST_GET_DRAFT_NOTES, it ) }.collect { val newNotes = it.body() ?: error("Empty response") @@ -178,7 +182,7 @@ class GitLabMergeRequestDiscussionsContainerImpl( launchNow { updateRequests.collect { val response = api.rest.loadUpdatableJsonList( - project.serverPath, GitLabApiRequestName.REST_GET_DRAFT_NOTES, uri, lastETag + glProject.serverPath, GitLabApiRequestName.REST_GET_DRAFT_NOTES, uri, lastETag ) val newNotes = response.body() if (newNotes != null) { @@ -218,7 +222,7 @@ class GitLabMergeRequestDiscussionsContainerImpl( override val draftNotes: Flow> = draftNotesData.mapCaching( { it.note.id }, - { (note, author) -> GitLabMergeRequestDraftNoteImpl(this, api, project, mr, draftNotesEvents::emit, note, author) }, + { (note, author) -> GitLabMergeRequestDraftNoteImpl(this, api, glProject, mr, draftNotesEvents::emit, note, author) }, GitLabMergeRequestDraftNoteImpl::destroy, { update(it.note) } ).modelFlow(cs, LOG) @@ -234,40 +238,40 @@ class GitLabMergeRequestDiscussionsContainerImpl( override suspend fun addNote(body: String) { withContext(cs.coroutineContext) { withContext(Dispatchers.IO) { - api.graphQL.addNote(project, mr.gid, body).getResultOrThrow() + api.graphQL.addNote(glProject, mr.gid, body).getResultOrThrow() }.also { withContext(NonCancellable) { discussionEvents.emit(GitLabDiscussionEvent.Added(it)) } } } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.ADD_NOTE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.ADD_NOTE) } override suspend fun addNote(position: GitLabDiffPositionInput, body: String) { withContext(cs.coroutineContext) { withContext(Dispatchers.IO) { - api.graphQL.addDiffNote(project, mr.gid, position, body).getResultOrThrow() + api.graphQL.addDiffNote(glProject, mr.gid, position, body).getResultOrThrow() }.also { withContext(NonCancellable) { discussionEvents.emit(GitLabDiscussionEvent.Added(it)) } } } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.ADD_DIFF_NOTE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.ADD_DIFF_NOTE) } override suspend fun submitDraftNotes() { withContext(cs.coroutineContext) { withContext(Dispatchers.IO) { - api.rest.submitDraftNotes(project, mr.id) + api.rest.submitDraftNotes(glProject, mr.id) } withContext(NonCancellable) { draftNotesEvents.emit(GitLabNoteEvent.AllDeleted()) reloadRequests.emit(Unit) } } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.SUBMIT_DRAFT_NOTES) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.SUBMIT_DRAFT_NOTES) } fun requestReload() { diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabNote.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabNote.kt index 344c97924287..5a5d00e02fb8 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabNote.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabNote.kt @@ -4,6 +4,7 @@ package org.jetbrains.plugins.gitlab.mergerequest.data import com.intellij.collaboration.async.mapState import com.intellij.collaboration.async.modelFlow import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.project.Project import com.intellij.util.childScope import kotlinx.coroutines.* import kotlinx.coroutines.flow.* @@ -54,8 +55,9 @@ private val LOG = logger() class MutableGitLabMergeRequestNote( parentCs: CoroutineScope, + private val project: Project, private val api: GitLabApi, - private val project: GitLabProjectCoordinates, + private val glProject: GitLabProjectCoordinates, mr: GitLabMergeRequest, private val eventSink: suspend (GitLabNoteEvent) -> Unit, private val noteData: GitLabNoteDTO @@ -82,24 +84,24 @@ class MutableGitLabMergeRequestNote( withContext(cs.coroutineContext) { operationsGuard.withLock { withContext(Dispatchers.IO) { - api.graphQL.updateNote(project, noteData.id, newText).getResultOrThrow() + api.graphQL.updateNote(glProject, noteData.id, newText).getResultOrThrow() } } data.update { it.copy(body = newText) } } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.UPDATE_NOTE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.UPDATE_NOTE) } override suspend fun delete() { withContext(cs.coroutineContext) { operationsGuard.withLock { withContext(Dispatchers.IO) { - api.graphQL.deleteNote(project, noteData.id).getResultOrThrow() + api.graphQL.deleteNote(glProject, noteData.id).getResultOrThrow() } } eventSink(GitLabNoteEvent.Deleted(noteData.id)) } - GitLabStatistics.logMrActionExecuted(GitLabStatistics.MergeRequestAction.DELETE_NOTE) + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.DELETE_NOTE) } fun update(item: GitLabNoteDTO) { diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/diff/GitLabMergeRequestDiffExtension.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/diff/GitLabMergeRequestDiffExtension.kt index 514f363667eb..46ef60b781c0 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/diff/GitLabMergeRequestDiffExtension.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/diff/GitLabMergeRequestDiffExtension.kt @@ -61,7 +61,7 @@ class GitLabMergeRequestDiffExtension : DiffExtension() { cs.launch { val isCumulative = changeVmFlow.first().isCumulativeChange - GitLabStatistics.logMrDiffOpened(isCumulative) + GitLabStatistics.logMrDiffOpened(project, isCumulative) } val discussions = changeVmFlow.flatMapLatest { it.discussions } diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/filters/GitLabMergeRequestsFiltersViewModel.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/filters/GitLabMergeRequestsFiltersViewModel.kt index bb3ecf850292..f90613f9f682 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/filters/GitLabMergeRequestsFiltersViewModel.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/filters/GitLabMergeRequestsFiltersViewModel.kt @@ -5,6 +5,7 @@ import com.intellij.collaboration.async.launchNow import com.intellij.collaboration.ui.codereview.list.search.ReviewListSearchPanelViewModel import com.intellij.collaboration.ui.codereview.list.search.ReviewListSearchPanelViewModelBase import com.intellij.collaboration.ui.icon.IconsProvider +import com.intellij.openapi.project.Project import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.MutableStateFlow @@ -37,6 +38,7 @@ internal interface GitLabMergeRequestsFiltersViewModel : ReviewListSearchPanelVi @OptIn(FlowPreview::class) internal class GitLabMergeRequestsFiltersViewModelImpl( scope: CoroutineScope, + private val project: Project?, // only for statistics historyModel: GitLabMergeRequestsFiltersHistoryModel, override val currentUser: GitLabUserDTO, override val avatarIconsProvider: IconsProvider, @@ -85,7 +87,7 @@ internal class GitLabMergeRequestsFiltersViewModelImpl( // with debounce to avoid collecting intermediate state searchState.drop(1).debounce(5000).collect { if (it.filterCount > 0) { - GitLabStatistics.logMrFiltersApplied(it) + GitLabStatistics.logMrFiltersApplied(project, it) } } } diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/toolwindow/GitLabReviewListTabComponentDescriptor.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/toolwindow/GitLabReviewListTabComponentDescriptor.kt index 613a65d58239..3f1d98e230ef 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/toolwindow/GitLabReviewListTabComponentDescriptor.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/toolwindow/GitLabReviewListTabComponentDescriptor.kt @@ -38,6 +38,7 @@ internal class GitLabReviewListTabComponentDescriptor( private val accountVm = GitLabAccountViewModelImpl(project, cs, ctx.account, accountManager) private val filterVm: GitLabMergeRequestsFiltersViewModel = GitLabMergeRequestsFiltersViewModelImpl( cs, + project, currentUser = ctx.currentUser, historyModel = GitLabMergeRequestsFiltersHistoryModel(project.service()), avatarIconsProvider = avatarIconsProvider, diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/toolwindow/GitLabReviewTabComponentFactory.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/toolwindow/GitLabReviewTabComponentFactory.kt index 50dd2b9323ed..0b271bd17b19 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/toolwindow/GitLabReviewTabComponentFactory.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/toolwindow/GitLabReviewTabComponentFactory.kt @@ -49,7 +49,7 @@ internal class GitLabReviewTabComponentFactory( cs: CoroutineScope, projectContext: GitLabProjectUIContext ): ReviewListTabComponentDescriptor { - GitLabStatistics.logMrListOpened() + GitLabStatistics.logMrListOpened(project) return GitLabReviewListTabComponentDescriptor(project, cs, toolwindowViewModel.accountManager, projectContext) } @@ -58,14 +58,14 @@ internal class GitLabReviewTabComponentFactory( reviewTabType: GitLabReviewTab): JComponent { return when (reviewTabType) { is GitLabReviewTab.ReviewSelected -> { - GitLabStatistics.logMrDetailsOpened() + GitLabStatistics.logMrDetailsOpened(project) createReviewDetailsComponent(cs, projectContext, reviewTabType.reviewId) } } } override fun createEmptyTabContent(cs: CoroutineScope): JComponent { - GitLabStatistics.logMrTwLoginOpened() + GitLabStatistics.logMrTwLoginOpened(project) return createSelectorsComponent(cs) } diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/util/gitLabStatistics.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/util/gitLabStatistics.kt index 001078e5e8a9..637712be53f9 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/util/gitLabStatistics.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/util/gitLabStatistics.kt @@ -9,6 +9,7 @@ import com.intellij.internal.statistic.eventLog.events.EventPair import com.intellij.internal.statistic.service.fus.collectors.ApplicationUsagesCollector import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project import org.jetbrains.plugins.gitlab.api.GitLabGQLQuery import org.jetbrains.plugins.gitlab.authentication.accounts.GitLabAccountManager import org.jetbrains.plugins.gitlab.mergerequest.ui.filters.GitLabMergeRequestsFiltersValue @@ -34,14 +35,14 @@ internal object GitLabStatistics { //endregion //region Counters - private val COUNTERS_GROUP = EventLogGroup("vcs.gitlab.counters", version = 4) + private val COUNTERS_GROUP = EventLogGroup("vcs.gitlab.counters", version = 5) /** * Server returned 5** error */ private val SERVER_ERROR_EVENT = COUNTERS_GROUP.registerEvent("api.server.error.occurred", - EventFields.Enum("requestName", GitLabApiRequestName::class.java), - EventFields.Boolean("isDefaultServer"), + EventFields.Enum("request_name", GitLabApiRequestName::class.java), + EventFields.Boolean("is_default_server"), EventFields.Version) fun logServerError(request: GitLabApiRequestName, isDefaultServer: Boolean, serverVersion: String?): Unit = @@ -73,12 +74,12 @@ internal object GitLabStatistics { override fun getGroup(): EventLogGroup = COUNTERS_GROUP } - private val FILTER_SEARCH_PRESENT = EventFields.Boolean("hasSearch") - private val FILTER_STATE_PRESENT = EventFields.Boolean("hasState") - private val FILTER_AUTHOR_PRESENT = EventFields.Boolean("hasAuthor") - private val FILTER_ASSIGNEE_PRESENT = EventFields.Boolean("hasAssignee") - private val FILTER_REVIEWER_PRESENT = EventFields.Boolean("hasReviewer") - private val FILTER_LABEL_PRESENT = EventFields.Boolean("hasLabel") + private val FILTER_SEARCH_PRESENT = EventFields.Boolean("has_search") + private val FILTER_STATE_PRESENT = EventFields.Boolean("has_state") + private val FILTER_AUTHOR_PRESENT = EventFields.Boolean("has_author") + private val FILTER_ASSIGNEE_PRESENT = EventFields.Boolean("has_assignee") + private val FILTER_REVIEWER_PRESENT = EventFields.Boolean("has_reviewer") + private val FILTER_LABEL_PRESENT = EventFields.Boolean("has_label") /** * Merge requests list filters applied @@ -91,8 +92,9 @@ internal object GitLabStatistics { FILTER_REVIEWER_PRESENT, FILTER_LABEL_PRESENT) - fun logMrFiltersApplied(filters: GitLabMergeRequestsFiltersValue): Unit = + fun logMrFiltersApplied(project: Project?, filters: GitLabMergeRequestsFiltersValue): Unit = FILTERS_APPLIED_EVENT.log( + project, EventPair(FILTER_SEARCH_PRESENT, filters.searchQuery != null), EventPair(FILTER_STATE_PRESENT, filters.state != null), EventPair(FILTER_AUTHOR_PRESENT, filters.author != null), @@ -107,33 +109,33 @@ internal object GitLabStatistics { */ private val MR_TW_LOGIN_OPENED_EVENT = COUNTERS_GROUP.registerEvent("mergerequests.toolwindow.login.opened") - fun logMrTwLoginOpened(): Unit = MR_TW_LOGIN_OPENED_EVENT.log() + fun logMrTwLoginOpened(project: Project): Unit = MR_TW_LOGIN_OPENED_EVENT.log(project) /** * Merge requests toolwindow was opened */ private val MR_LIST_OPENED_EVENT = COUNTERS_GROUP.registerEvent("mergerequests.list.opened") - fun logMrListOpened(): Unit = MR_LIST_OPENED_EVENT.log() + fun logMrListOpened(project: Project): Unit = MR_LIST_OPENED_EVENT.log(project) /** * Merge request details were opened */ private val MR_DETAILS_OPENED_EVENT = COUNTERS_GROUP.registerEvent("mergerequests.details.opened") - fun logMrDetailsOpened(): Unit = MR_DETAILS_OPENED_EVENT.log() + fun logMrDetailsOpened(project: Project): Unit = MR_DETAILS_OPENED_EVENT.log(project) /** * Merge request diff was opened */ - private val MR_DIFF_OPENED_EVENT = COUNTERS_GROUP.registerEvent("mergerequests.diff.opened", EventFields.Boolean("isCumulative")) + private val MR_DIFF_OPENED_EVENT = COUNTERS_GROUP.registerEvent("mergerequests.diff.opened", EventFields.Boolean("is_cumulative")) - fun logMrDiffOpened(isCumulative: Boolean): Unit = MR_DIFF_OPENED_EVENT.log(isCumulative) + fun logMrDiffOpened(project: Project, isCumulative: Boolean): Unit = MR_DIFF_OPENED_EVENT.log(project, isCumulative) /** * Merge request action was executed */ - private val MR_ACTION_FIELD = EventFields.Enum("action", MergeRequestAction::class.java) + private val MR_ACTION_FIELD = EventFields.Enum("action") enum class MergeRequestAction { MERGE, @@ -159,7 +161,7 @@ internal object GitLabStatistics { */ private val MR_ACTION_EVENT = COUNTERS_GROUP.registerEvent("mergerequests.action.performed", MR_ACTION_FIELD) - fun logMrActionExecuted(action: MergeRequestAction): Unit = MR_ACTION_EVENT.log(action) + fun logMrActionExecuted(project: Project, action: MergeRequestAction): Unit = MR_ACTION_EVENT.log(project, action) //endregion } diff --git a/plugins/gitlab/test/org/jetbrains/plugins/gitlab/mergerequest/ui/filters/GitLabMergeRequestsFiltersViewModelImplTest.kt b/plugins/gitlab/test/org/jetbrains/plugins/gitlab/mergerequest/ui/filters/GitLabMergeRequestsFiltersViewModelImplTest.kt index ba21d7cda45a..b53885ee4c83 100644 --- a/plugins/gitlab/test/org/jetbrains/plugins/gitlab/mergerequest/ui/filters/GitLabMergeRequestsFiltersViewModelImplTest.kt +++ b/plugins/gitlab/test/org/jetbrains/plugins/gitlab/mergerequest/ui/filters/GitLabMergeRequestsFiltersViewModelImplTest.kt @@ -35,7 +35,8 @@ internal class GitLabMergeRequestsFiltersViewModelImplTest { @Test fun `check initial default filter search state`() = runTest(UnconfinedTestDispatcher()) { val cs = childScope() - val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, historyModel = emptyHistoryModel, currentUser = mockedUser, + val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, project = null, + historyModel = emptyHistoryModel, currentUser = mockedUser, avatarIconsProvider = mock(), projectData = mock()) val loaderSupplierMock = mockLoaderSupplier() @@ -79,7 +80,8 @@ internal class GitLabMergeRequestsFiltersViewModelImplTest { @Test fun `check changed filter search state`() = runTest(UnconfinedTestDispatcher()) { val cs = childScope() - val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, historyModel = emptyHistoryModel, currentUser = mockedUser, + val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, project = null, + historyModel = emptyHistoryModel, currentUser = mockedUser, avatarIconsProvider = mock(), projectData = mock()) val loaderSupplierMock = mockLoaderSupplier() @@ -109,7 +111,8 @@ internal class GitLabMergeRequestsFiltersViewModelImplTest { @Test fun `check participant filters`() = runTest(UnconfinedTestDispatcher()) { val cs = childScope() - val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, historyModel = emptyHistoryModel, currentUser = mockedUser, + val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, project = null, + historyModel = emptyHistoryModel, currentUser = mockedUser, avatarIconsProvider = mock(), projectData = mock()) val loaderSupplierMock = mockLoaderSupplier() @@ -145,7 +148,8 @@ internal class GitLabMergeRequestsFiltersViewModelImplTest { @Test fun `check default filter`() = runTest(UnconfinedTestDispatcher()) { val cs = childScope() - val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, historyModel = emptyHistoryModel, currentUser = mockedUser, + val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, project = null, + historyModel = emptyHistoryModel, currentUser = mockedUser, avatarIconsProvider = mock(), projectData = mock()) assertEquals(filterVm.searchState.value, defaultFilter) @@ -155,7 +159,8 @@ internal class GitLabMergeRequestsFiltersViewModelImplTest { @Test fun `select empty state filter`() = runTest(UnconfinedTestDispatcher()) { val cs = childScope() - val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, historyModel = emptyHistoryModel, currentUser = mockedUser, + val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, project = null, + historyModel = emptyHistoryModel, currentUser = mockedUser, avatarIconsProvider = mock(), projectData = mock()) assertEquals(filterVm.searchState.value, defaultFilter) @@ -186,7 +191,8 @@ internal class GitLabMergeRequestsFiltersViewModelImplTest { private fun checkSelectedFilter(selectedFilter: GitLabMergeRequestsFiltersValue) = runTest(UnconfinedTestDispatcher()) { val cs = childScope() - val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, historyModel = emptyHistoryModel, currentUser = mockedUser, + val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, project = null, + historyModel = emptyHistoryModel, currentUser = mockedUser, avatarIconsProvider = mock(), projectData = mock()) assertEquals(filterVm.searchState.value, defaultFilter) From d75b49399ab51239f6cd2bff1cee6aa2f7c3001f Mon Sep 17 00:00:00 2001 From: Anton Lobov Date: Fri, 30 Jun 2023 14:37:25 +0200 Subject: [PATCH 094/226] [fleet] FL-20330 workaround idea code that passes this to a call in the constructor FLEET-MR-2546 GitOrigin-RevId: 1e013ee1f18fa4e9553fbc3418d3cf04df01f043 --- .../intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java index 1d54380f35a3..ed8e8a51de96 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java @@ -59,6 +59,7 @@ public class XValueNodeImpl extends XValueContainerNode implements XValu super(tree, parent, true, value); myName = name; + // todo: should be rewritten, this code passes partially initialized 'this' into a call value.computePresentation(this, XValuePlace.TREE); // add "Collecting" message only if computation is not yet done From a46575981745b138bd19d6b81223d217b6069cfc Mon Sep 17 00:00:00 2001 From: "Victoria.Petrakovich" Date: Fri, 30 Jun 2023 22:23:25 +0000 Subject: [PATCH 095/226] [kotlin] Enhance message about different Kotlin versions in modules Merge-request: IJ-MR-109883 Merged-by: Victoria Petrakovich GitOrigin-RevId: 2bbae1557016bbdeb38c1ede573e95f3b9e3a5f8 --- .../gradle/ConversionToKotlinTest.kt | 28 ++--- .../gradle/GradleConfiguratorTest.kt | 46 ++++---- ...otlinProjectConfigurationBundle.properties | 8 +- .../ConfigureKotlinInProjectUtils.kt | 44 ++++++- .../ui/CreateLibraryDialogWithModules.java | 6 +- .../idea/framework/ui/ChooseModulePanel.java | 32 +++-- .../ConfigureDialogWithModulesAndVersion.form | 2 +- .../ConfigureDialogWithModulesAndVersion.java | 111 ++++++++++++------ .../framework/ui/ModulesChangedObserver.java | 7 ++ 9 files changed, 194 insertions(+), 90 deletions(-) create mode 100644 plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ModulesChangedObserver.java diff --git a/plugins/kotlin/gradle/gradle-java/tests/test/org/jetbrains/kotlin/idea/codeInsight/gradle/ConversionToKotlinTest.kt b/plugins/kotlin/gradle/gradle-java/tests/test/org/jetbrains/kotlin/idea/codeInsight/gradle/ConversionToKotlinTest.kt index 336121b25562..a1e91a7af9e3 100644 --- a/plugins/kotlin/gradle/gradle-java/tests/test/org/jetbrains/kotlin/idea/codeInsight/gradle/ConversionToKotlinTest.kt +++ b/plugins/kotlin/gradle/gradle-java/tests/test/org/jetbrains/kotlin/idea/codeInsight/gradle/ConversionToKotlinTest.kt @@ -25,7 +25,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -50,7 +50,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -75,7 +75,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -98,7 +98,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -121,7 +121,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -144,7 +144,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -169,7 +169,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -194,7 +194,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -220,7 +220,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule, rootModule), @@ -246,7 +246,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule, rootModule), @@ -271,7 +271,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -296,7 +296,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -321,7 +321,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -344,7 +344,7 @@ class ConversionToKotlinTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), diff --git a/plugins/kotlin/gradle/gradle-java/tests/test/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleConfiguratorTest.kt b/plugins/kotlin/gradle/gradle-java/tests/test/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleConfiguratorTest.kt index 5593d1f644ac..f77ce7d8b4b8 100644 --- a/plugins/kotlin/gradle/gradle-java/tests/test/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleConfiguratorTest.kt +++ b/plugins/kotlin/gradle/gradle-java/tests/test/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleConfiguratorTest.kt @@ -156,7 +156,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -180,7 +180,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -203,7 +203,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -226,7 +226,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -250,7 +250,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -274,7 +274,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -298,7 +298,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -322,7 +322,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -346,7 +346,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -370,7 +370,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -395,7 +395,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule, subModule), @@ -421,7 +421,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule, subModule), @@ -446,7 +446,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -471,7 +471,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -496,7 +496,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -521,7 +521,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val subModule = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(subModule), @@ -549,7 +549,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project.app")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -571,7 +571,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val module = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(module), @@ -1090,7 +1090,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -1113,7 +1113,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -1136,7 +1136,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -1159,7 +1159,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), @@ -1182,7 +1182,7 @@ class GradleConfiguratorTest : KotlinGradleImportingTestCase() { val rootModule = ModuleManager.getInstance(myProject).findModuleByName("project")!! val configurator = findGradleModuleConfigurator() val collector = NotificationMessageCollector.create(myProject) - val kotlinVersionsAndModules = getKotlinVersionsAndModules(myProject, configurator) + val (kotlinVersionsAndModules, rootModuleKotlinVersion) = getKotlinVersionsAndModules(myProject, configurator) configurator.configureWithVersion( myProject, listOf(rootModule), diff --git a/plugins/kotlin/project-configuration/resources/messages/KotlinProjectConfigurationBundle.properties b/plugins/kotlin/project-configuration/resources/messages/KotlinProjectConfigurationBundle.properties index da7974d5e0df..bd1c53ade43b 100644 --- a/plugins/kotlin/project-configuration/resources/messages/KotlinProjectConfigurationBundle.properties +++ b/plugins/kotlin/project-configuration/resources/messages/KotlinProjectConfigurationBundle.properties @@ -52,9 +52,13 @@ configure.kotlin.find.maven.versions=Find Kotlin Maven plugin versions configure.kotlin.loading=loading\u2026 configure.kotlin.cant.load.versions=Couldn't load versions list from search.maven.org -configure.kotlin.modules.fix.version.manually=With the chosen version of Kotlin, you will probably have to fix versions in other modules manually:\n -configure.kotlin.version.and.modules={0} in {1}\n +configure.kotlin.root.contains.another.kotlin=Your top level build script contains Kotlin {0}.
+configure.kotlin.root.should.contain.same.version=The top level and modules' build scripts should contain the same version.
+configure.kotlin.currently.there.are.versions=Currently, there are versions:
+configure.kotlin.version.and.modules={0} in {1}
configure.kotlin.version.and.modules.and.more=, and in {0} more. +configure.kotlin.choose.another.kotlin.version=
You can choose another Kotlin version or correct versions manually after the conversion.
+configure.kotlin.choose.the.same.kotlin.version=
Use the {0} Kotlin version or correct versions manually after the conversion.
kotlin.compiler.and.runtime.version=Kotlin compiler and runtime version: diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt index 60ccb53f2c96..1d93e0dfda63 100644 --- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt @@ -10,9 +10,11 @@ import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.externalSystem.model.ProjectSystemId import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.Project +import com.intellij.openapi.project.guessProjectDir import com.intellij.openapi.project.modules import com.intellij.openapi.roots.DependencyScope import com.intellij.openapi.roots.LibraryOrderEntry @@ -21,12 +23,16 @@ import com.intellij.openapi.roots.ProjectFileIndex import com.intellij.openapi.roots.impl.libraries.LibraryEx import com.intellij.openapi.roots.libraries.PersistentLibraryKind import com.intellij.openapi.util.ThrowableComputable +import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.FileTypeIndex import com.intellij.psi.search.GlobalSearchScope import com.intellij.util.concurrency.annotations.RequiresBackgroundThread import com.intellij.util.indexing.DumbModeAccessType +import org.jetbrains.annotations.NonNls import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider @@ -59,6 +65,9 @@ import org.jetbrains.kotlin.platform.isJs import org.jetbrains.kotlin.platform.isWasm import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.konan.isNative +import java.nio.file.Path +import kotlin.io.path.Path +import kotlin.io.path.exists private val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtils") @@ -440,9 +449,11 @@ typealias KotlinVersionsAndModules = Map { val configuredModules = getConfiguredModules(project, configurator) val kotlinVersionsAndModules: MutableMap> = mutableMapOf() + val rootModule = getRootModule(project) + var rootModuleVersion: String? = null for (moduleEntity in configuredModules) { val module = moduleEntity.value getKotlinCompilerArguments(module)?.pluginClasspaths?.let { pluginsClasspaths -> @@ -452,11 +463,40 @@ fun getKotlinVersionsAndModules( val modulesForThisVersion = kotlinVersionsAndModules.getOrDefault(version, mutableMapOf()) modulesForThisVersion[moduleEntity.key] = module kotlinVersionsAndModules[version] = modulesForThisVersion + + rootModule?.let { + if (rootModule.name == moduleEntity.key) { + rootModuleVersion = version + } + } } } } } - return kotlinVersionsAndModules + return Pair(kotlinVersionsAndModules, rootModuleVersion) +} + +fun getRootModule(project: Project): Module? { + val topLevelBuildScript = project.getTopLevelBuildScriptFile() + return topLevelBuildScript?.let { ModuleUtilCore.findModuleForPsiElement(it) } +} + +@NonNls +private const val DEFAULT_SCRIPT_NAME = "build.gradle" + +@NonNls +private const val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts" + +private fun Project.getTopLevelBuildScriptFile(): PsiFile? { + val projectDir = this.guessProjectDir() ?: return null + val filePath = listOf(DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME).asSequence() + .map { Path("${projectDir.path}/$it") } + .firstOrNull(Path::exists) + return filePath?.let { path -> + VfsUtil.findFile(path, true)?.let { + PsiManager.getInstance(this).findFile(it) + } + } } typealias ModuleName = String diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ui/CreateLibraryDialogWithModules.java b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ui/CreateLibraryDialogWithModules.java index 373e4078d4c3..7ad5ab6f92e0 100644 --- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ui/CreateLibraryDialogWithModules.java +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ui/CreateLibraryDialogWithModules.java @@ -9,12 +9,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator; import org.jetbrains.kotlin.idea.framework.ui.ChooseModulePanel; +import org.jetbrains.kotlin.idea.framework.ui.ModulesChangedObserver; import javax.swing.*; import java.util.Collection; import java.util.List; -public class CreateLibraryDialogWithModules extends DialogWrapper { +public class CreateLibraryDialogWithModules extends DialogWrapper implements ModulesChangedObserver { private final ChooseModulePanel chooseModulePanel; public CreateLibraryDialogWithModules( @@ -37,4 +38,7 @@ public class CreateLibraryDialogWithModules extends DialogWrapper { protected @Nullable JComponent createCenterPanel() { return chooseModulePanel.getContentPane(); } + + @Override + public void onModulesChangedNotified() {} } \ No newline at end of file diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ChooseModulePanel.java b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ChooseModulePanel.java index c58f73613bea..80acdebe05f7 100644 --- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ChooseModulePanel.java +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ChooseModulePanel.java @@ -62,15 +62,6 @@ public class ChooseModulePanel { } singleModuleComboBox.setModel(comboBoxModel); - ActionListener listener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updateComponents(); - } - }; - singleModuleRadioButton.addActionListener(listener); - allModulesWithKtRadioButton.addActionListener(listener); - allModulesRadioButton.addActionListener(listener); if (modulesWithKtFiles.size() > 2) { String firstName = modulesWithKtFiles.get(0).getName(); @@ -110,6 +101,27 @@ public class ChooseModulePanel { updateComponents(); } + public void setActionListeners(ModulesChangedObserver modulesChangedObserver) { + ActionListener listener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + updateComponents(); + modulesChangedObserver.onModulesChangedNotified(); + } + }; + singleModuleRadioButton.addActionListener(listener); + allModulesWithKtRadioButton.addActionListener(listener); + allModulesRadioButton.addActionListener(listener); + + ActionListener singleModulesListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + modulesChangedObserver.onModulesChangedNotified(); + } + }; + singleModuleComboBox.addActionListener(singleModulesListener); + } + public JComponent getContentPane() { return contentPane; } @@ -128,7 +140,7 @@ public class ChooseModulePanel { return Collections.singletonList(ModuleManager.getInstance(project).findModuleByName(selectedItem)); } - public List getModules() { + public @NotNull List getModules() { return modules; } } diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.form b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.form index 02e31a22f1a7..0c4cd9f1b744 100644 --- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.form +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.form @@ -6,7 +6,7 @@ - + diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.java b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.java index 431afbf656ac..a3d9a79cc85b 100644 --- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.java +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ConfigureDialogWithModulesAndVersion.java @@ -20,7 +20,6 @@ import com.intellij.util.net.HttpConfigurable; import com.intellij.util.text.VersionComparatorUtil; import com.intellij.util.ui.AsyncProcessIcon; import com.intellij.util.ui.UIUtil; -import kotlin.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.idea.compiler.configuration.IdeKotlinVersion; @@ -43,7 +42,7 @@ import java.util.stream.Collectors; import static org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtilsKt.*; -public class ConfigureDialogWithModulesAndVersion extends DialogWrapper { +public class ConfigureDialogWithModulesAndVersion extends DialogWrapper implements ModulesChangedObserver { private static final String VERSIONS_LIST_URL = "https://search.maven.org/solrsearch/select?q=g:%22org.jetbrains.kotlin%22+AND+a:%22kotlin-stdlib%22&core=gav&rows=20&wt=json"; @@ -54,6 +53,8 @@ public class ConfigureDialogWithModulesAndVersion extends DialogWrapper { @NotNull private final String minimumVersion; private final Map> kotlinVersionsAndModules; + @Nullable private final String rootNoduleVersion; + @Nullable private final Module rootModule; private final Map> jvmModulesTargetingUnsupportedJvm; private final Map modulesAndJvmTargets; @@ -79,7 +80,9 @@ public class ConfigureDialogWithModulesAndVersion extends DialogWrapper { KotlinJ2KOnboardingFUSCollector.Companion.logShowConfigureKtWindow(project); - kotlinVersionsAndModules = getKotlinVersionsAndModules(project, configurator); + var kotlinVersions = getKotlinVersionsAndModules(project, configurator); + kotlinVersionsAndModules = kotlinVersions.getFirst(); + rootNoduleVersion = kotlinVersions.getSecond(); setTitle(KotlinProjectConfigurationBundle.message("configure.kotlin.title", configurator.getPresentableText())); @@ -106,60 +109,94 @@ public class ConfigureDialogWithModulesAndVersion extends DialogWrapper { chooseModulePanel = new ChooseModulePanel(project, configurator, excludeModules); chooseModulesPanelPlace.add(chooseModulePanel.getContentPane(), BorderLayout.CENTER); - Pair>, Map> pair = + var jvmTargets = getModulesTargetingUnsupportedJvmAndTargetsForAllModules(chooseModulePanel.getModules(), IdeKotlinVersion.get(DEFAULT_KOTLIN_VERSION)); - jvmModulesTargetingUnsupportedJvm = pair.getFirst(); - modulesAndJvmTargets = pair.getSecond(); + jvmModulesTargetingUnsupportedJvm = jvmTargets.getFirst(); + modulesAndJvmTargets = jvmTargets.getSecond(); + + rootModule = getRootModule(project); + + chooseModulePanel.setActionListeners(this); kotlinVersionComboBox.addItemListener(e -> showWarningIfThereAreDifferentKotlinVersions()); showUnsupportedJvmTargetWarning(); updateComponents(); } + @Override + public void onModulesChangedNotified() { + showWarningIfThereAreDifferentKotlinVersions(); + } + private static final int MODULES_TO_DISPLAY_SIZE = 2; private static final String DELIMITER = ", "; private void showWarningIfThereAreDifferentKotlinVersions() { String currentSelectedKotlinVersion = getKotlinVersion(); - if (!kotlinVersionsAndModules.isEmpty() && - !(kotlinVersionsAndModules.size() == 1 && kotlinVersionsAndModules.containsKey(currentSelectedKotlinVersion))) { + List modulesToConfigure = chooseModulePanel.getModulesToConfigure(); + if (!kotlinVersionsAndModules.isEmpty() && currentSelectedKotlinVersion != null && !modulesToConfigure.isEmpty()) { listOfKotlinVersionsAndModules.setText(""); - final StringBuilder message = new StringBuilder(); - message.append(KotlinProjectConfigurationBundle.message("configure.kotlin.modules.fix.version.manually")); - kotlinVersionsAndModules.keySet().stream().filter(it -> !it.equals(currentSelectedKotlinVersion)).sorted() - .forEach(it -> { - Map modules = kotlinVersionsAndModules.get(it); - Set modulesNames = modules.keySet(); - StringBuilder modulesEnumeration = new StringBuilder(); - if (modulesNames.size() > MODULES_TO_DISPLAY_SIZE) { - modulesEnumeration.append( - modulesNames.stream().limit(MODULES_TO_DISPLAY_SIZE).sorted() - .collect(Collectors.joining(DELIMITER))); - modulesEnumeration.append( - KotlinProjectConfigurationBundle.message("configure.kotlin.version.and.modules.and.more", - modulesNames.size() - - MODULES_TO_DISPLAY_SIZE)); - } else { - modulesEnumeration.append(modulesNames.stream().sorted().collect(Collectors.joining(DELIMITER))); - } - message.append(KotlinProjectConfigurationBundle - .message("configure.kotlin.version.and.modules", it, - modulesEnumeration.toString())); - } - ); - // It's not hardcoded, we take strings from resources - //noinspection HardCodedStringLiteral - listOfKotlinVersionsAndModules.setText(message.toString()); - listOfKotlinVersionsAndModules.setVisible(true); + + if (modulesToConfigure.contains(rootModule) && + !(kotlinVersionsAndModules.size() == 1 && kotlinVersionsAndModules.containsKey(currentSelectedKotlinVersion))) { + createMessageAboutDifferentKotlinVersions(currentSelectedKotlinVersion); + } else if (rootNoduleVersion != null && + !IdeKotlinVersion.get(rootNoduleVersion).equals(IdeKotlinVersion.get(currentSelectedKotlinVersion))) { + createMessageThatTopLevelAndModulesShouldHaveSameVersion(); + } else { + listOfKotlinVersionsAndModules.setVisible(false); + } } else { listOfKotlinVersionsAndModules.setVisible(false); } } + private void createMessageThatTopLevelAndModulesShouldHaveSameVersion() { + String message = KotlinProjectConfigurationBundle.message("configure.kotlin.root.contains.another.kotlin", rootNoduleVersion) + + KotlinProjectConfigurationBundle.message("configure.kotlin.root.should.contain.same.version") + + KotlinProjectConfigurationBundle.message("configure.kotlin.choose.the.same.kotlin.version", rootNoduleVersion); + Messages.installHyperlinkSupport(listOfKotlinVersionsAndModules); + listOfKotlinVersionsAndModules.setText(message); + listOfKotlinVersionsAndModules.setVisible(true); + } + + private void createMessageAboutDifferentKotlinVersions(String currentSelectedKotlinVersion) { + final StringBuilder message = new StringBuilder(); + message.append(KotlinProjectConfigurationBundle.message("configure.kotlin.root.should.contain.same.version")); + message.append(KotlinProjectConfigurationBundle.message("configure.kotlin.currently.there.are.versions")); + + kotlinVersionsAndModules.keySet().stream().filter(it -> !it.equals(currentSelectedKotlinVersion)).sorted() + .forEach(it -> { + Map modules = kotlinVersionsAndModules.get(it); + Set modulesNames = modules.keySet(); + StringBuilder modulesEnumeration = new StringBuilder(); + if (modulesNames.size() > MODULES_TO_DISPLAY_SIZE) { + modulesEnumeration.append( + modulesNames.stream().limit(MODULES_TO_DISPLAY_SIZE).sorted() + .collect(Collectors.joining(DELIMITER))); + modulesEnumeration.append( + KotlinProjectConfigurationBundle.message("configure.kotlin.version.and.modules.and.more", + modulesNames.size() - + MODULES_TO_DISPLAY_SIZE)); + } else { + modulesEnumeration.append(modulesNames.stream().sorted().collect(Collectors.joining(DELIMITER))); + } + message.append(KotlinProjectConfigurationBundle + .message("configure.kotlin.version.and.modules", it, + modulesEnumeration.toString())); + } + ); + + message.append(KotlinProjectConfigurationBundle.message("configure.kotlin.choose.another.kotlin.version")); + Messages.installHyperlinkSupport(listOfKotlinVersionsAndModules); + // It's not hardcoded, we take strings from resources + //noinspection HardCodedStringLiteral + listOfKotlinVersionsAndModules.setText(message.toString()); + listOfKotlinVersionsAndModules.setVisible(true); + } + private void showUnsupportedJvmTargetWarning() { - //warningsSplitter.setEnabled(true); - //warningsSplitter.setVisible(true); if (!jvmModulesTargetingUnsupportedJvm.isEmpty()) { final StringBuilder message = new StringBuilder(); message.append(KotlinProjectConfigurationBundle.message("configurator.kotlin.jvm.targets.unsupported", "1.8")); diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ModulesChangedObserver.java b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ModulesChangedObserver.java new file mode 100644 index 000000000000..6e44cfce5e7d --- /dev/null +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/framework/ui/ModulesChangedObserver.java @@ -0,0 +1,7 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.framework.ui; + +public interface ModulesChangedObserver { + + void onModulesChangedNotified(); +} From 90f0132e407ea4c538928bfb3afa80e2370c5854 Mon Sep 17 00:00:00 2001 From: Alexandr Suhinin Date: Fri, 30 Jun 2023 19:20:41 +0300 Subject: [PATCH 096/226] [floating toolbar] IDEA-321869: enable toolbar by default GitOrigin-RevId: 09c9b11c49382a5726230b59c0a54c31b883f831 --- platform/platform-resources/src/META-INF/LangExtensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index e2303023782f..566d7d414680 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -1702,7 +1702,7 @@ - + Date: Fri, 30 Jun 2023 20:32:55 +0300 Subject: [PATCH 097/226] [floating toolbar] IDEA-321869: fix show intention popup in default position if toolbar is not available GitOrigin-RevId: 18224216494af3c5ddd1b853400375cc5ca16df0 --- .../impl/IntentionHintComponent.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java index 2f25690a0144..644d43da8608 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionHintComponent.java @@ -240,6 +240,21 @@ public final class IntentionHintComponent implements Disposable, ScrollAwareHint showPopup(null); } + private void showPopupFromToolbar(CodeFloatingToolbar toolbar) { + RelativePoint position = findPositionForToolbarButton(toolbar); + adjustVerticalOverlapping(position); + showPopup(position); + } + + private void adjustVerticalOverlapping(@Nullable RelativePoint position) { + if (position == null) return; + if (myPopup.myListPopup == null) { + myPopup.myHint = this; + IntentionPopup.recreateMyPopup(myPopup, new IntentionListStep(myPopup, myPopup.myEditor, myPopup.myFile, myPopup.myProject, myPopup.myCachedIntentions)); + } + ActionButton.adjustVerticalOverlapping(myPopup.myListPopup, position.getOriginalComponent()); + } + private void showPopup(@Nullable RelativePoint positionHint) { myPopup.show(this, positionHint); } @@ -272,22 +287,17 @@ public final class IntentionHintComponent implements Disposable, ScrollAwareHint return new RelativePoint(swCorner.getComponent(), popup); } - private void showPopupFromToolbar(@NotNull CodeFloatingToolbar toolbar){ + private static @Nullable RelativePoint findPositionForToolbarButton(@NotNull CodeFloatingToolbar toolbar){ JComponent component = toolbar.getHintComponent(); - if (component == null) return; + if (component == null) return null; List buttons = UIUtil.findComponentsOfType(component, ActionButton.class); ActionButton intentionButton = ContainerUtil.find(buttons, (button) -> button.getAction() instanceof ShowIntentionActionsAction); - if (intentionButton == null) return; + if (intentionButton == null) return null; RelativePoint buttonPoint = RelativePoint.getSouthWestOf(intentionButton); RelativePoint toolbarPoint = RelativePoint.getSouthWestOf(component); int horizontalOffset = toolbarPoint.getScreenPoint().x - buttonPoint.getScreenPoint().x; buttonPoint.getPoint().translate(horizontalOffset, 0); - if (myPopup.myListPopup == null) { - myPopup.myHint = this; - IntentionPopup.recreateMyPopup(myPopup, new IntentionListStep(myPopup, myPopup.myEditor, myPopup.myFile, myPopup.myProject, myPopup.myCachedIntentions)); - } - ActionButton.adjustVerticalOverlapping(myPopup.myListPopup, intentionButton); - showPopup(buttonPoint); + return buttonPoint; } private static final class MyComponentHint extends LightweightHint { From 087946141a6dc10da974a8c55e071ea553c12918 Mon Sep 17 00:00:00 2001 From: Dmitry Kichinsky Date: Fri, 30 Jun 2023 09:49:08 +0200 Subject: [PATCH 098/226] [maven] update version to 4.0.0-alpha-7 GitOrigin-RevId: b2f6d7655ae6af6a04e041e7e7791edc43bf6b0e --- .../intellij.maven.server.m40.iml | 136 +++++++++--------- .../server/m40/Maven40ServerEmbedderImpl.java | 12 +- .../server/m40/utils/Maven40ProfileUtil.java | 7 +- ...avenCompatibilityProjectImportingTest.java | 2 +- .../MavenMultiVersionImportingTestCase.java | 2 +- 5 files changed, 79 insertions(+), 80 deletions(-) diff --git a/plugins/maven/maven40-server-impl/intellij.maven.server.m40.iml b/plugins/maven/maven40-server-impl/intellij.maven.server.m40.iml index b20fb21fe182..89a3133dbc5d 100644 --- a/plugins/maven/maven40-server-impl/intellij.maven.server.m40.iml +++ b/plugins/maven/maven40-server-impl/intellij.maven.server.m40.iml @@ -10,104 +10,100 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + - diff --git a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java index d2ddceb4ff9d..46769e5fa15b 100644 --- a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java +++ b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java @@ -18,6 +18,7 @@ import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.InvalidRepositoryException; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.cli.MavenCli; import org.apache.maven.cli.internal.extension.model.CoreExtension; import org.apache.maven.execution.*; @@ -35,7 +36,6 @@ import org.apache.maven.plugin.LegacySupport; import org.apache.maven.plugin.internal.PluginDependenciesResolver; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuildingException; -import org.apache.maven.repository.RepositorySystem; import org.apache.maven.session.scope.internal.SessionScope; import org.apache.maven.settings.Settings; import org.apache.maven.settings.building.DefaultSettingsBuilderFactory; @@ -83,7 +83,7 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase { private final boolean myAlwaysUpdateSnapshots; - @NotNull private final RepositorySystem myRepositorySystem; + @NotNull private final MavenRepositorySystem myRepositorySystem; @NotNull private final Maven40ImporterSpy myImporterSpy; @@ -194,7 +194,7 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase { ReflectionUtilRt.getField(cliRequestClass, cliRequest, Properties.class, "userProperties") ); - myRepositorySystem = getComponent(RepositorySystem.class); + myRepositorySystem = getComponent(MavenRepositorySystem.class); Maven40ImporterSpy importerSpy = getComponentIfExists(Maven40ImporterSpy.class); @@ -926,8 +926,8 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase { List result = map2ArtifactRepositories(repositories); if (getComponent(LegacySupport.class).getRepositorySession() == null) { myRepositorySystem.injectMirror(result, myMavenSettings.getMirrors()); - myRepositorySystem.injectProxy(result, myMavenSettings.getProxies()); - myRepositorySystem.injectAuthentication(result, myMavenSettings.getServers()); + //myRepositorySystem.injectProxy(result, myMavenSettings.getProxies()); + //myRepositorySystem.injectAuthentication(result, myMavenSettings.getServers()); } return result; } @@ -946,7 +946,7 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase { } private ArtifactRepository buildArtifactRepository(Repository repo) throws InvalidRepositoryException { - RepositorySystem repositorySystem = myRepositorySystem; + MavenRepositorySystem repositorySystem = myRepositorySystem; RepositorySystemSession session = getComponent(LegacySupport.class).getRepositorySession(); ArtifactRepository repository = repositorySystem.buildArtifactRepository(repo); diff --git a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ProfileUtil.java b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ProfileUtil.java index 4d4030a3327b..7bf95ffd58ce 100644 --- a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ProfileUtil.java +++ b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ProfileUtil.java @@ -16,6 +16,7 @@ import org.apache.maven.model.profile.activation.JdkVersionProfileActivator; import org.apache.maven.model.profile.activation.OperatingSystemProfileActivator; import org.apache.maven.model.profile.activation.ProfileActivator; import org.apache.maven.model.profile.activation.PropertyProfileActivator; +import org.apache.maven.model.root.DefaultRootLocator; import org.apache.maven.project.MavenProject; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.maven.model.MavenConstants; @@ -66,7 +67,8 @@ public final class Maven40ProfileUtil { if (expandedProfilesCache == null) { DefaultPathTranslator pathTranslator = new DefaultPathTranslator(); DefaultUrlNormalizer urlNormalizer = new DefaultUrlNormalizer(); - StringVisitorModelInterpolator interpolator = new StringVisitorModelInterpolator(pathTranslator, urlNormalizer); + DefaultRootLocator rootLocator = new DefaultRootLocator(); + StringVisitorModelInterpolator interpolator = new StringVisitorModelInterpolator(pathTranslator, urlNormalizer, rootLocator); expandedProfilesCache = doInterpolate(interpolator, nativeModel, basedir).getProfiles(); } Profile eachExpandedProfile = expandedProfilesCache.get(i); @@ -168,7 +170,8 @@ public final class Maven40ProfileUtil { Model nativeModel = Maven40ModelConverter.toNativeModel(model); DefaultPathTranslator pathTranslator = new DefaultPathTranslator(); DefaultUrlNormalizer urlNormalizer = new DefaultUrlNormalizer(); - StringVisitorModelInterpolator interpolator = new StringVisitorModelInterpolator(pathTranslator, urlNormalizer); + DefaultRootLocator rootLocator = new DefaultRootLocator(); + StringVisitorModelInterpolator interpolator = new StringVisitorModelInterpolator(pathTranslator, urlNormalizer, rootLocator); Model result = doInterpolate(interpolator, nativeModel, basedir); MyDefaultPathTranslator myPathTranslator = new MyDefaultPathTranslator(pathTranslator); myPathTranslator.alignToBaseDirectory(result, basedir); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compatibility/MavenCompatibilityProjectImportingTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compatibility/MavenCompatibilityProjectImportingTest.java index ba2ac4820a9d..287f2fa492b5 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compatibility/MavenCompatibilityProjectImportingTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compatibility/MavenCompatibilityProjectImportingTest.java @@ -34,7 +34,7 @@ public class MavenCompatibilityProjectImportingTest extends MavenImportingTestCa @Parameterized.Parameters(name = "with Maven-{0}") public static List getMavenVersions() { return Arrays.asList( - new String[]{"4.0.0-alpha-5"}, + new String[]{"4.0.0-alpha-7"}, new String[]{"3.9.2"}, new String[]{"3.9.1"}, new String[]{"3.9.0"}, diff --git a/plugins/maven/testFramework/src/com/intellij/maven/testFramework/MavenMultiVersionImportingTestCase.java b/plugins/maven/testFramework/src/com/intellij/maven/testFramework/MavenMultiVersionImportingTestCase.java index aa057be27ed3..ffb1eb8be784 100644 --- a/plugins/maven/testFramework/src/com/intellij/maven/testFramework/MavenMultiVersionImportingTestCase.java +++ b/plugins/maven/testFramework/src/com/intellij/maven/testFramework/MavenMultiVersionImportingTestCase.java @@ -30,7 +30,7 @@ import java.util.List; @RunWith(Parameterized.class) public abstract class MavenMultiVersionImportingTestCase extends MavenImportingTestCase { - public static final String[] MAVEN_VERSIONS = new String[]{"bundled", "4.0.0-alpha-5"}; + public static final String[] MAVEN_VERSIONS = new String[]{"bundled", "4.0.0-alpha-7"}; @Parameterized.Parameter(0) public String myMavenVersion; @Nullable From e3bce343939d1cc0de89fbf6e9addf4bb566bd8f Mon Sep 17 00:00:00 2001 From: Dmitry Kichinsky Date: Sat, 1 Jul 2023 00:33:18 +0200 Subject: [PATCH 099/226] [maven] update version to 4.0.0-alpha-7 GitOrigin-RevId: 45826df1a2072c0bb5f2d10db9a793bb73fbb4cf --- .../server/m40/Maven40ServerEmbedderImpl.java | 29 +++++++++++++++++++ ...avenCompatibilityProjectImportingTest.java | 13 ++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java index 46769e5fa15b..e540f097aed4 100644 --- a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java +++ b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java @@ -442,6 +442,9 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase { MavenExecutionRequest result = new DefaultMavenExecutionRequest(); try { + injectDefaultRepositories(result); + injectDefaultPluginRepositories(result); + getComponent(MavenExecutionRequestPopulator.class).populateFromSettings(result, myMavenSettings); result.setPom(file); @@ -476,6 +479,32 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase { } } + private void injectDefaultRepositories(MavenExecutionRequest request) + throws MavenExecutionRequestPopulationException { + Set definedRepositories = myRepositorySystem.getRepoIds(request.getRemoteRepositories()); + + if (!definedRepositories.contains(MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID)) { + try { + request.addRemoteRepository(myRepositorySystem.createDefaultRemoteRepository(request)); + } catch (Exception e) { + throw new MavenExecutionRequestPopulationException("Cannot create default remote repository.", e); + } + } + } + + private void injectDefaultPluginRepositories(MavenExecutionRequest request) + throws MavenExecutionRequestPopulationException { + Set definedRepositories = myRepositorySystem.getRepoIds(request.getPluginArtifactRepositories()); + + if (!definedRepositories.contains(MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID)) { + try { + request.addPluginArtifactRepository(myRepositorySystem.createDefaultRemoteRepository(request)); + } catch (Exception e) { + throw new MavenExecutionRequestPopulationException("Cannot create default remote repository.", e); + } + } + } + @NotNull private static File getMultimoduleProjectDir(@Nullable File file) { File mavenMultiModuleProjectDirectory; diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compatibility/MavenCompatibilityProjectImportingTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compatibility/MavenCompatibilityProjectImportingTest.java index 287f2fa492b5..9db532c0d0a3 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compatibility/MavenCompatibilityProjectImportingTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compatibility/MavenCompatibilityProjectImportingTest.java @@ -4,6 +4,7 @@ package org.jetbrains.idea.maven.compatibility; import com.intellij.maven.testFramework.MavenImportingTestCase; import com.intellij.maven.testFramework.MavenWrapperTestFixture; import com.intellij.openapi.module.LanguageLevelUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.VersionComparatorUtil; @@ -408,7 +409,17 @@ public class MavenCompatibilityProjectImportingTest extends MavenImportingTestCa """); assertModules("project"); - var expectedVersion = VersionComparatorUtil.compare(myMavenVersion, "3.9.0") >= 0 ? LanguageLevel.JDK_1_7 : LanguageLevel.JDK_1_5; + LanguageLevel expectedVersion; + if (isMaven4()) { + expectedVersion = VersionComparatorUtil.compare(myMavenVersion, "4.0.0-alpha-7") >= 0 ? LanguageLevel.JDK_1_8 : LanguageLevel.JDK_1_7; + } + else { + expectedVersion = VersionComparatorUtil.compare(myMavenVersion, "3.9.0") >= 0 ? LanguageLevel.JDK_1_7 : LanguageLevel.JDK_1_5; + } assertEquals(expectedVersion, LanguageLevelUtil.getCustomLanguageLevel(getModule("project"))); } + + protected boolean isMaven4() { + return StringUtil.compareVersionNumbers(myMavenVersion, "4.0") >= 0; + } } From 702be5858d265c5576e07c7393983ef032af04c9 Mon Sep 17 00:00:00 2001 From: Ilya Muradyan Date: Sat, 1 Jul 2023 00:49:39 +0200 Subject: [PATCH 100/226] KTNB-260, FUS: Fix `notebook.opened` event, add `cell.result.received`, `output.updated`, `library.used` events GitOrigin-RevId: c644c0cbef443a86e4f765d409a06137251448a1 --- .../intellij/internal/statistic/LibraryNameValidationRule.kt | 2 +- .../internal/statistic/libraryUsage/LibraryUsageDescriptors.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/internal/statistic/LibraryNameValidationRule.kt b/java/java-impl/src/com/intellij/internal/statistic/LibraryNameValidationRule.kt index 08f7a2ad0288..627208c9c947 100644 --- a/java/java-impl/src/com/intellij/internal/statistic/LibraryNameValidationRule.kt +++ b/java/java-impl/src/com/intellij/internal/statistic/LibraryNameValidationRule.kt @@ -12,7 +12,7 @@ import com.intellij.internal.statistic.libraryUsage.LibraryUsageDescriptors *
* See 'library-jar-statistics.xml' and 'library-usage-statistics.xml' files. */ -internal class LibraryNameValidationRule : CustomValidationRule() { +class LibraryNameValidationRule : CustomValidationRule() { override fun getRuleId(): String = "used_library_name" override fun doValidate(data: String, context: EventContext): ValidationResultType { diff --git a/java/java-impl/src/com/intellij/internal/statistic/libraryUsage/LibraryUsageDescriptors.kt b/java/java-impl/src/com/intellij/internal/statistic/libraryUsage/LibraryUsageDescriptors.kt index 6a9f12a556d7..3a429e27d51d 100644 --- a/java/java-impl/src/com/intellij/internal/statistic/libraryUsage/LibraryUsageDescriptors.kt +++ b/java/java-impl/src/com/intellij/internal/statistic/libraryUsage/LibraryUsageDescriptors.kt @@ -8,7 +8,7 @@ import com.intellij.util.xmlb.annotations.Property import com.intellij.util.xmlb.annotations.Tag import com.intellij.util.xmlb.annotations.XCollection -internal object LibraryUsageDescriptors { +object LibraryUsageDescriptors { private val descriptors: List = downloadLibraryDescriptors() private val libraryDescriptorFinder: LibraryLayer = LibraryLayer.create(downloadLibraryDescriptors()) From e39fc292c36f17eeb5e384033552e3d70f00b633 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 30 Jun 2023 16:06:52 +0200 Subject: [PATCH 101/226] improve new user heuristic detection (check for bundled plugin state file, this may help when vm option file is generated and config folder is already exists) IDEA-321907 GitOrigin-RevId: b61efe590005da00153d4a44c611c1881d311710 --- .../intellij/ide/plugins/BundledPluginsState.kt | 17 ++++++++++++++++- .../src/com/intellij/idea/StartupUtil.kt | 7 +++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/BundledPluginsState.kt b/platform/platform-impl/src/com/intellij/ide/plugins/BundledPluginsState.kt index f24dc73ddac2..a09a23e97a8e 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/BundledPluginsState.kt +++ b/platform/platform-impl/src/com/intellij/ide/plugins/BundledPluginsState.kt @@ -22,6 +22,7 @@ import org.jetbrains.annotations.VisibleForTesting import java.io.IOException import java.nio.file.Files import java.nio.file.Path +import java.util.concurrent.atomic.AtomicReference import kotlin.io.path.exists import kotlin.io.path.readLines @@ -43,10 +44,24 @@ class BundledPluginsState : ApplicationInitializedListener { val loadedPlugins: Set @VisibleForTesting get() = PluginManagerCore.getLoadedPlugins().filterTo(HashSet()) { it.isBundled } + private val stateExistedAtTheStart = AtomicReference(null) + + /** + * should be called before writing to the file + */ + fun checkStateExistedAtTheStart(bundledPluginsFile: Path = PathManager.getConfigDir().resolve(BUNDLED_PLUGINS_FILENAME)): Boolean { + if (stateExistedAtTheStart.get() == null) { + stateExistedAtTheStart.set(bundledPluginsFile.exists()) + } + return stateExistedAtTheStart.get() + } + @VisibleForTesting fun writePluginIdsToFile(pluginIds: Set, configDir: Path = PathManager.getConfigDir()) { + val bundledPluginsFile = configDir.resolve(BUNDLED_PLUGINS_FILENAME) + checkStateExistedAtTheStart(bundledPluginsFile) PluginManagerCore.writePluginIdsToFile( - configDir.resolve(BUNDLED_PLUGINS_FILENAME), + bundledPluginsFile, pluginIds.map { "${it.pluginId.idString}|${it.category}\n" }, ) } diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt b/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt index b48ca34f12b8..301c226da7df 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt @@ -11,6 +11,7 @@ import com.intellij.ide.* import com.intellij.ide.bootstrap.* import com.intellij.ide.gdpr.EndUserAgreement import com.intellij.ide.instrument.WriteIntentLockInstrumenter +import com.intellij.ide.plugins.BundledPluginsState import com.intellij.ide.plugins.PluginManagerCore import com.intellij.ide.ui.laf.IntelliJLaf import com.intellij.idea.DirectoryLock.CannotActivateException @@ -216,7 +217,7 @@ fun CoroutineScope.startApplication(args: List, if (ConfigImportHelper.isNewUser() && System.getProperty(NewUiValue.KEY) == null) { runCatching { - EarlyAccessRegistryManager.setAndFlush(mapOf(NewUiValue.KEY to "true")) + EarlyAccessRegistryManager.setAndFlush(mapOf(NewUiValue.KEY to true.toString())) }.getOrLogException(log) } } @@ -335,8 +336,10 @@ fun CoroutineScope.startApplication(args: List, } fun isConfigImportNeeded(configPath: Path): Boolean { - return !Files.exists(configPath) || Files.exists(configPath.resolve(ConfigImportHelper.CUSTOM_MARKER_FILE_NAME)) + return !Files.exists(configPath) + || Files.exists(configPath.resolve(ConfigImportHelper.CUSTOM_MARKER_FILE_NAME)) || customTargetDirectoryToImportConfig != null + || !(BundledPluginsState.checkStateExistedAtTheStart() || ApplicationManagerEx.isInIntegrationTest()) } /** From 53ae7a29a95b088d010c134cc07a6deaf2cd9bde Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 29 Jun 2023 14:41:36 +0200 Subject: [PATCH 102/226] Java: minor reference graph cleanup GitOrigin-RevId: 195619e151da5e91e497f7a016f902333fcfa54e --- .../codeInspection/reference/RefJavaManagerImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java index b51d01d2945c..adcb011c7819 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java @@ -459,8 +459,9 @@ public final class RefJavaManagerImpl extends RefJavaManager { PsiModifierListOwner javaModifiersListOwner = ObjectUtils.tryCast(node.getJavaPsi(), PsiModifierListOwner.class); if (javaModifiersListOwner != null) { - PsiAnnotation externalAnnotation = myExternalAnnotationsManager.findExternalAnnotation(javaModifiersListOwner, - BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME); + PsiAnnotation externalAnnotation = + myExternalAnnotationsManager.findExternalAnnotation(javaModifiersListOwner, + BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME); UAnnotation uAnnotation = UastContextKt.toUElement(externalAnnotation, UAnnotation.class); if (uAnnotation != null) { retrieveSuppressions(uAnnotation, node); @@ -471,6 +472,7 @@ public final class RefJavaManagerImpl extends RefJavaManager { @Override public boolean visitExpression(@NotNull UExpression node) { + // for lambda expressions and method references RefElement refElement = myRefManager.getReference(node.getSourcePsi()); if (refElement != null) { myRefManager.buildReferences(refElement); @@ -544,7 +546,7 @@ public final class RefJavaManagerImpl extends RefJavaManager { } } - if (buf.length() > 0) { + if (!buf.isEmpty()) { String suppressId = buf.substring(1); element.addSuppression(suppressId); From d9290f4882c9f1f456daa88fc0fb2476b57d0b3d Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 30 Jun 2023 17:36:26 +0200 Subject: [PATCH 103/226] Mac: enable force-touch in keymap settings again (IDEA-192405) GitOrigin-RevId: 3424df7b3097f8cad26306c88c3c8d76f407499f --- ...acGestureSupportForMouseShortcutPanel.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacGestureSupportForMouseShortcutPanel.java b/platform/platform-impl/src/com/intellij/ui/mac/MacGestureSupportForMouseShortcutPanel.java index 089aae4006ef..39cf55549556 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacGestureSupportForMouseShortcutPanel.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacGestureSupportForMouseShortcutPanel.java @@ -10,25 +10,24 @@ import com.apple.eawt.event.GestureUtilities; import com.apple.eawt.event.PressureEvent; import com.apple.eawt.event.PressureListener; import com.intellij.openapi.actionSystem.PressureShortcut; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.keymap.impl.ui.MouseShortcutPanel; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.util.lang.JavaVersion; public final class MacGestureSupportForMouseShortcutPanel { public MacGestureSupportForMouseShortcutPanel(MouseShortcutPanel panel, Runnable runnable) { - //todo[kb]: return pressure listener to jbr17 - if (SystemInfo.isJetBrainsJvm && JavaVersion.current().isAtLeast(17)) { - return; - } - GestureListener pressureListener = new PressureListener() { - @Override - public void pressure(PressureEvent e) { - if (e.getStage() == 2) { - panel.setShortcut(new PressureShortcut(e.getStage())); - runnable.run(); + try { + GestureListener pressureListener = new PressureListener() { + @Override + public void pressure(PressureEvent e) { + if (e.getStage() == 2) { + panel.setShortcut(new PressureShortcut(e.getStage())); + runnable.run(); + } } - } - }; - GestureUtilities.addGestureListenerTo(panel, pressureListener); + }; + GestureUtilities.addGestureListenerTo(panel, pressureListener); + } catch (Throwable t) { + Logger.getInstance(MacGestureSupportForMouseShortcutPanel.class).warn("macOS gesture support failed", t); + } } } From 45ff05b5f13eb8f1adf340eaa87d18f9ad6e5a13 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Sat, 1 Jul 2023 11:52:27 +0200 Subject: [PATCH 104/226] IDEA-321134 "More tool windows" menu appears on a different monitor when button moved to the right sidebar GitOrigin-RevId: ff728d0ce411823c3a3c418ade6da64185ae741c --- .../src/com/intellij/toolWindow/MoreSquareStripeButton.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt b/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt index f58ee5f71d3f..f0e47e3406ea 100644 --- a/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt +++ b/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt @@ -89,7 +89,7 @@ private fun createAction(toolWindowToolbar: ToolWindowToolbar): DumbAwareAction override fun actionPerformed(e: AnActionEvent) { val actions = ToolWindowsGroup.getToolWindowActions(e.project ?: return, true) val popup = JBPopupFactory.getInstance().createActionGroupPopup(null, DefaultActionGroup(actions), e.dataContext, null, true) - val minimumPopupWidth = 300 + val minimumPopupWidth = JBUI.scale(300) popup.setMinimumSize(Dimension(minimumPopupWidth, -1)) val moreSquareStripeButton = toolWindowToolbar.moreButton val x = if (toolWindowToolbar is ToolWindowLeftToolbar) { From 555d12b0d283068cd5f3e9fa06ad5c71cefdbab6 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Sat, 1 Jul 2023 12:00:16 +0200 Subject: [PATCH 105/226] IDEA-299337 Tool window buttons: make it possible to move More icon GitOrigin-RevId: 43b8b41b62605cf69bd75b3e79dc4e79e9bd39ac --- .../intellij/openapi/wm/impl/ToolWindowManagerState.kt | 2 +- .../com/intellij/toolWindow/MoreSquareStripeButton.kt | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerState.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerState.kt index 19636e998c54..a03bcc6dc35e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerState.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerState.kt @@ -82,7 +82,7 @@ class ToolWindowManagerStateImpl : ToolWindowManagerState { } element.addContent(recentState) } - if (moreButton !== ToolWindowAnchor.LEFT) { + if (moreButton != ToolWindowAnchor.LEFT) { element.addContent(Element(MORE_BUTTON_TAG).setAttribute("side", moreButton.toString())) } return element diff --git a/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt b/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt index f0e47e3406ea..dd5136fdcbe1 100644 --- a/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt +++ b/platform/platform-impl/src/com/intellij/toolWindow/MoreSquareStripeButton.kt @@ -63,8 +63,7 @@ internal class MoreSquareStripeButton(toolWindowToolbar: ToolWindowToolbar, } override fun isAvailable(project: Project): Boolean { - return super.isAvailable(project) && ToolWindowManagerEx.getInstanceEx( - project).getMoreButtonSide() == side + return super.isAvailable(project) && ToolWindowManagerEx.getInstanceEx(project).getMoreButtonSide() == side } override fun checkSkipPressForEvent(e: MouseEvent) = e.button != MouseEvent.BUTTON1 @@ -109,11 +108,7 @@ internal abstract class AbstractMoreSquareStripeButton(action: AnAction) : Abstr override fun update() { super.update() val project = dataContext.getData(CommonDataKeys.PROJECT) - if (project == null) { - return - } - - val available = isAvailable(project) + val available = project != null && isAvailable(project) myPresentation.isEnabledAndVisible = available isEnabled = available From 5ad96f7b38d264d0b38c10c41a867acfbc7b68c2 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 30 Jun 2023 15:40:36 +0200 Subject: [PATCH 106/226] [java-intentions] More ModCommands (IDEA-322693) GitOrigin-RevId: ac544ca3f30695ccf6f8c389444d6ab6bb182ade --- .../impl/analysis/ModuleHighlightUtil.java | 2 +- .../daemon/impl/quickfix/ExtendsListFix.java | 2 - .../daemon/impl/quickfix/GoToSymbolFix.java | 46 +---- .../impl/quickfix/MoveParenthesisFix.java | 47 ++--- .../DeprecationInspectionBase.java | 4 +- .../deprecationInspectionQuickFixes.kt | 47 ++--- .../src/messages/QuickFixBundle.properties | 2 +- .../impl/quickfix/NegationBroadScopeFix.java | 82 +++------ .../intention/impl/InlineStreamMapAction.java | 36 ++-- .../impl/config/QuickFixFactoryImpl.java | 2 +- .../quickFix/negationBroadScope/after1.java | 2 +- .../ig/inheritance/StaticInheritanceFix.java | 154 ++++++---------- .../StaticInheritanceInspection.java | 6 +- .../ShowDateTimeExampleOutputIntention.java | 171 ++++++++---------- .../binding/FormClassAnnotator.java | 44 +---- 15 files changed, 229 insertions(+), 418 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java index 676b851b8119..b52734fd4a72 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java @@ -119,7 +119,7 @@ final class ModuleHighlightUtil { .descriptionAndTooltip(message); rootModuleInfos.stream().map(f -> PsiManager.getInstance(project).findFile(f)).filter(f -> f != file).findFirst().ifPresent( duplicate -> { - IntentionAction action = new GoToSymbolFix(duplicate, JavaErrorBundle + var action = new GoToSymbolFix(duplicate, JavaErrorBundle .message("module.open.duplicate.text")); info.registerFix(action, null, null, null, null); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ExtendsListFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ExtendsListFix.java index db73aae5b8e9..ed63a242c33b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ExtendsListFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ExtendsListFix.java @@ -5,7 +5,6 @@ import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.intention.impl.BaseIntentionAction; import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; import com.intellij.codeInspection.util.IntentionName; -import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; @@ -97,7 +96,6 @@ public class ExtendsListFix extends LocalQuickFixAndIntentionActionOnPsiElement @NotNull PsiElement endElement) { final PsiClass myClass = (PsiClass)startElement; invokeImpl(myClass); - UndoUtil.markPsiFileForUndo(file); } protected void invokeImpl(PsiClass myClass) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GoToSymbolFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GoToSymbolFix.java index 4c8bc2e26371..4cbe4266bf75 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GoToSymbolFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GoToSymbolFix.java @@ -1,62 +1,36 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 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.quickfix; -import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; import com.intellij.codeInspection.util.IntentionName; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModNavigate; +import com.intellij.modcommand.PsiBasedModCommandAction; import com.intellij.psi.NavigatablePsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.SmartPointerManager; -import com.intellij.psi.SmartPsiElementPointer; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; -public class GoToSymbolFix implements IntentionAction { - private final SmartPsiElementPointer myPointer; +public class GoToSymbolFix extends PsiBasedModCommandAction { private final @IntentionName String myMessage; public GoToSymbolFix(@NotNull NavigatablePsiElement symbol, @NotNull @Nls String message) { - myPointer = SmartPointerManager.getInstance(symbol.getProject()).createSmartPsiElementPointer(symbol); + super(symbol); myMessage = message; } @NotNull @Override - public String getText() { + public String getFamilyName() { return myMessage; } - @NotNull @Override - public String getFamilyName() { - return getText(); + protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull NavigatablePsiElement element) { + return new ModNavigate(element.getContainingFile().getVirtualFile(), 0, 0, 0); } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return myPointer.getElement() != null; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - NavigatablePsiElement e = myPointer.getElement(); - if (e != null && e.isValid()) { - e.navigate(true); - } - } - - @Override - public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { - NavigatablePsiElement element = myPointer.getElement(); - if (element == null) return IntentionPreviewInfo.EMPTY; + protected @NotNull IntentionPreviewInfo generatePreview(ActionContext context, NavigatablePsiElement element) { return IntentionPreviewInfo.navigate(element); } - - @Override - public boolean startInWriteAction() { - return false; - } } \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveParenthesisFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveParenthesisFix.java index 1112aff865e5..ccccbe43b168 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveParenthesisFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveParenthesisFix.java @@ -1,74 +1,51 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 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.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.HighPriorityAction; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.codeInsight.intention.PriorityAction; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.codeInspection.util.IntentionFamilyName; -import com.intellij.codeInspection.util.IntentionName; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import com.siyeh.ig.psiutils.CommentTracker; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import org.jetbrains.annotations.NotNull; -import java.util.List; import java.util.Objects; -public final class MoveParenthesisFix implements IntentionAction, HighPriorityAction { - private final PsiCallExpression myCall; +public final class MoveParenthesisFix extends PsiUpdateModCommandAction { private final int myPos; private final int myShiftSize; public MoveParenthesisFix(PsiCallExpression call, int pos, int shiftSize) { - myCall = call; + super(call); myPos = pos; myShiftSize = shiftSize; } @Override - public @IntentionName @NotNull String getText() { + public @NotNull @IntentionFamilyName String getFamilyName() { return QuickFixBundle.message("intention.move.parenthesis.name"); } @Override - public @NotNull @IntentionFamilyName String getFamilyName() { - return getText(); + protected @NotNull Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiCallExpression element) { + return Presentation.of(getFamilyName()).withPriority(PriorityAction.Priority.HIGH); } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return !project.isDisposed() && myCall.isValid() && BaseIntentionAction.canModify(myCall); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - PsiCallExpression copy = copyWithShift(myCall, myPos, myShiftSize); + protected void invoke(@NotNull ActionContext context, @NotNull PsiCallExpression call, @NotNull ModPsiUpdater updater) { + PsiCallExpression copy = copyWithShift(call, myPos, myShiftSize); if (copy != null) { - new CommentTracker().replaceAndRestoreComments(myCall, copy); + new CommentTracker().replaceAndRestoreComments(call, copy); } } - - @Override - public boolean startInWriteAction() { - return true; - } - - @Override - public @NotNull FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new MoveParenthesisFix(PsiTreeUtil.findSameElementInCopy(myCall, target), myPos, myShiftSize); - } private static PsiCallExpression copyWithShift(PsiCallExpression parentCall, int pos, int shift) { PsiCallExpression parentCopy = (PsiCallExpression)parentCall.copy(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/DeprecationInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/DeprecationInspectionBase.java index d29aa645ed75..8a7d88bf3b3a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/DeprecationInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/DeprecationInspectionBase.java @@ -100,7 +100,7 @@ public abstract class DeprecationInspectionBase extends LocalInspectionTool { if (deprecatedElement instanceof PsiMethod method && methodCall != null) { PsiMethod replacement = findReplacementInJavaDoc(method, methodCall); if (replacement != null) { - return new ReplaceMethodCallFix((PsiMethodCallExpression)elementToHighlight.getParent().getParent(), replacement); + return new ReplaceMethodCallFix((PsiMethodCallExpression)elementToHighlight.getParent().getParent(), replacement).asQuickFix(); } } if (deprecatedElement instanceof PsiField field) { @@ -108,7 +108,7 @@ public abstract class DeprecationInspectionBase extends LocalInspectionTool { if (referenceExpression != null) { PsiMember replacement = findReplacementInJavaDoc(field, referenceExpression); if (replacement != null) { - return new ReplaceFieldReferenceFix(referenceExpression, replacement); + return new ReplaceFieldReferenceFix(referenceExpression, replacement).asQuickFix(); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/deprecationInspectionQuickFixes.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/deprecationInspectionQuickFixes.kt index 8eb252a33020..f154fec64707 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/deprecationInspectionQuickFixes.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/deprecationInspectionQuickFixes.kt @@ -1,23 +1,10 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInspection.deprecation -import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview -import com.intellij.codeInspection.LocalQuickFixOnPsiElement -import com.intellij.openapi.project.Project +import com.intellij.codeInspection.PsiUpdateModCommandAction +import com.intellij.modcommand.ModCommandAction +import com.intellij.modcommand.ModCommandAction.Presentation +import com.intellij.modcommand.ModPsiUpdater import com.intellij.psi.* import com.intellij.psi.codeStyle.JavaCodeStyleManager import com.intellij.psi.util.PsiFormatUtil @@ -40,15 +27,15 @@ private fun generateQualifierText(expr: PsiReferenceExpression, } } -internal class ReplaceMethodCallFix(expr: PsiMethodCallExpression, replacementMethod: PsiMethod) : LocalQuickFixOnPsiElement(expr) { - @SafeFieldForPreview +internal class ReplaceMethodCallFix(expr: PsiMethodCallExpression, replacementMethod: PsiMethod) : + PsiUpdateModCommandAction(expr) { private val myReplacementMethodPointer = SmartPointerManager.getInstance(replacementMethod.project).createSmartPsiElementPointer(replacementMethod) private val myReplacementText = PsiFormatUtil.formatMethod(replacementMethod, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_CONTAINING_CLASS or PsiFormatUtilBase.SHOW_NAME, 0) - override fun getText(): String { - return InspectionGadgetsBundle.message("replace.method.call.fix.text", myReplacementText) + override fun getPresentation(context: ModCommandAction.ActionContext, element: PsiMethodCallExpression): Presentation { + return Presentation.of(InspectionGadgetsBundle.message("replace.method.call.fix.text", myReplacementText)) } @Nls @@ -56,12 +43,12 @@ internal class ReplaceMethodCallFix(expr: PsiMethodCallExpression, replacementMe return InspectionGadgetsBundle.message("replace.method.call.fix.family.name") } - override fun invoke(project: Project, file: PsiFile, startElement: PsiElement, endElement: PsiElement) { - val expr = (startElement as? PsiMethodCallExpression) ?: return + override fun invoke(context: ModCommandAction.ActionContext, expr: PsiMethodCallExpression, updater: ModPsiUpdater) { val replacementMethod = myReplacementMethodPointer.element ?: return val qualifierText = generateQualifierText(expr.methodExpression, replacementMethod) + val project = context.project val elementFactory = JavaPsiFacade.getElementFactory(project) val newMethodCall = elementFactory.createExpressionFromText(qualifierText + replacementMethod.name + expr.argumentList.text, expr) val replaced = expr.replace(newMethodCall) as PsiMethodCallExpression @@ -69,8 +56,8 @@ internal class ReplaceMethodCallFix(expr: PsiMethodCallExpression, replacementMe } } -internal class ReplaceFieldReferenceFix(expr: PsiReferenceExpression, replacementMember: PsiMember) : LocalQuickFixOnPsiElement(expr) { - @SafeFieldForPreview +internal class ReplaceFieldReferenceFix(expr: PsiReferenceExpression, replacementMember: PsiMember) : + PsiUpdateModCommandAction(expr) { private val myReplacementMemberPointer = SmartPointerManager.getInstance(replacementMember.project).createSmartPsiElementPointer(replacementMember) private val myReplacementText = @@ -87,16 +74,16 @@ internal class ReplaceFieldReferenceFix(expr: PsiReferenceExpression, replacemen return InspectionGadgetsBundle.message("replace.field.reference.fix.family.name") } - override fun getText(): String { - return InspectionGadgetsBundle.message("replace.field.reference.fix.text", myReplacementText) + override fun getPresentation(context: ModCommandAction.ActionContext, element: PsiReferenceExpression): Presentation { + return Presentation.of(InspectionGadgetsBundle.message("replace.field.reference.fix.text", myReplacementText)) } - override fun invoke(project: Project, file: PsiFile, startElement: PsiElement, endElement: PsiElement) { - val expr = (startElement as? PsiReferenceExpression) ?: return + override fun invoke(context: ModCommandAction.ActionContext, expr: PsiReferenceExpression, updater: ModPsiUpdater) { val replacementMember = myReplacementMemberPointer.element ?: return val qualifierText = generateQualifierText(expr, replacementMember) + val project = context.project val replaced = expr.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText( qualifierText + replacementMember.name + (if (replacementMember is PsiMethod) "()" else ""), expr)) JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced) diff --git a/java/java-analysis-impl/src/messages/QuickFixBundle.properties b/java/java-analysis-impl/src/messages/QuickFixBundle.properties index 181c48217adc..e4e51b335c5a 100644 --- a/java/java-analysis-impl/src/messages/QuickFixBundle.properties +++ b/java/java-analysis-impl/src/messages/QuickFixBundle.properties @@ -187,7 +187,7 @@ move.class.to.package.family=Move Class to Package move.class.to.package.text=Move to package ''{0}'' # change if (!a == b) ... => if (!(a == b)) ... -negation.broader.scope.family=Negation Broader Scope +negation.broader.scope.family=Negation broader scope negation.broader.scope.text=Change to ''!({0})'' optimize.imports.fix=Optimize imports diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/NegationBroadScopeFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/NegationBroadScopeFix.java index 2526b043f072..fd46bff4b37f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/NegationBroadScopeFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/NegationBroadScopeFix.java @@ -2,56 +2,51 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; +import com.intellij.codeInspection.PsiUpdateModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Objects; + /** * if (!a == b) ... => if (!(a == b)) ... */ -public class NegationBroadScopeFix implements IntentionAction { - private final PsiPrefixExpression myPrefixExpression; - +public class NegationBroadScopeFix extends PsiUpdateModCommandAction { public NegationBroadScopeFix(@NotNull PsiPrefixExpression prefixExpression) { - myPrefixExpression = prefixExpression; + super(prefixExpression); } @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new NegationBroadScopeFix(PsiTreeUtil.findSameElementInCopy(myPrefixExpression, target)); - } + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiPrefixExpression expression) { + PsiExpression operand = expression.getOperand(); + if (operand == null) return null; - @Override - @NotNull - public String getText() { - PsiExpression operand = myPrefixExpression.getOperand(); - String text = operand == null ? "" : operand.getText() + " "; - PsiElement parent = myPrefixExpression.getParent(); + PsiElement parent = expression.getParent(); + String text = operand.getText() + " "; String rop; - if (parent instanceof PsiInstanceOfExpression) { + if (parent instanceof PsiInstanceOfExpression instanceOf) { + if (instanceOf.getOperand() != expression) return null; text += PsiKeyword.INSTANCEOF + " "; - final PsiTypeElement typeElement = ((PsiInstanceOfExpression)parent).getCheckType(); + final PsiTypeElement typeElement = instanceOf.getCheckType(); rop = typeElement == null ? "" : typeElement.getText(); } - else if (parent instanceof PsiBinaryExpression) { - text += ((PsiBinaryExpression)parent).getOperationSign().getText() + " "; - final PsiExpression rOperand = ((PsiBinaryExpression)parent).getROperand(); + else if (parent instanceof PsiBinaryExpression binaryExpression) { + if (binaryExpression.getLOperand() != expression) return null; + if (!TypeConversionUtil.isBooleanType(binaryExpression.getType())) return null; + text += binaryExpression.getOperationSign().getText() + " "; + final PsiExpression rOperand = binaryExpression.getROperand(); rop = rOperand == null ? "" : rOperand.getText(); } else { - rop = ""; + return null; } text += rop; - return QuickFixBundle.message("negation.broader.scope.text", text); + return Presentation.of(QuickFixBundle.message("negation.broader.scope.text", text)); } @Override @@ -61,40 +56,15 @@ public class NegationBroadScopeFix implements IntentionAction { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - if (!myPrefixExpression.isValid() || myPrefixExpression.getOperand() == null) return false; - - PsiElement parent = myPrefixExpression.getParent(); - if (parent instanceof PsiInstanceOfExpression && ((PsiInstanceOfExpression)parent).getOperand() == myPrefixExpression) { - return true; - } - return parent instanceof PsiBinaryExpression binaryExpression && - binaryExpression.getLOperand() == myPrefixExpression && - TypeConversionUtil.isBooleanType(binaryExpression.getType()); - } - - @NotNull - @Override - public PsiElement getElementToMakeWritable(@NotNull PsiFile file) { - return myPrefixExpression.getContainingFile(); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - if (!isAvailable(project, editor, file)) return; - PsiExpression operand = myPrefixExpression.getOperand(); + protected void invoke(@NotNull ActionContext context, @NotNull PsiPrefixExpression myPrefixExpression, @NotNull ModPsiUpdater updater) { + PsiExpression operand = Objects.requireNonNull(myPrefixExpression.getOperand()); PsiElement unnegated = myPrefixExpression.replace(operand); PsiElement parent = unnegated.getParent(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(file.getProject()); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.project()); PsiPrefixExpression negated = (PsiPrefixExpression)factory.createExpressionFromText("!(xxx)", parent); - PsiParenthesizedExpression parentheses = (PsiParenthesizedExpression)negated.getOperand(); - parentheses.getExpression().replace(parent.copy()); + PsiParenthesizedExpression parentheses = (PsiParenthesizedExpression)Objects.requireNonNull(negated.getOperand()); + Objects.requireNonNull(parentheses.getExpression()).replace(parent.copy()); parent.replace(negated); } - - @Override - public boolean startInWriteAction() { - return true; - } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InlineStreamMapAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InlineStreamMapAction.java index 6b53808f1afb..106c0ca48395 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InlineStreamMapAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InlineStreamMapAction.java @@ -1,19 +1,17 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.intention.impl; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; -import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.java.JavaBundle; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.impl.source.DummyHolder; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.util.LambdaRefactoringUtil; -import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.ParenthesesUtils; @@ -25,7 +23,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Set; -public class InlineStreamMapAction extends PsiElementBaseIntentionAction { +public class InlineStreamMapAction extends PsiUpdateModCommandAction { private static final Logger LOG = Logger.getInstance(InlineStreamMapAction.class.getName()); public static final class Holder { private static final Set MAP_METHODS = @@ -35,21 +33,23 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction { .of("flatMap", "flatMapToInt", "flatMapToLong", "flatMapToDouble", "forEach", "forEachOrdered", "anyMatch", "noneMatch", "allMatch") .append(MAP_METHODS).toSet(); } + + public InlineStreamMapAction() { + super(PsiIdentifier.class); + } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull final PsiElement element) { - if (!(element instanceof PsiIdentifier)) return false; + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiIdentifier element) { final PsiElement parent = element.getParent(); - if (!(parent instanceof PsiReferenceExpression)) return false; + if (!(parent instanceof PsiReferenceExpression)) return null; final PsiElement gParent = parent.getParent(); - if (!(gParent instanceof PsiMethodCallExpression curCall)) return false; - if (!isMapCall(curCall)) return false; + if (!(gParent instanceof PsiMethodCallExpression curCall)) return null; + if (!isMapCall(curCall)) return null; PsiMethodCallExpression nextCall = getNextExpressionToMerge(curCall); - if(nextCall == null) return false; + if(nextCall == null) return null; String key = curCall.getArgumentList().isEmpty() || nextCall.getArgumentList().isEmpty() ? "intention.inline.map.merge.text" : "intention.inline.map.inline.text"; - setText(JavaBundle.message(key, element.getText(), nextCall.getMethodExpression().getReferenceName())); - return true; + return Presentation.of(JavaBundle.message(key, element.getText(), nextCall.getMethodExpression().getReferenceName())); } private static boolean isMapCall(@NotNull PsiMethodCallExpression methodCallExpression) { @@ -165,7 +165,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction { } @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + protected void invoke(@NotNull ActionContext context, @NotNull PsiIdentifier element, @NotNull ModPsiUpdater updater) { PsiMethodCallExpression mapCall = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class); if(mapCall == null) return; @@ -190,7 +190,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction { CommentTracker ct = new CommentTracker(); - if (!lambda.isPhysical() && !IntentionPreviewUtils.isPreviewElement(lambda)) { + if (lambda.getContainingFile() instanceof DummyHolder) { lambda = (PsiLambdaExpression)nextCall.getArgumentList().add(lambda); } PsiElement body = lambda.getBody(); @@ -201,7 +201,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction { LOG.assertTrue(nextParameters.length == 1); PsiParameter[] prevParameters = previousLambda.getParameterList().getParameters(); LOG.assertTrue(prevParameters.length == 1); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.project()); for(PsiReferenceExpression ref : VariableAccessUtils.getVariableReferences(nextParameters[0], body)) { PsiExpression replacement = ct.markUnchanged(previousBody); if (ref.getParent() instanceof PsiExpression && @@ -221,7 +221,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction { } else { ct.replaceAndRestoreComments(nextQualifier, prevQualifier); } - CodeStyleManager.getInstance(project).reformat(lambda); + CodeStyleManager.getInstance(context.project()).reformat(lambda); } @Nullable diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java index 607b0a5dc545..7da9a1d6d0a8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java @@ -295,7 +295,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @NotNull @Override public IntentionAction createNegationBroadScopeFix(@NotNull PsiPrefixExpression expr) { - return new NegationBroadScopeFix(expr); + return new NegationBroadScopeFix(expr).asIntention(); } @NotNull diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/negationBroadScope/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/negationBroadScope/after1.java index 518a8eeb3e63..0ace2c15e091 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/negationBroadScope/after1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/negationBroadScope/after1.java @@ -1,6 +1,6 @@ // "Change to '!(1 == 1)'" "true-preview" public class Foo { void task() { - if (!(1 == 1)) {} + if (!(1 == 1)) {} } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java index af7b789f81ca..acd6199eebfc 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java @@ -1,45 +1,31 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ig.inheritance; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.QuickFixFactory; -import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; +import com.intellij.codeInspection.ModCommands; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.java.analysis.JavaAnalysisBundle; -import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.ModCommandQuickFix; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.impl.DebugUtil; -import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; -import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.ClassUtils; import org.jetbrains.annotations.NotNull; -class StaticInheritanceFix extends InspectionGadgetsFix { +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +class StaticInheritanceFix extends ModCommandQuickFix { private final boolean myReplaceInWholeProject; StaticInheritanceFix(boolean replaceInWholeProject) { @@ -61,17 +47,8 @@ class StaticInheritanceFix extends InspectionGadgetsFix { } @Override - public boolean startInWriteAction() { - return false; - } - - @Override - public void doFix(final @NotNull Project project, @NotNull ProblemDescriptor descriptor) { - doFix(project, descriptor, false); - } - - private void doFix(final Project project, ProblemDescriptor descriptor, boolean inPreview) { - final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)descriptor.getPsiElement(); + public @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)descriptor.getStartElement(); final PsiClass iface = (PsiClass)referenceElement.resolve(); assert iface != null; final PsiField[] allFields = iface.getAllFields(); @@ -80,83 +57,58 @@ class StaticInheritanceFix extends InspectionGadgetsFix { assert implementingClass != null; final PsiFile file = implementingClass.getContainingFile(); - if (inPreview) { - processUsages(allFields, implementingClass, project, true, iface, file); - } else { - ProgressManager.getInstance().run(new Task.Modal(project, - JavaAnalysisBundle.message("static.inheritrance.fix.replace.progress", iface.getName()), false) { - - @Override - public void run(@NotNull ProgressIndicator indicator) { - processUsages(allFields, implementingClass, project, false, iface, file); - } - }); - } + return ModCommands.psiUpdate(ModCommandAction.ActionContext.from(descriptor), updater -> + processUsages(allFields, implementingClass, project, iface, file, updater)); } - private void processUsages(PsiField[] allFields, - PsiClass implementingClass, - Project project, - boolean inPreview, - PsiClass iface, - PsiFile file) { + private void processUsages(@NotNull PsiField @NotNull [] allFields, + PsiClass implementingClass, + Project project, + PsiClass iface, + PsiFile file, + @NotNull ModPsiUpdater updater) { + Map replacements = findReplacements(allFields, implementingClass, updater); + PsiClassType classType = JavaPsiFacade.getInstance(project).getElementFactory().createType(iface); + IntentionAction fix = QuickFixFactory.getInstance().createExtendsListFix(updater.getWritable(implementingClass), classType, false); + fix.invoke(project, null, file); + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); + replacements.forEach((referenceExpression, containingClass) -> { + final PsiReferenceExpression qualified = (PsiReferenceExpression) + elementFactory.createExpressionFromText("xxx." + referenceExpression.getText(), referenceExpression); + final PsiReferenceExpression newReference = (PsiReferenceExpression)referenceExpression.replace(qualified); + final PsiReferenceExpression qualifier = (PsiReferenceExpression)newReference.getQualifierExpression(); + assert qualifier != null : DebugUtil.psiToString(newReference, true); + qualifier.bindToElement(containingClass); + }); + } + + @NotNull + private Map findReplacements(@NotNull PsiField @NotNull [] allFields, + @NotNull PsiClass implementingClass, + @NotNull ModPsiUpdater updater) { + Map replacements = new LinkedHashMap<>(); for (final PsiField field : allFields) { - SearchScope scope = ReadAction.compute(() -> implementingClass.getUseScope()); - if (inPreview) { - scope = scope.intersectWith(new LocalSearchScope(file)); - } + SearchScope scope = implementingClass.getUseScope(); final Query search = ReferencesSearch.search(field, scope, false); for (PsiReference reference : search) { if (!(reference instanceof PsiReferenceExpression referenceExpression)) { continue; } if (!myReplaceInWholeProject) { - boolean isInheritor = - ReadAction.compute(() -> { - boolean isInheritor1 = false; - PsiClass aClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class); - while (aClass != null) { - isInheritor1 = InheritanceUtil.isInheritorOrSelf(aClass, implementingClass, true); - if (isInheritor1) break; - aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class); - } - return isInheritor1; - }); + boolean isInheritor = false; + PsiClass aClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class); + while (aClass != null) { + isInheritor = InheritanceUtil.isInheritorOrSelf(aClass, implementingClass, true); + if (isInheritor) break; + aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class); + } if (!isInheritor) continue; } - final Runnable runnable = () -> { - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); - final PsiReferenceExpression qualified = (PsiReferenceExpression) - elementFactory.createExpressionFromText("xxx." + referenceExpression.getText(), referenceExpression); - final PsiReferenceExpression newReference = (PsiReferenceExpression)referenceExpression.replace(qualified); - final PsiReferenceExpression qualifier = (PsiReferenceExpression)newReference.getQualifierExpression(); - assert qualifier != null : DebugUtil.psiToString(newReference, true); - final PsiClass containingClass = field.getContainingClass(); - qualifier.bindToElement(containingClass); - }; - if (inPreview) { - runnable.run(); - } else { - WriteCommandAction.runWriteCommandAction(project, null, null, runnable, - ReadAction.compute(() -> referenceExpression.getContainingFile())); - } + + final PsiClass containingClass = Objects.requireNonNull(field.getContainingClass()); + replacements.put(updater.getWritable(referenceExpression), containingClass); } } - final Runnable runnable = () -> { - PsiClassType classType = JavaPsiFacade.getInstance(project).getElementFactory().createType(iface); - IntentionAction fix = QuickFixFactory.getInstance().createExtendsListFix(implementingClass, classType, false); - fix.invoke(project, null, file); - }; - if (inPreview) { - runnable.run(); - } else { - WriteCommandAction.runWriteCommandAction(project, null, null, runnable, file); - } - } - - @Override - public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) { - doFix(project, previewDescriptor, true); - return IntentionPreviewInfo.DIFF; + return replacements; } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceInspection.java index 7636504368c3..a4efa40f8775 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceInspection.java @@ -15,6 +15,7 @@ */ package com.siyeh.ig.inheritance; +import com.intellij.codeInspection.LocalQuickFix; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiJavaCodeReferenceElement; @@ -22,7 +23,6 @@ import com.intellij.psi.PsiReferenceList; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; -import com.siyeh.ig.InspectionGadgetsFix; import org.jetbrains.annotations.NotNull; import java.util.HashSet; @@ -38,8 +38,8 @@ public class StaticInheritanceInspection extends BaseInspection { } @Override - protected InspectionGadgetsFix @NotNull [] buildFixes(Object... infos) { - return new InspectionGadgetsFix[]{new StaticInheritanceFix(false), new StaticInheritanceFix(true)}; + protected LocalQuickFix @NotNull [] buildFixes(Object... infos) { + return new LocalQuickFix[]{new StaticInheritanceFix(false), new StaticInheritanceFix(true)}; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/datetime/ShowDateTimeExampleOutputIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/datetime/ShowDateTimeExampleOutputIntention.java index a77c6021e435..9f1680f18b01 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/datetime/ShowDateTimeExampleOutputIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/datetime/ShowDateTimeExampleOutputIntention.java @@ -1,19 +1,18 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ipp.datetime; -import com.intellij.codeInsight.hint.HintManager; -import com.intellij.codeInsight.intention.HighPriorityAction; -import com.intellij.openapi.editor.Editor; +import com.intellij.codeInsight.intention.PriorityAction; +import com.intellij.codeInspection.ModCommands; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.PsiBasedModCommandAction; import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiUtil; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ig.callMatcher.CallMatcher; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.TypeUtils; -import com.siyeh.ipp.base.Intention; -import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.text.SimpleDateFormat; import java.time.LocalDateTime; @@ -25,7 +24,11 @@ import static com.siyeh.ig.callMatcher.CallMatcher.*; /** * @author Bas Leijdekkers */ -public class ShowDateTimeExampleOutputIntention extends Intention implements HighPriorityAction { +public class ShowDateTimeExampleOutputIntention extends PsiBasedModCommandAction { + + public ShowDateTimeExampleOutputIntention() { + super(PsiExpression.class); + } private static final CallMatcher DATE_TIME_FORMATTER_METHODS = anyOf( staticCall("java.time.format.DateTimeFormatter", "ofPattern"), @@ -33,107 +36,87 @@ public class ShowDateTimeExampleOutputIntention extends Intention implements Hig ); private static final CallMatcher SIMPLE_DATE_FORMAT_METHODS = instanceCall("java.text.SimpleDateFormat", "applyPattern", "applyLocalizedPattern").parameterTypes(CommonClassNames.JAVA_LANG_STRING); - Boolean dateTimeFormatter = null; @Override public @NotNull String getFamilyName() { return IntentionPowerPackBundle.message("show.example.date.time.output.intention.family.name"); } + enum Formatter { + NONE, DATE_TIME_FORMATTER, SIMPLE_DATE_FORMAT + } + + private static @NotNull Formatter getFormatter(@NotNull PsiExpression expression) { + if (!(expression.getParent() instanceof PsiExpressionList parent)) return Formatter.NONE; + final PsiType type = expression.getType(); + if (!TypeUtils.isJavaLangString(type)) return Formatter.NONE; + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiMethodCallExpression call) { + if (SIMPLE_DATE_FORMAT_METHODS.test(call)) { + return Formatter.SIMPLE_DATE_FORMAT; + } + if (DATE_TIME_FORMATTER_METHODS.test(call)) { + return Formatter.DATE_TIME_FORMATTER; + } + return Formatter.NONE; + } + if (grandParent instanceof PsiNewExpression newExpression) { + final PsiJavaCodeReferenceElement classReference = newExpression.getClassReference(); + if (classReference == null || !"SimpleDateFormat".equals(classReference.getReferenceName())) { + return Formatter.NONE; + } + final PsiElement target = classReference.resolve(); + if (!(target instanceof PsiClass aClass)) { + return Formatter.NONE; + } + if (!InheritanceUtil.isInheritor(aClass, "java.text.SimpleDateFormat")) { + return Formatter.NONE; + } + return Formatter.SIMPLE_DATE_FORMAT; + } + return Formatter.NONE; + } + @Override - public @NotNull String getText() { - return getFamilyName(); + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiExpression expression) { + while (expression.getParent() instanceof PsiExpression parent) { + expression = parent; + } + Formatter formatter = getFormatter(expression); + if (formatter == Formatter.NONE) return null; + final Object value = ExpressionUtils.computeConstantExpression(expression); + return value instanceof String ? Presentation.of(getFamilyName()).withPriority(PriorityAction.Priority.HIGH) : null; } @Override - public boolean startInWriteAction() { - return false; - } - - @Override - protected @NotNull PsiElementPredicate getElementPredicate() { - return new PsiElementPredicate() { - @Override - public boolean satisfiedBy(PsiElement element) { - if (!(element instanceof PsiExpression expression)) { - return false; + protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull PsiExpression expression) { + while (expression.getParent() instanceof PsiExpression parent) { + expression = parent; + } + Formatter formatter = getFormatter(expression); + final Object value = ExpressionUtils.computeConstantExpression(expression); + if (!(value instanceof String)) return ModCommands.nop(); + return switch (formatter) { + case NONE -> ModCommands.nop(); + case DATE_TIME_FORMATTER -> { + try { + final DateTimeFormatter fmt = DateTimeFormatter.ofPattern((String)value); + //noinspection HardCodedStringLiteral + yield ModCommands.info(LocalDateTime.now().format(fmt)); } - final PsiType type = expression.getType(); - if (!TypeUtils.isJavaLangString(type)) { - return false; + catch (IllegalArgumentException e) { + yield ModCommands.error(IntentionPowerPackBundle.message("invalid.pattern.hint.text")); } - PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression).getParent(); - if (parent == null) return false; - final PsiElement grandParent = parent.getParent(); - if (grandParent instanceof PsiMethodCallExpression) { - if (SIMPLE_DATE_FORMAT_METHODS.test((PsiMethodCallExpression)grandParent)) { - dateTimeFormatter = false; - } - else if (DATE_TIME_FORMATTER_METHODS.test((PsiMethodCallExpression)grandParent)) { - dateTimeFormatter = true; - } - else { - return false; - } + } + case SIMPLE_DATE_FORMAT -> { + try { + final SimpleDateFormat format = new SimpleDateFormat((String)value); + yield ModCommands.info(format.format(new Date())); } - else if (grandParent instanceof PsiNewExpression newExpression) { - final PsiJavaCodeReferenceElement classReference = newExpression.getClassReference(); - if (classReference == null || !"SimpleDateFormat".equals(classReference.getReferenceName())) { - return false; - } - final PsiElement target = classReference.resolve(); - if (!(target instanceof PsiClass aClass)) { - return false; - } - if (!InheritanceUtil.isInheritor(aClass, "java.text.SimpleDateFormat")) { - return false; - } - dateTimeFormatter = false; - return true; + catch (IllegalArgumentException e) { + yield ModCommands.error(IntentionPowerPackBundle.message("invalid.pattern.hint.text")); } - else { - return false; - } - final Object value = ExpressionUtils.computeConstantExpression(expression); - return value instanceof String; } }; } - - @Override - protected void processIntention(Editor editor, @NotNull PsiElement element) { - if (!(element instanceof PsiExpression expression) || dateTimeFormatter == null) { - return; - } - final Object value = ExpressionUtils.computeConstantExpression(expression); - if (!(value instanceof String)) { - return; - } - String example; - if (dateTimeFormatter) { - try { - final DateTimeFormatter formatter = DateTimeFormatter.ofPattern((String)value); - //noinspection HardCodedStringLiteral - example = LocalDateTime.now().format(formatter); - } - catch (IllegalArgumentException e) { - example = IntentionPowerPackBundle.message("invalid.pattern.hint.text"); - } - } - else { - try { - final SimpleDateFormat format = new SimpleDateFormat((String)value); - example = format.format(new Date()); - } - catch (IllegalArgumentException e) { - example = IntentionPowerPackBundle.message("invalid.pattern.hint.text"); - } - } - HintManager.getInstance().showInformationHint(editor, example); - } - - @Override - protected void processIntention(@NotNull PsiElement element) { - assert false; - } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassAnnotator.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassAnnotator.java index ce550f737ee8..3e0661a26d23 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassAnnotator.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassAnnotator.java @@ -1,20 +1,18 @@ -// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.uiDesigner.binding; -import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.daemon.impl.quickfix.DeleteElementFix; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.ui.UIBundle; import com.intellij.uiDesigner.UIDesignerBundle; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Objects; public class FormClassAnnotator implements Annotator { @@ -30,7 +28,7 @@ public class FormClassAnnotator implements Annotator { } else if (psiElement instanceof PsiClass aClass) { final List formsBoundToClass = FormClassIndex.findFormsBoundToClass(aClass.getProject(), aClass); - if (formsBoundToClass.size() > 0) { + if (!formsBoundToClass.isEmpty()) { holder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(aClass.getNameIdentifier()).gutterIconRenderer(new BoundIconRenderer(aClass)).create(); } } @@ -54,37 +52,9 @@ public class FormClassAnnotator implements Annotator { if (field.hasInitializer()) { final String message = UIDesignerBundle.message("field.is.overwritten.by.generated.code", field.getName()); - holder.newAnnotation(HighlightSeverity.WARNING, message).range(field.getInitializer()) - .withFix(new IntentionAction() { - @Override - @NotNull - public String getText() { - return message; - } - - @Override - @NotNull - public String getFamilyName() { - return UIBundle.message("remove.field.initializer.quick.fix"); - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return field.getInitializer() != null; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - final PsiExpression initializer = field.getInitializer(); - LOG.assertTrue(initializer != null); - initializer.delete(); - } - - @Override - public boolean startInWriteAction() { - return true; - } - }).create(); + PsiExpression initializer = Objects.requireNonNull(field.getInitializer()); + holder.newAnnotation(HighlightSeverity.WARNING, message).range(initializer) + .withFix(new DeleteElementFix(initializer, UIBundle.message("remove.field.initializer.quick.fix"))).create(); } } } From 3fbeee35b2a95414d3559204e0b2a7cbf377e157 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 30 Jun 2023 18:08:39 +0200 Subject: [PATCH 107/226] [java-inspections] DynamicRegexReplaceableByCompiledPatternFix: mod-command (IDEA-322693), reuse existing constant when possible GitOrigin-RevId: 39f46e2d238ba957add866eb822db1970ffe4250 --- ...eplaceableByCompiledPatternInspection.java | 92 +++++++++---------- .../ReplaceAll.after.java | 14 +++ .../ReplaceAll.java | 9 ++ ...exReplaceableByCompiledPatternFixTest.java | 24 ++--- 4 files changed, 76 insertions(+), 63 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_compiled_pattern/ReplaceAll.after.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_compiled_pattern/ReplaceAll.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/DynamicRegexReplaceableByCompiledPatternInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/DynamicRegexReplaceableByCompiledPatternInspection.java index fc4a141a637b..48f02a59c9ba 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/DynamicRegexReplaceableByCompiledPatternInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/DynamicRegexReplaceableByCompiledPatternInspection.java @@ -1,24 +1,24 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ig.performance; -import com.intellij.codeInsight.CodeInsightUtilCore; -import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.PsiUpdateModCommandQuickFix; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.impl.AllowedApiFilterExtension; import com.intellij.psi.util.PsiUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; -import com.siyeh.ig.InspectionGadgetsFix; -import com.siyeh.ig.psiutils.ClassUtils; -import com.siyeh.ig.psiutils.CommentTracker; -import com.siyeh.ig.psiutils.ExpressionUtils; -import com.siyeh.ig.psiutils.HighlightUtils; +import com.siyeh.ig.psiutils.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.util.Collection; +import java.util.List; import java.util.Set; import java.util.regex.Matcher; @@ -29,7 +29,7 @@ public class DynamicRegexReplaceableByCompiledPatternInspection extends BaseInsp ); @Override - protected InspectionGadgetsFix buildFix(Object... infos) { + protected LocalQuickFix buildFix(Object... infos) { return new DynamicRegexReplaceableByCompiledPatternFix(); } @@ -40,17 +40,12 @@ public class DynamicRegexReplaceableByCompiledPatternInspection extends BaseInsp "dynamic.regex.replaceable.by.compiled.pattern.problem.descriptor"); } - @Override - protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { - return true; - } - @Override public BaseInspectionVisitor buildVisitor() { return new DynamicRegexReplaceableByCompiledPatternVisitor(); } - private static class DynamicRegexReplaceableByCompiledPatternFix extends InspectionGadgetsFix { + private static class DynamicRegexReplaceableByCompiledPatternFix extends PsiUpdateModCommandQuickFix { @Override @NotNull @@ -60,8 +55,7 @@ public class DynamicRegexReplaceableByCompiledPatternInspection extends BaseInsp } @Override - protected void doFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - final PsiElement element = descriptor.getPsiElement(); + protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) { final PsiClass aClass = ClassUtils.getContainingStaticClass(element); if (aClass == null) { return; @@ -76,21 +70,33 @@ public class DynamicRegexReplaceableByCompiledPatternInspection extends BaseInsp } final PsiExpressionList list = methodCallExpression.getArgumentList(); final PsiExpression[] expressions = list.getExpressions(); + if (expressions.length == 0) return; CommentTracker commentTracker = new CommentTracker(); - @NonNls final StringBuilder fieldText = - new StringBuilder("private static final java.util.regex.Pattern PATTERN = java.util.regex.Pattern.compile("); - final int expressionsLength = expressions.length; - if (expressionsLength > 0) { - fieldText.append(commentTracker.text(expressions[0])); - } - @NonNls final String methodName = methodExpression.getReferenceName(); + final String methodName = methodExpression.getReferenceName(); final boolean literalReplacement = "replace".equals(methodName); - if (literalReplacement) { - fieldText.append(", java.util.regex.Pattern.LITERAL"); + String regexpText = commentTracker.text(expressions[0]); + String initializer = "java.util.regex.Pattern.compile(" + regexpText + + (literalReplacement ? ", java.util.regex.Pattern.LITERAL" : "") + ")"; + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + List names = new VariableNameGenerator(aClass, VariableKind.STATIC_FINAL_FIELD) + .byExpression(factory.createExpressionFromText("__(" + regexpText + ")", null)) + .byName("PATTERN", "REGEX", "REGEXP").generateAll(true); + String name = names.get(0); + String fieldText = "private static final java.util.regex.Pattern " + name + " = "+ initializer + ";"; + final int expressionsLength = expressions.length; + PsiField fieldTemplate = factory.createFieldFromText(fieldText, element); + for (PsiField classField : aClass.getFields()) { + if (classField.hasModifierProperty(PsiModifier.STATIC) && classField.hasModifierProperty(PsiModifier.FINAL) && + fieldTemplate.getType().equals(classField.getType()) && + EquivalenceChecker.getCanonicalPsiEquivalence() + .expressionsAreEquivalent(fieldTemplate.getInitializer(), classField.getInitializer())) { + name = classField.getName(); + fieldTemplate = null; + break; + } } - fieldText.append(");"); - @NonNls final StringBuilder expressionText = new StringBuilder("PATTERN."); + @NonNls final StringBuilder expressionText = new StringBuilder(name + "."); final PsiExpression qualifier = methodExpression.getQualifierExpression(); @NonNls final String qualifierText = (qualifier == null) ? "this" : commentTracker.text(qualifier); if ("split".equals(methodName)) { @@ -130,32 +136,20 @@ public class DynamicRegexReplaceableByCompiledPatternInspection extends BaseInsp expressionText.append(')'); } - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final PsiElement field = aClass.add(factory.createFieldFromText(fieldText.toString(), element)); - PsiMethodCallExpression newMethodCallExpression = - (PsiMethodCallExpression)commentTracker.replaceAndRestoreComments(methodCallExpression, expressionText.toString()); - newMethodCallExpression = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(newMethodCallExpression); - if (newMethodCallExpression == null) return; - final PsiReferenceExpression reference = getReference(newMethodCallExpression); - HighlightUtils.showRenameTemplate(aClass, (PsiNameIdentifierOwner)field, reference); + JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project); + if (fieldTemplate != null) { + PsiField field = (PsiField)aClass.add(fieldTemplate); + field = (PsiField)javaCodeStyleManager.shortenClassReferences(field); + updater.rename(field, names); + } + javaCodeStyleManager.shortenClassReferences( + commentTracker.replaceAndRestoreComments(methodCallExpression, expressionText.toString())); } private static boolean needsQuote(PsiExpression expr) { Object constExprValue = ExpressionUtils.computeConstantExpression(expr); - return !(constExprValue instanceof String) || - Matcher.quoteReplacement((String) constExprValue) != constExprValue; - } - - private static PsiReferenceExpression getReference(PsiMethodCallExpression newMethodCallExpression) { - final PsiReferenceExpression methodExpression = newMethodCallExpression.getMethodExpression(); - final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); - if (qualifierExpression instanceof PsiMethodCallExpression methodCallExpression) { - return getReference(methodCallExpression); - } - if (!(qualifierExpression instanceof PsiReferenceExpression)) { - return null; - } - return (PsiReferenceExpression)qualifierExpression; + return !(constExprValue instanceof String value) || + Matcher.quoteReplacement(value) != constExprValue; } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_compiled_pattern/ReplaceAll.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_compiled_pattern/ReplaceAll.after.java new file mode 100644 index 000000000000..0f2b21af298e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_compiled_pattern/ReplaceAll.after.java @@ -0,0 +1,14 @@ +import java.util.regex.Pattern; + +class Literal { + + private static final Pattern PATTERN = Pattern.compile("https://.+"); + private static final Pattern REGEX = Pattern.compile("http://.+"); + + void f(String text, String replacement) { + REGEX.matcher(text).replaceAll(replacement); + REGEX.matcher(text).replaceAll(replacement); + PATTERN.matcher(text).replaceAll(replacement); + PATTERN.matcher(text).replaceAll(replacement); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_compiled_pattern/ReplaceAll.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_compiled_pattern/ReplaceAll.java new file mode 100644 index 000000000000..a801233301d0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/replace_with_compiled_pattern/ReplaceAll.java @@ -0,0 +1,9 @@ +class Literal { + + void f(String text, String replacement) { + text.replaceAll("http://.+", replacement); + text.replaceAll("http://.+", replacement); + text.replaceAll("https://.+", replacement); + text.replaceAll("https://.+", replacement); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/DynamicRegexReplaceableByCompiledPatternFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/DynamicRegexReplaceableByCompiledPatternFixTest.java index 2303adc0d5f3..497b943b26a3 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/DynamicRegexReplaceableByCompiledPatternFixTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/DynamicRegexReplaceableByCompiledPatternFixTest.java @@ -1,6 +1,8 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ig.fixes.performance; +import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.IGQuickFixesTestCase; import com.siyeh.ig.performance.DynamicRegexReplaceableByCompiledPatternInspection; @@ -13,21 +15,15 @@ public class DynamicRegexReplaceableByCompiledPatternFixTest extends IGQuickFixe myFixture.enableInspections(new DynamicRegexReplaceableByCompiledPatternInspection()); myRelativePath = "performance/replace_with_compiled_pattern"; myDefaultHint = InspectionGadgetsBundle.message("dynamic.regex.replaceable.by.compiled.pattern.quickfix"); - myFixture.addClass(""" - package java.util.regex;public class Pattern { public static Pattern compile(String regex, int flags) { - return null; - } public Matcher matcher(CharSequence input) { return null; }}"""); - myFixture.addClass("package java.util.regex;" + - "public class Matcher {" + - " public String replaceAll(String replacement) {" + - " return \"\";" + - " }" + - " public static String quoteReplacement(String s) {" + - " return s;" + - " }" + - "}"); } public void testLiteral() { doTest(); } public void testLiteralLiteral() { doTest(); } + public void testReplaceAll() { doTest("Fix all 'Dynamic regular expression could be replaced by compiled 'Pattern'' problems in file"); } + + @Override + protected void tuneFixture(JavaModuleFixtureBuilder builder) throws Exception { + super.tuneFixture(builder); + builder.addJdk(IdeaTestUtil.getMockJdk18Path().getPath()); + } } From e6accf54710c2264c5bd50625f45e4bc20e557da Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sat, 1 Jul 2023 08:41:21 +0200 Subject: [PATCH 108/226] [java-inspections] DeleteCatchFix, DeleteElementFix: mod-command (IDEA-322693) GitOrigin-RevId: 1145b22298df2b7a4f7ba0661141cb0952b81d64 --- .../daemon/impl/quickfix/DeleteCatchFix.java | 60 ++++--------------- .../impl/quickfix/DeleteElementFix.java | 42 ++++--------- .../impl/config/QuickFixFactoryImpl.java | 6 +- 3 files changed, 25 insertions(+), 83 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeleteCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeleteCatchFix.java index 04a7067a822a..09eabc2167d3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeleteCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeleteCatchFix.java @@ -1,35 +1,17 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2023 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.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.daemon.impl.actions.IntentionActionWithFixAllOption; import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.impl.BaseIntentionAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; +import com.intellij.codeInspection.PsiUpdateModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.siyeh.ig.psiutils.ControlFlowUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class DeleteCatchFix implements IntentionActionWithFixAllOption { - private final PsiParameter myCatchParameter; +public class DeleteCatchFix extends PsiUpdateModCommandAction { private final String myTypeText; public DeleteCatchFix(@NotNull PsiParameter catchParameter) { @@ -37,16 +19,10 @@ public class DeleteCatchFix implements IntentionActionWithFixAllOption { } private DeleteCatchFix(@NotNull PsiParameter catchParameter, @NotNull String typeText) { - myCatchParameter = catchParameter; + super(catchParameter); myTypeText = typeText; } - @Override - @NotNull - public String getText() { - return QuickFixBundle.message("delete.catch.text", myTypeText); - } - @Override @NotNull public String getFamilyName() { @@ -54,27 +30,16 @@ public class DeleteCatchFix implements IntentionActionWithFixAllOption { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return myCatchParameter.isValid() && BaseIntentionAction.canModify(myCatchParameter); + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiParameter element) { + return Presentation.of(QuickFixBundle.message("delete.catch.text", myTypeText)); } @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new DeleteCatchFix(PsiTreeUtil.findSameElementInCopy(myCatchParameter, target)); - } - - @NotNull - @Override - public PsiElement getElementToMakeWritable(@NotNull PsiFile file) { - return myCatchParameter.getContainingFile(); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) { - PsiElement previousElement = deleteCatch(myCatchParameter); + protected void invoke(@NotNull ActionContext context, @NotNull PsiParameter catchParameter, @NotNull ModPsiUpdater updater) { + PsiElement previousElement = deleteCatch(catchParameter); if (previousElement != null) { //move caret to previous catch section - editor.getCaretModel().moveToOffset(previousElement.getTextRange().getEndOffset()); + updater.moveTo(previousElement.getTextRange().getEndOffset()); } } @@ -132,9 +97,4 @@ public class DeleteCatchFix implements IntentionActionWithFixAllOption { catchSection.delete(); return previousElement; } - - @Override - public boolean startInWriteAction() { - return true; - } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeleteElementFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeleteElementFix.java index 6c57fdd07967..018e6026c094 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeleteElementFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DeleteElementFix.java @@ -1,19 +1,14 @@ // Copyright 2000-2023 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.quickfix; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.CommonQuickFixBundle; +import com.intellij.codeInspection.ModCommands; import com.intellij.codeInspection.PsiUpdateModCommandAction; -import com.intellij.codeInspection.util.IntentionName; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; import com.intellij.modcommand.ModPsiUpdater; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; import com.intellij.psi.util.JavaElementKind; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.psiutils.CommentTracker; import org.jetbrains.annotations.Nls; @@ -50,7 +45,7 @@ public class DeleteElementFix extends PsiUpdateModCommandAction { new CommentTracker().deleteAndRestoreComments(element); } - public static final class DeleteMultiFix implements IntentionAction { + public static final class DeleteMultiFix implements ModCommandAction { private final @NotNull PsiElement @NotNull [] myElements; private @NotNull final @Nls String myMessage; @@ -65,8 +60,8 @@ public class DeleteElementFix extends PsiUpdateModCommandAction { } @Override - public @IntentionName @NotNull String getText() { - return myMessage; + public @NotNull Presentation getPresentation(@NotNull ActionContext context) { + return Presentation.of(myMessage); } @Override @@ -75,25 +70,12 @@ public class DeleteElementFix extends PsiUpdateModCommandAction { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return true; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - for (PsiElement element : myElements) { - new CommentTracker().deleteAndRestoreComments(element); - } - } - - @Override - public boolean startInWriteAction() { - return true; - } - - @Override - public @NotNull FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new DeleteMultiFix(ContainerUtil.map2Array(myElements, PsiElement.class, e -> PsiTreeUtil.findSameElementInCopy(e, target))); + public @NotNull ModCommand perform(@NotNull ActionContext context) { + return ModCommands.psiUpdate(context, updater -> { + for (PsiElement element : ContainerUtil.map(myElements, updater::getWritable)) { + new CommentTracker().deleteAndRestoreComments(element); + } + }); } } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java index 7da9a1d6d0a8..d4f8a56e582c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java @@ -277,7 +277,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @NotNull @Override public IntentionAction createDeleteCatchFix(@NotNull PsiParameter parameter) { - return new DeleteCatchFix(parameter); + return new DeleteCatchFix(parameter).asIntention(); } @NotNull @@ -780,7 +780,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @Override public @NotNull IntentionAction createDeleteFix(@NotNull PsiElement @NotNull ... elements) { - return new DeleteElementFix.DeleteMultiFix(elements); + return new DeleteElementFix.DeleteMultiFix(elements).asIntention(); } @NotNull @@ -1202,6 +1202,6 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @Override public @NotNull IntentionAction createDeleteFix(@NotNull PsiElement @NotNull [] elements, @NotNull @Nls String text) { - return new DeleteElementFix.DeleteMultiFix(elements, text); + return new DeleteElementFix.DeleteMultiFix(elements, text).asIntention(); } } From f35bade00124b06dcef8634592d1438537bee902 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sat, 1 Jul 2023 08:45:03 +0200 Subject: [PATCH 109/226] [java-inspections] EliminateParenthesesIntention: mod-command (IDEA-322693) GitOrigin-RevId: ce1ba85e54fde30e577d46a935e08dc0242db7a2 --- .../intellij/codeInspection/ModCommands.java | 5 ++ .../IntentionPowerPackBundle.properties | 1 + .../EliminateParenthesesIntention.java | 66 ++++++------------- .../EliminateParenthesesIntentionTest.java | 19 +++++- 4 files changed, 43 insertions(+), 48 deletions(-) diff --git a/platform/lang-api/src/com/intellij/codeInspection/ModCommands.java b/platform/lang-api/src/com/intellij/codeInspection/ModCommands.java index fb891bf38859..6041f53d3a64 100644 --- a/platform/lang-api/src/com/intellij/codeInspection/ModCommands.java +++ b/platform/lang-api/src/com/intellij/codeInspection/ModCommands.java @@ -152,6 +152,11 @@ public final class ModCommands { public @NotNull String getFamilyName() { return title; } + + @Override + public String toString() { + return "Step: [" + title + "] " + element.getText(); + } }; } diff --git a/plugins/IntentionPowerPak/resources/messages/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/resources/messages/IntentionPowerPackBundle.properties index aa8674997956..c07570af2668 100644 --- a/plugins/IntentionPowerPak/resources/messages/IntentionPowerPackBundle.properties +++ b/plugins/IntentionPowerPak/resources/messages/IntentionPowerPackBundle.properties @@ -86,6 +86,7 @@ copy.concatenated.string.to.clipboard.intention.family.name=Copy string concaten flip.expression.intention.family.name=Flip binary expression flip.setter.call.intention.family.name=Flip setter call eliminate.parentheses.intention.name=Eliminate parentheses +eliminate.parentheses.intention.title=Eliminate Parentheses reverse.for.loop.direction.intention.family.name=Reverse direction of for loop reverse.for.loop.direction.intention.name=Reverse direction of for loop replace.operator.assignment.with.postfix.expression.intention.family.name=Replace operator assignment with postfix expression diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/expression/eliminate/EliminateParenthesesIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/expression/eliminate/EliminateParenthesesIntention.java index be7d59a7f4bb..2811885c7ca6 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/expression/eliminate/EliminateParenthesesIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/expression/eliminate/EliminateParenthesesIntention.java @@ -1,17 +1,14 @@ -// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ipp.expression.eliminate; -import com.intellij.codeInsight.intention.BaseElementAtCaretIntentionAction; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.NlsContexts; -import com.intellij.openapi.util.Pass; +import com.intellij.codeInspection.ModCommands; +import com.intellij.modcommand.ModChooseAction; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.PsiBasedModCommandAction; import com.intellij.psi.*; import com.intellij.psi.util.PsiExpressionTrimRenderer; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.IntroduceTargetChooser; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.siyeh.IntentionPowerPackBundle; @@ -24,54 +21,33 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; -public final class EliminateParenthesesIntention extends BaseElementAtCaretIntentionAction { - private static final Pass ELIMINATE_CALLBACK = new Pass<>() { - @Override - public void pass(@NotNull PsiParenthesizedExpression expression) { - WriteCommandAction.writeCommandAction(expression.getProject(), expression.getContainingFile()) - .withName(getName()) - .run(() -> replaceExpression(expression)); - } - }; +public final class EliminateParenthesesIntention extends PsiBasedModCommandAction { + public EliminateParenthesesIntention() { + super(PsiJavaToken.class); + } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return getName(); - } - - @NotNull - @Override - public String getText() { - return getName(); - } - - private static @NlsContexts.Command String getName() { return IntentionPowerPackBundle.message("eliminate.parentheses.intention.name"); } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - List possibleInnerExpressions = getPossibleInnerExpressions(element); - return possibleInnerExpressions != null && !possibleInnerExpressions.isEmpty(); + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiJavaToken leaf) { + List possibleInnerExpressions = getPossibleInnerExpressions(leaf); + return possibleInnerExpressions != null && !possibleInnerExpressions.isEmpty() ? Presentation.of( + IntentionPowerPackBundle.message("eliminate.parentheses.intention.name")) : null; } @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - List possibleInnerExpressions = getPossibleInnerExpressions(element); - if (possibleInnerExpressions == null) return; - processInnerExpression(editor, possibleInnerExpressions); - } - - private static void processInnerExpression(@Nullable Editor editor, @NotNull List expressions) { - PsiParenthesizedExpression firstItem = ContainerUtil.getFirstItem(expressions); - if (expressions.size() == 1 || firstItem != null && !firstItem.isPhysical()) { - replaceExpression(expressions.get(0)); - return; - } - if (expressions.isEmpty() || editor == null) return; - IntroduceTargetChooser.showChooser(editor, expressions, ELIMINATE_CALLBACK, new PsiExpressionTrimRenderer.RenderFunction()); + protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull PsiJavaToken leaf) { + List possibleInnerExpressions = getPossibleInnerExpressions(leaf); + if (possibleInnerExpressions == null) return ModCommands.nop(); + List actions = ContainerUtil.map( + possibleInnerExpressions, + expr -> ModCommands.psiUpdateStep(expr, PsiExpressionTrimRenderer.render(expr), (e, u) -> replaceExpression(e))); + return new ModChooseAction(IntentionPowerPackBundle.message("eliminate.parentheses.intention.title"), actions); } private static void replaceExpression(@NotNull PsiParenthesizedExpression parenthesized) { diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/expression/EliminateParenthesesIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/expression/EliminateParenthesesIntentionTest.java index 7ede7d974022..d542681b7875 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/expression/EliminateParenthesesIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/expression/EliminateParenthesesIntentionTest.java @@ -1,9 +1,15 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ipp.expression; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.ModCommandService; +import com.intellij.openapi.application.impl.NonBlockingReadActionImpl; +import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.CaretModel; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ipp.IPPTestCase; +import com.siyeh.ipp.expression.eliminate.EliminateParenthesesIntention; import org.jetbrains.annotations.NotNull; public class EliminateParenthesesIntentionTest extends IPPTestCase { @@ -25,9 +31,16 @@ public class EliminateParenthesesIntentionTest extends IPPTestCase { String testName = getTestName(false); myFixture.configureByFile(testName + ".java"); CaretModel model = myFixture.getEditor().getCaretModel(); + EliminateParenthesesIntention intention = new EliminateParenthesesIntention(); model.runForEachCaret(caret -> { - model.moveToOffset(caret.getOffset()); - myFixture.launchAction(myFixture.findSingleIntention(intentionName)); + ModCommandAction.ActionContext context = ModCommandAction.ActionContext.from(getEditor(), getFile()); + assertNotNull(intention.getPresentation(context)); + ModCommand command = intention.perform(context); + CommandProcessor.getInstance().executeCommand( + getProject(), + () -> ModCommandService.getInstance().executeInBatch(context, command), + "", null); + NonBlockingReadActionImpl.waitForAsyncTaskCompletion(); }); myFixture.checkResultByFile(testName + "_after.java", false); } From c8a22f04ee14c0bf9f2ab226f97bfd23780c3b15 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sat, 1 Jul 2023 10:18:54 +0200 Subject: [PATCH 110/226] [java-inspections] ExtractSetFromComparisonChainAction: mod-command (IDEA-322693) GitOrigin-RevId: c213159456b423ed0ecae09e16fb56567f39417b --- .../ExtractSetFromComparisonChainAction.java | 237 ++++++++---------- .../resources/messages/JavaBundle.properties | 6 +- 2 files changed, 109 insertions(+), 134 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ExtractSetFromComparisonChainAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ExtractSetFromComparisonChainAction.java index 654c14cd62cf..62131e977334 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ExtractSetFromComparisonChainAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ExtractSetFromComparisonChainAction.java @@ -1,32 +1,27 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.intention.impl; -import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.PsiEquivalenceUtil; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; -import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; +import com.intellij.codeInspection.ModCommands; import com.intellij.codeInspection.RemoveRedundantTypeArgumentsUtil; import com.intellij.java.JavaBundle; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ApplicationNamesInfo; -import com.intellij.openapi.application.WriteAction; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ModChooseAction; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.ThrowableRunnable; +import com.intellij.util.ThreeState; +import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.psiutils.ClassUtils; import com.siyeh.ig.psiutils.EqualityCheck; import com.siyeh.ig.psiutils.ExpressionUtils; @@ -42,7 +37,7 @@ import java.util.*; import static com.intellij.util.ObjectUtils.tryCast; -public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntentionAction { +public class ExtractSetFromComparisonChainAction implements ModCommandAction { private static class Holder { private static final String GUAVA_IMMUTABLE_SET = "com.google.common.collect.ImmutableSet"; private static final String INITIALIZER_FORMAT_GUAVA = GUAVA_IMMUTABLE_SET + ".of({0})"; @@ -59,107 +54,60 @@ public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntention CommonClassNames.JAVA_UTIL_COLLECTIONS + ".unmodifiableSet(" + "java.util.EnumSet.of({0}))"; } - @Override - public boolean startInWriteAction() { - return false; + + private final @NotNull ThreeState myProcessDuplicates; + + public ExtractSetFromComparisonChainAction() { + myProcessDuplicates = ThreeState.UNSURE; + } + + private ExtractSetFromComparisonChainAction(boolean processDuplicates) { + myProcessDuplicates = ThreeState.fromBoolean(processDuplicates); } @Override - public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { - PsiElement element = getElement(editor, file); - if (element == null) return IntentionPreviewInfo.EMPTY; - extract(project, editor, element); - return IntentionPreviewInfo.DIFF; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return; - - PsiDocumentManager.getInstance(project).commitAllDocuments(); - - extract(project, editor, element); - } - - private void extract(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - boolean preview = !element.isPhysical(); + public @NotNull ModCommand perform(@NotNull ActionContext actionContext) { + PsiElement element = actionContext.findLeaf(); List comparisons = comparisons(element).toList(); - if (comparisons.size() < 2) return; + if (comparisons.size() < 2) return ModCommands.nop(); PsiClass containingClass = ClassUtils.getContainingStaticClass(element); - if (containingClass == null) return; - ExpressionToConstantReplacementContext context = new ExpressionToConstantReplacementContext(comparisons); - List copies = findCopies(comparisons, containingClass); - JavaCodeStyleManager manager = JavaCodeStyleManager.getInstance(project); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + if (containingClass == null) return ModCommands.nop(); + List copies = + myProcessDuplicates == ThreeState.NO ? List.of() : findCopies(comparisons, containingClass); + if (myProcessDuplicates == ThreeState.UNSURE && !copies.isEmpty()) { + return new ModChooseAction(JavaBundle.message("intention.extract.set.from.comparison.chain.popup.title"), + List.of(new ExtractSetFromComparisonChainAction(false), + new ExtractSetFromComparisonChainAction(true))); + } LinkedHashSet suggestions = getSuggestions(comparisons); - class Extractor implements ThrowableRunnable { - SmartPsiElementPointer resultPtr; - SmartPsiElementPointer fieldPtr; + return ModCommands.psiUpdate(containingClass, (cls, updater) -> { + Project project = cls.getProject(); + ExpressionToConstantReplacementContext context = new ExpressionToConstantReplacementContext(comparisons).getWritable(updater); + List writableCopies = ContainerUtil.map(copies, copy -> copy.getWritable(updater)); - @Override - public void run() { - if (!containingClass.isValid()) return; - String name = manager.suggestUniqueVariableName(suggestions.iterator().next(), containingClass, false); - String fieldInitializer = context.myInitializer; - PsiType elementType = context.myTypePtr.getType(); - if (elementType == null) return; - String pattern = getInitializer(elementType, containingClass); - String initializer = MessageFormat.format(pattern, fieldInitializer, elementType.getCanonicalText()); - String modifiers = containingClass.isInterface() ? "" : "private static final "; - String type = CommonClassNames.JAVA_UTIL_SET + - (PsiUtil.isLanguageLevel5OrHigher(containingClass) ? "<" + elementType.getCanonicalText() + ">" : ""); - PsiField field = factory.createFieldFromText(modifiers + type + " " + name + "=" + initializer + ";", containingClass); - field = (PsiField)containingClass.add(field); - RemoveRedundantTypeArgumentsUtil.removeRedundantTypeArguments(field); - CodeStyleManager.getInstance(project).reformat(manager.shortenClassReferences(field)); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + JavaCodeStyleManager manager = JavaCodeStyleManager.getInstance(project); + String name = manager.suggestUniqueVariableName(suggestions.iterator().next(), cls, false); + String fieldInitializer = context.myInitializer; + PsiType elementType = context.myType; + if (elementType == null) return; + String pattern = getInitializer(elementType, cls); + String initializer = MessageFormat.format(pattern, fieldInitializer, elementType.getCanonicalText()); + String modifiers = cls.isInterface() ? "" : "private static final "; + String type = CommonClassNames.JAVA_UTIL_SET + + (PsiUtil.isLanguageLevel5OrHigher(cls) ? "<" + elementType.getCanonicalText() + ">" : ""); + PsiField field = factory.createFieldFromText(modifiers + type + " " + name + "=" + initializer + ";", cls); + field = (PsiField)cls.add(field); + RemoveRedundantTypeArgumentsUtil.removeRedundantTypeArguments(field); + CodeStyleManager.getInstance(project).reformat(manager.shortenClassReferences(field)); - SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project); - PsiElement result = context.replace(field); - resultPtr = result == null ? null : smartPointerManager.createSmartPsiElementPointer(result); - fieldPtr = smartPointerManager.createSmartPsiElementPointer(field); + context.replace(field); + for (ExpressionToConstantReplacementContext copy : writableCopies) { + copy.replace(field); } - } - Extractor extractor = new Extractor(); - if (preview) { - extractor.run(); - } - else { - WriteAction.run(extractor); - } - PsiElement result = extractor.resultPtr == null ? null : extractor.resultPtr.getElement(); - if (result == null || !result.isValid()) return; - - if (!copies.isEmpty() && !preview) { - int answer = ApplicationManager.getApplication().isUnitTestMode() ? Messages.YES : - Messages.showYesNoDialog(project, - JavaBundle.message("intention.extract.set.from.comparison.chain.duplicates", - ApplicationNamesInfo.getInstance().getProductName(), - copies.size()), JavaBundle.message( - "dialog.title.process.duplicates"), - Messages.getQuestionIcon()); - if (answer == Messages.YES) { - WriteAction.run(() -> { - PsiField field = extractor.fieldPtr.getElement(); - if (field == null) return; - for (ExpressionToConstantReplacementContext copy : copies) { - copy.replace(field); - } - }); - } - } - - PsiField field = extractor.fieldPtr.getElement(); - result = extractor.resultPtr.getElement(); - if (result == null || field == null) return; - PsiReferenceExpression fieldRef = - tryCast(ReferencesSearch.search(field, new LocalSearchScope(result)).findFirst(), PsiReferenceExpression.class); - if (fieldRef == null) return; - - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); - editor.getCaretModel().moveToOffset(fieldRef.getTextOffset()); - editor.getSelectionModel().removeSelection(); - new MemberInplaceRenamer(field, field, editor).performInplaceRefactoring(suggestions); + updater.rename(field, List.copyOf(suggestions)); + }); } private static List findCopies(@NotNull List comparisons, @@ -206,14 +154,27 @@ public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntention } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - return comparisons(element).count() > 1; - } - - @NotNull - @Override - public String getText() { - return getFamilyName(); + public @Nullable Presentation getPresentation(@NotNull ActionContext actionContext) { + PsiElement element = actionContext.findLeaf(); + List comparisons = comparisons(element).toList(); + if (comparisons.size() <= 1) return null; + return switch (myProcessDuplicates) { + case UNSURE -> Presentation.of(getFamilyName()); + case YES -> { + PsiClass containingClass = ClassUtils.getContainingStaticClass(element); + if (containingClass == null) yield null; + ExpressionToConstantReplacementContext context = new ExpressionToConstantReplacementContext(comparisons); + List copies = findCopies(comparisons, containingClass); + TextRange[] ranges = + StreamEx.of(copies).append(context).map(ExpressionToConstantReplacementContext::range).toArray(TextRange.EMPTY_ARRAY); + yield Presentation.of(JavaBundle.message("intention.extract.set.from.comparison.chain.replace.all")).withHighlighting(ranges); + } + case NO -> { + ExpressionToConstantReplacementContext context = new ExpressionToConstantReplacementContext(comparisons); + yield Presentation.of(JavaBundle.message("intention.extract.set.from.comparison.chain.replace.only.this")) + .withHighlighting(context.range()); + } + }; } @Nls @@ -274,42 +235,54 @@ public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntention } static final class ExpressionToConstantReplacementContext { - final SmartPsiElementPointer myExpressionPtr; - final SmartPsiElementPointer myFirstComparisonPtr; - final SmartPsiElementPointer myLastComparisonPtr; - final SmartTypePointer myTypePtr; + final @NotNull PsiExpression myExpression; + final @NotNull PsiExpression myFirstComparison; + final @NotNull PsiExpression myLastComparison; + final PsiType myType; final String myInitializer; ExpressionToConstantReplacementContext(List comparisons) { assert !comparisons.isEmpty(); - Project project = comparisons.get(0).myComparison.getProject(); - SmartPointerManager manager = SmartPointerManager.getInstance(project); - myExpressionPtr = manager.createSmartPsiElementPointer(comparisons.get(0).myExpression); - myFirstComparisonPtr = manager.createSmartPsiElementPointer(comparisons.get(0).myComparison); - myLastComparisonPtr = manager.createSmartPsiElementPointer(comparisons.get(comparisons.size() - 1).myComparison); - myTypePtr = SmartTypePointerManager.getInstance(project).createSmartTypePointer(comparisons.get(0).myType); + myExpression = comparisons.get(0).myExpression; + myFirstComparison = comparisons.get(0).myComparison; + myLastComparison = comparisons.get(comparisons.size() - 1).myComparison; + myType = comparisons.get(0).myType; myInitializer = StreamEx.of(comparisons).map(cmp -> cmp.myConstant.getText()).joining(","); } + private ExpressionToConstantReplacementContext(ExpressionToConstantReplacementContext context, ModPsiUpdater updater) { + myExpression = updater.getWritable(context.myExpression); + myFirstComparison = updater.getWritable(context.myFirstComparison); + myLastComparison = updater.getWritable(context.myLastComparison); + myType = context.myType; + myInitializer = context.myInitializer; + } + + @NotNull TextRange range() { + int start = myFirstComparison.getTextRange().getStartOffset(); + int end = myLastComparison.getTextRange().getEndOffset(); + return TextRange.create(start, end); + } + + @NotNull ExpressionToConstantReplacementContext getWritable(@NotNull ModPsiUpdater updater) { + return new ExpressionToConstantReplacementContext(this, updater); + } + @Nullable private PsiElement replace(@NotNull PsiField field) { Project project = field.getProject(); PsiClass containingClass = field.getContainingClass(); if (containingClass == null) return null; String name = field.getName(); - PsiExpression expression = myExpressionPtr.getElement(); - PsiExpression firstComparison = myFirstComparisonPtr.getElement(); - PsiExpression lastComparison = myLastComparisonPtr.getElement(); - if (expression == null || firstComparison == null || lastComparison == null) return null; - PsiExpression disjunction = tryCast(firstComparison.getParent(), PsiPolyadicExpression.class); + PsiExpression disjunction = tryCast(myFirstComparison.getParent(), PsiPolyadicExpression.class); if (disjunction == null) return null; - int startOffset = firstComparison.getStartOffsetInParent(); - int endOffset = lastComparison.getStartOffsetInParent() + lastComparison.getTextLength(); + int startOffset = myFirstComparison.getStartOffsetInParent(); + int endOffset = myLastComparison.getStartOffsetInParent() + myLastComparison.getTextLength(); String origText = disjunction.getText(); String fieldReference = PsiResolveHelper.getInstance(project).resolveReferencedVariable(name, disjunction) == field ? name : containingClass.getQualifiedName() + "." + name; String replacementText = origText.substring(0, startOffset) + - fieldReference + ".contains(" + expression.getText() + ")" + + fieldReference + ".contains(" + myExpression.getText() + ")" + origText.substring(endOffset); PsiExpression replacement = JavaPsiFacade.getElementFactory(project).createExpressionFromText(replacementText, disjunction); if (replacement instanceof PsiMethodCallExpression && disjunction.getParent() instanceof PsiParenthesizedExpression) { diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties index 21794e49c34a..f170946c2a05 100644 --- a/java/openapi/resources/messages/JavaBundle.properties +++ b/java/openapi/resources/messages/JavaBundle.properties @@ -820,8 +820,8 @@ intention.extract.if.condition.text=Extract if ({0}) intention.extract.map.step.family=Extract to separate mapping method intention.extract.map.step.text=Extract variable ''{0}'' to ''{1}'' operation intention.extract.method.text=Extract method -intention.extract.set.from.comparison.chain.duplicates={0} has detected {1} code {1,choice,1#fragment|2#fragments} in this class that can be replaced using newly created Set. Would you like to replace {1,choice,1#it|2#them}? intention.extract.set.from.comparison.chain.family=Extract Set from comparison chain +intention.extract.set.from.comparison.chain.popup.title=Extract Set from Comparison Chain intention.family.add.javadoc=Add Javadoc intention.family.copy.abstract.method.implementation=Copy abstract method implementation intention.family.create.a.class.in.package=Create a class in package @@ -1866,4 +1866,6 @@ delete.initializer.completely=Delete initializer completely delete.assignment.completely=Delete assignment completely popup.title.remove.unused.variable=Remove Unused Variable intention.family.name.extract.possible.side.effects=Extract possible side effects -intention.family.name.delete.possible.side.effects=Delete possible side effects \ No newline at end of file +intention.family.name.delete.possible.side.effects=Delete possible side effects +intention.extract.set.from.comparison.chain.replace.only.this=Replace only this occurrence +intention.extract.set.from.comparison.chain.replace.all=Replace all occurrences \ No newline at end of file From 4a65f8fe1df0c00a506a4e64014d46c30b909f5a Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sat, 1 Jul 2023 12:35:23 +0200 Subject: [PATCH 111/226] [mod-command] ModDisplayError -> ModDisplayMessage GitOrigin-RevId: f6fe981411ed2b99015715496f78f9e4c4361ccf --- .../preview/IntentionPreviewUtils.java | 8 +++++--- .../src/com/intellij/modcommand/ModCommand.java | 2 +- .../intellij/modcommand/ModDisplayError.java | 13 ------------- .../intellij/modcommand/ModDisplayMessage.java | 17 +++++++++++++++++ .../intellij/codeInspection/ModCommands.java | 10 +++++++++- .../impl/modcommand/ModCommandServiceImpl.java | 15 +++++++++------ 6 files changed, 41 insertions(+), 24 deletions(-) delete mode 100644 platform/analysis-api/src/com/intellij/modcommand/ModDisplayError.java create mode 100644 platform/analysis-api/src/com/intellij/modcommand/ModDisplayMessage.java diff --git a/platform/analysis-api/src/com/intellij/codeInsight/intention/preview/IntentionPreviewUtils.java b/platform/analysis-api/src/com/intellij/codeInsight/intention/preview/IntentionPreviewUtils.java index 70d1956049bf..434d1a3261ae 100644 --- a/platform/analysis-api/src/com/intellij/codeInsight/intention/preview/IntentionPreviewUtils.java +++ b/platform/analysis-api/src/com/intellij/codeInsight/intention/preview/IntentionPreviewUtils.java @@ -181,9 +181,11 @@ public final class IntentionPreviewUtils { else if (command instanceof ModChooseAction target) { return getChoosePreview(context, target); } - else if (command instanceof ModDisplayError error) { - return new IntentionPreviewInfo.Html(new HtmlBuilder().append( - AnalysisBundle.message("preview.cannot.perform.action")).br().append(error.errorMessage()).toFragment()); + else if (command instanceof ModDisplayMessage message) { + if (message.kind() == ModDisplayMessage.MessageKind.ERROR) { + return new IntentionPreviewInfo.Html(new HtmlBuilder().append( + AnalysisBundle.message("preview.cannot.perform.action")).br().append(message.messageText()).toFragment()); + } } } return customDiffList.isEmpty() ? navigateInfo : diff --git a/platform/analysis-api/src/com/intellij/modcommand/ModCommand.java b/platform/analysis-api/src/com/intellij/modcommand/ModCommand.java index 62bd5d1c8b15..f84d27c36487 100644 --- a/platform/analysis-api/src/com/intellij/modcommand/ModCommand.java +++ b/platform/analysis-api/src/com/intellij/modcommand/ModCommand.java @@ -15,7 +15,7 @@ import java.util.Set; * All inheritors are records, so the whole state is declarative and readable. */ public sealed interface ModCommand - permits ModChooseAction, ModCompositeCommand, ModCreateFile, ModDeleteFile, ModDisplayError, ModHighlight, ModNavigate, + permits ModChooseAction, ModCompositeCommand, ModCreateFile, ModDeleteFile, ModDisplayMessage, ModHighlight, ModNavigate, ModNothing, ModRenameSymbol, ModUpdateFileText { /** diff --git a/platform/analysis-api/src/com/intellij/modcommand/ModDisplayError.java b/platform/analysis-api/src/com/intellij/modcommand/ModDisplayError.java deleted file mode 100644 index 138025de8ce6..000000000000 --- a/platform/analysis-api/src/com/intellij/modcommand/ModDisplayError.java +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.modcommand; - -import com.intellij.openapi.util.NlsContexts; -import org.jetbrains.annotations.NotNull; - -/** - * A command that displays an error message. - * - * @param errorMessage localized error message to display - */ -public record ModDisplayError(@NlsContexts.Tooltip @NotNull String errorMessage) implements ModCommand { -} diff --git a/platform/analysis-api/src/com/intellij/modcommand/ModDisplayMessage.java b/platform/analysis-api/src/com/intellij/modcommand/ModDisplayMessage.java new file mode 100644 index 000000000000..e8c79953b685 --- /dev/null +++ b/platform/analysis-api/src/com/intellij/modcommand/ModDisplayMessage.java @@ -0,0 +1,17 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.modcommand; + +import com.intellij.openapi.util.NlsContexts; +import org.jetbrains.annotations.NotNull; + +/** + * A command that displays an message. + * + * @param messageText localized message to display + * @param kind + */ +public record ModDisplayMessage(@NlsContexts.Tooltip @NotNull String messageText, MessageKind kind) implements ModCommand { + public enum MessageKind { + INFORMATION, ERROR; + } +} diff --git a/platform/lang-api/src/com/intellij/codeInspection/ModCommands.java b/platform/lang-api/src/com/intellij/codeInspection/ModCommands.java index 6041f53d3a64..41175c018d80 100644 --- a/platform/lang-api/src/com/intellij/codeInspection/ModCommands.java +++ b/platform/lang-api/src/com/intellij/codeInspection/ModCommands.java @@ -37,7 +37,15 @@ public final class ModCommands { * @return a command that displays the specified error message in the editor */ public static @NotNull ModCommand error(@NotNull @NlsContexts.Tooltip String message) { - return new ModDisplayError(message); + return new ModDisplayMessage(message, ModDisplayMessage.MessageKind.ERROR); + } + + /** + * @param message informational message to display + * @return a command that displays the specified informational message in the editor + */ + public static @NotNull ModCommand info(@NotNull @NlsContexts.Tooltip String message) { + return new ModDisplayMessage(message, ModDisplayMessage.MessageKind.INFORMATION); } /** diff --git a/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java b/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java index 5e8baa7ae7a6..9aec5450397f 100644 --- a/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java @@ -124,9 +124,9 @@ public class ModCommandServiceImpl implements ModCommandService { if (command instanceof ModChooseAction chooser) { return executeChoose(context, chooser, onTheFly); } - if (command instanceof ModDisplayError error) { + if (command instanceof ModDisplayMessage message) { if (!onTheFly) return true; // TODO: gather all errors and display them together? - return executeError(project, error); + return executeMessage(project, message); } if (command instanceof ModRenameSymbol rename) { if (!onTheFly) return true; @@ -147,7 +147,7 @@ public class ModCommandServiceImpl implements ModCommandService { return true; } catch (IOException e) { - executeError(project, new ModDisplayError(e.getMessage())); + executeMessage(project, new ModDisplayMessage(e.getMessage(), ModDisplayMessage.MessageKind.ERROR)); return false; } } @@ -167,7 +167,7 @@ public class ModCommandServiceImpl implements ModCommandService { }); } catch (IOException e) { - executeError(project, new ModDisplayError(e.getMessage())); + executeMessage(project, new ModDisplayMessage(e.getMessage(), ModDisplayMessage.MessageKind.ERROR)); return false; } } @@ -256,10 +256,13 @@ public class ModCommandServiceImpl implements ModCommandService { } } - private static boolean executeError(@NotNull Project project, @NotNull ModDisplayError error) { + private static boolean executeMessage(@NotNull Project project, @NotNull ModDisplayMessage message) { Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); if (editor == null) return false; - HintManager.getInstance().showErrorHint(editor, error.errorMessage()); + switch (message.kind()) { + case INFORMATION -> HintManager.getInstance().showInformationHint(editor, message.messageText()); + case ERROR -> HintManager.getInstance().showErrorHint(editor, message.messageText()); + } return true; } From 777a05e66d1a8546a0cb978c63e12b29f3925d93 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sat, 1 Jul 2023 13:27:38 +0200 Subject: [PATCH 112/226] [java-intentions] More ModCommands (IDEA-322693) GitOrigin-RevId: df31f3ce4ef6913f6d2b990302386bdc4fff2824 --- .../impl/quickfix/PermuteArgumentsFix.java | 42 ++------- .../src/messages/QuickFixBundle.properties | 2 +- .../daemon/impl/quickfix/MoveCatchUpFix.java | 92 ++++++------------- .../impl/quickfix/MoveMemberIntoClassFix.java | 55 +++++------ .../impl/config/QuickFixFactoryImpl.java | 4 +- 5 files changed, 66 insertions(+), 129 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/PermuteArgumentsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/PermuteArgumentsFix.java index 5f29ce9e693f..665d5cd9261d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/PermuteArgumentsFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/PermuteArgumentsFix.java @@ -3,18 +3,14 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.HighPriorityAction; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.codeInsight.intention.PriorityAction; +import com.intellij.codeInspection.PsiUpdateModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ArrayUtil; @@ -25,47 +21,29 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -public final class PermuteArgumentsFix implements IntentionAction, HighPriorityAction { +public final class PermuteArgumentsFix extends PsiUpdateModCommandAction { private static final Logger LOG = Logger.getInstance(PermuteArgumentsFix.class); - private final PsiCall myCall; private final PsiCall myPermutation; private PermuteArgumentsFix(@NotNull PsiCall call, @NotNull PsiCall permutation) { - myCall = call; + super(call); myPermutation = permutation; } - @Override - public boolean startInWriteAction() { - return true; - } - - - @Override - @NotNull - public String getText() { - return QuickFixBundle.message("permute.arguments"); - } - - @Override - public @NotNull FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new PermuteArgumentsFix(PsiTreeUtil.findSameElementInCopy(myCall, target), myPermutation); - } - @Override @NotNull public String getFamilyName() { - return getText(); + return QuickFixBundle.message("permute.arguments"); } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return !project.isDisposed() && myCall.isValid() && BaseIntentionAction.canModify(myCall); + protected @NotNull Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiCall element) { + return Presentation.of(getFamilyName()).withPriority(PriorityAction.Priority.HIGH); } @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - Objects.requireNonNull(myCall.getArgumentList()).replace(Objects.requireNonNull(myPermutation.getArgumentList())); + protected void invoke(@NotNull ActionContext context, @NotNull PsiCall call, @NotNull ModPsiUpdater updater) { + Objects.requireNonNull(call.getArgumentList()).replace(Objects.requireNonNull(myPermutation.getArgumentList())); } public static boolean registerFix(@NotNull HighlightInfo.Builder info, PsiCall callExpression, final CandidateInfo[] candidates, final TextRange fixRange) { diff --git a/java/java-analysis-impl/src/messages/QuickFixBundle.properties b/java/java-analysis-impl/src/messages/QuickFixBundle.properties index e4e51b335c5a..9de1625e9175 100644 --- a/java/java-analysis-impl/src/messages/QuickFixBundle.properties +++ b/java/java-analysis-impl/src/messages/QuickFixBundle.properties @@ -179,7 +179,7 @@ change.inheritors.visibility.warning.text=Do you want to change inheritors' visi change.inheritors.visibility.warning.title=Change Inheritors move.class.in.extend.list.family=Move Class in Extend list move.bound.class.to.front.fix.text=Move bound ''{0}'' to the beginning of the bounds list of type parameter ''{1}'' -move.catch.up.family=Move Catch Up +move.catch.up.family=Move 'catch' up move.catch.up.text=Move catch for ''{0}'' before ''{1}'' move.class.to.separate.file.family=Move class to separate file move.class.to.separate.file.text=Move class ''{0}'' to ''{0}.java'' diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveCatchUpFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveCatchUpFix.java index 8a239b1f3c92..a2168b63ed37 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveCatchUpFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveCatchUpFix.java @@ -1,37 +1,19 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2023 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.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.impl.BaseIntentionAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; +import com.intellij.codeInspection.ModCommands; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; import com.intellij.psi.PsiCatchSection; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; import com.intellij.psi.PsiTryStatement; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class MoveCatchUpFix implements IntentionAction { +public class MoveCatchUpFix implements ModCommandAction { private final @NotNull PsiCatchSection myCatchSection; private final @NotNull PsiCatchSection myMoveBeforeSection; @@ -41,17 +23,22 @@ public class MoveCatchUpFix implements IntentionAction { } @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new MoveCatchUpFix(PsiTreeUtil.findSameElementInCopy(myCatchSection, target), - PsiTreeUtil.findSameElementInCopy(myMoveBeforeSection, target)); - } - - @Override - @NotNull - public String getText() { - return QuickFixBundle.message("move.catch.up.text", - JavaHighlightUtil.formatType(myCatchSection.getCatchType()), - JavaHighlightUtil.formatType(myMoveBeforeSection.getCatchType())); + public @Nullable Presentation getPresentation(@NotNull ActionContext context) { + if (myCatchSection.isValid() + && BaseIntentionAction.canModify(myCatchSection) + && myMoveBeforeSection.isValid() + && myCatchSection.getCatchType() != null + && PsiUtil.resolveClassInType(myCatchSection.getCatchType()) != null + && myMoveBeforeSection.getCatchType() != null + && PsiUtil.resolveClassInType(myMoveBeforeSection.getCatchType()) != null + && !myCatchSection.getManager().areElementsEquivalent( + PsiUtil.resolveClassInType(myCatchSection.getCatchType()), + PsiUtil.resolveClassInType(myMoveBeforeSection.getCatchType()))) { + return Presentation.of(QuickFixBundle.message("move.catch.up.text", + JavaHighlightUtil.formatType(myCatchSection.getCatchType()), + JavaHighlightUtil.formatType(myMoveBeforeSection.getCatchType()))); + } + return null; } @Override @@ -61,34 +48,13 @@ public class MoveCatchUpFix implements IntentionAction { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return myCatchSection.isValid() - && BaseIntentionAction.canModify(myCatchSection) - && myMoveBeforeSection.isValid() - && myCatchSection.getCatchType() != null - && PsiUtil.resolveClassInType(myCatchSection.getCatchType()) != null - && myMoveBeforeSection.getCatchType() != null - && PsiUtil.resolveClassInType(myMoveBeforeSection.getCatchType()) != null - && !myCatchSection.getManager().areElementsEquivalent( - PsiUtil.resolveClassInType(myCatchSection.getCatchType()), - PsiUtil.resolveClassInType(myMoveBeforeSection.getCatchType())); - } - - @NotNull - @Override - public PsiElement getElementToMakeWritable(@NotNull PsiFile file) { - return myCatchSection.getContainingFile(); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) { - PsiTryStatement statement = myCatchSection.getTryStatement(); - statement.addBefore(myCatchSection, myMoveBeforeSection); - myCatchSection.delete(); - } - - @Override - public boolean startInWriteAction() { - return true; + public @NotNull ModCommand perform(@NotNull ActionContext context) { + return ModCommands.psiUpdate(context, updater -> { + PsiCatchSection catchSection = updater.getWritable(myCatchSection); + PsiCatchSection moveBeforeSection = updater.getWritable(myMoveBeforeSection); + PsiTryStatement statement = catchSection.getTryStatement(); + statement.addBefore(catchSection, moveBeforeSection); + catchSection.delete(); + }); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveMemberIntoClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveMemberIntoClassFix.java index f47684393de3..3873e257fbfb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveMemberIntoClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveMemberIntoClassFix.java @@ -1,15 +1,13 @@ -// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 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.quickfix; import com.intellij.codeInsight.daemon.impl.analysis.MemberModel; import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; -import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.java.JavaBundle; import com.intellij.lang.jvm.JvmModifier; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.text.StringUtil; @@ -21,26 +19,26 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; -public class MoveMemberIntoClassFix extends LocalQuickFixAndIntentionActionOnPsiElement { +public class MoveMemberIntoClassFix extends PsiUpdateModCommandAction { - public MoveMemberIntoClassFix(@Nullable PsiErrorElement errorElement) { + public MoveMemberIntoClassFix(@NotNull PsiErrorElement errorElement) { super(errorElement); } @Override - public void invoke(@NotNull Project project, - @NotNull PsiFile file, - @Nullable Editor editor, - @NotNull PsiElement startElement, - @NotNull PsiElement endElement) { - Pair rangeAndMember = createMember(file); + protected void invoke(@NotNull ActionContext context, @NotNull PsiErrorElement element, @NotNull ModPsiUpdater updater) { + PsiFile file = element.getContainingFile(); + MemberInfo rangeAndMember = createMember(file, element); if (rangeAndMember == null) return; Document document = file.getViewProvider().getDocument(); - TextRange memberRange = rangeAndMember.getFirst(); - PsiMember member = rangeAndMember.getSecond(); + TextRange memberRange = rangeAndMember.range(); + PsiMember member = rangeAndMember.member(); PsiClass psiClass = getPsiClass(file, member); if (psiClass == null) return; - PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + if (psiClass.getContainingFile() != file) { + psiClass = (PsiClass)file.add(psiClass); + } + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(context.project()); documentManager.doPostponedOperationsAndUnblockDocument(document); SmartPsiElementPointer classPtr = SmartPointerManager.createPointer(psiClass); document.deleteString(memberRange.getStartOffset(), memberRange.getEndOffset()); @@ -61,12 +59,7 @@ public class MoveMemberIntoClassFix extends LocalQuickFixAndIntentionActionOnPsi PsiClass psiClass = ContainerUtil.find(javaFile.getClasses(), c -> className.equals(c.getName())); if (psiClass != null) return psiClass; PsiElementFactory factory = JavaPsiFacade.getElementFactory(file.getProject()); - return (PsiClass)file.add(createClass(factory, className, member)); - } - - @Override - public @NotNull String getText() { - return getFamilyName(); + return createClass(factory, className, member); } @Override @@ -86,25 +79,25 @@ public class MoveMemberIntoClassFix extends LocalQuickFixAndIntentionActionOnPsi } return factory.createInterface(className); } + + record MemberInfo(@NotNull TextRange range, @NotNull PsiMember member) {} - private @Nullable Pair<@NotNull TextRange, @NotNull PsiMember> createMember(@NotNull PsiFile file) { - PsiErrorElement errorElement = ObjectUtils.tryCast(getStartElement(), PsiErrorElement.class); - if (errorElement == null) return null; + private static @Nullable MemberInfo createMember(@NotNull PsiFile file, @NotNull PsiErrorElement errorElement) { MemberModel model = MemberModel.create(errorElement); if (model == null) return null; TextRange memberRange = model.textRange(); String memberText = memberRange.substring(file.getText()); PsiElementFactory factory = JavaPsiFacade.getElementFactory(file.getProject()); MemberModel.MemberType memberType = model.memberType(); - return Pair.create(memberRange, memberType.create(factory, memberText, file)); + return new MemberInfo(memberRange, memberType.create(factory, memberText, file)); } @Override - public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { - Pair member = createMember(file); - if (member == null || !(member.getSecond() instanceof PsiNamedElement)) return IntentionPreviewInfo.EMPTY; - PsiClass psiClass = getPsiClass(file, member.getSecond()); + protected @NotNull IntentionPreviewInfo generatePreview(ActionContext context, PsiErrorElement element) { + MemberInfo info = createMember(context.file(), element); + if (info == null || !(info.member() instanceof PsiNamedElement member)) return IntentionPreviewInfo.EMPTY; + PsiClass psiClass = getPsiClass(context.file(), info.member()); if (psiClass == null) return IntentionPreviewInfo.EMPTY; - return IntentionPreviewInfo.movePsi((PsiNamedElement)member.getSecond(), psiClass); + return IntentionPreviewInfo.movePsi(member, psiClass); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java index d4f8a56e582c..07b6b2160700 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java @@ -319,7 +319,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @NotNull @Override public IntentionAction createMoveCatchUpFix(@NotNull PsiCatchSection section, @NotNull PsiCatchSection section1) { - return new MoveCatchUpFix(section, section1); + return new MoveCatchUpFix(section, section1).asIntention(); } @NotNull @@ -1061,7 +1061,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @Override public @NotNull IntentionAction createMoveMemberIntoClassFix(@NotNull PsiErrorElement errorElement) { - return new MoveMemberIntoClassFix(errorElement); + return new MoveMemberIntoClassFix(errorElement).asIntention(); } @Override From 3b0c9fd51a6ab3b7a305aded2ac43ef7e66d0d32 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sat, 1 Jul 2023 13:49:14 +0200 Subject: [PATCH 113/226] [java-intentions] QualifyThisArgumentFix/QualifySuperArgumentFix/QualifyWithThis: mod-commands (IDEA-322693) GitOrigin-RevId: d775d9cc0f920d7e571df14ba65de38123ec978e --- .../daemon/impl/analysis/HighlightUtil.java | 8 +-- .../quickfix/QualifySuperArgumentFix.java | 28 +------- .../impl/quickfix/QualifyThisArgumentFix.java | 26 +------- .../QualifyThisOrSuperArgumentFix.java | 64 ++++--------------- .../impl/quickfix/QualifyWithThisFix.java | 64 +++++-------------- 5 files changed, 36 insertions(+), 154 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index e5a1b891c6a8..9b74f96c9fb0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -2676,13 +2676,13 @@ public final class HighlightUtil { } HighlightInfo.Builder builder = createMemberReferencedError(resolvedName, expression.getTextRange()); - if (expression instanceof PsiReferenceExpression && PsiUtil.isInnerClass(parentClass)) { - String referenceName = ((PsiReferenceExpression)expression).getReferenceName(); + if (expression instanceof PsiReferenceExpression ref && PsiUtil.isInnerClass(parentClass)) { + String referenceName = ref.getReferenceName(); PsiClass containingClass = parentClass.getContainingClass(); LOG.assertTrue(containingClass != null); PsiField fieldInContainingClass = containingClass.findFieldByName(referenceName, true); - if (fieldInContainingClass != null && ((PsiReferenceExpression)expression).getQualifierExpression() == null) { - builder.registerFix(new QualifyWithThisFix(containingClass, expression), null, null, null, null); + if (fieldInContainingClass != null && ref.getQualifierExpression() == null) { + builder.registerFix(new QualifyWithThisFix(containingClass, ref), null, null, null, null); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java index 6e9813780467..fece1a7b4170 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java @@ -1,43 +1,19 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2023 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.quickfix; import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; public class QualifySuperArgumentFix extends QualifyThisOrSuperArgumentFix { private QualifySuperArgumentFix(@NotNull PsiExpression expression, @NotNull PsiClass psiClass) { super(expression, psiClass); } - @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new QualifySuperArgumentFix(PsiTreeUtil.findSameElementInCopy(myExpression, target), myPsiClass); - } - @Override protected String getQualifierText() { return PsiKeyword.SUPER; @@ -70,7 +46,7 @@ public class QualifySuperArgumentFix extends QualifyThisOrSuperArgumentFix { return; } if (method != null && !method.hasModifierProperty(PsiModifier.ABSTRACT)) { - IntentionAction action = new QualifySuperArgumentFix(expr, superClass); + var action = new QualifySuperArgumentFix(expr, superClass); highlightInfo.registerFix(action, null, null, null, null); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyThisArgumentFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyThisArgumentFix.java index d0a7da932d5c..eb3215ade724 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyThisArgumentFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyThisArgumentFix.java @@ -1,24 +1,8 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2023 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.quickfix; import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; @@ -27,7 +11,6 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.util.RefactoringChangeUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.HashSet; import java.util.Set; @@ -37,11 +20,6 @@ public class QualifyThisArgumentFix extends QualifyThisOrSuperArgumentFix{ super(expression, psiClass); } - @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new QualifyThisArgumentFix(PsiTreeUtil.findSameElementInCopy(myExpression, target), myPsiClass); - } - @Override protected String getQualifierText() { return PsiKeyword.THIS; @@ -92,7 +70,7 @@ public class QualifyThisArgumentFix extends QualifyThisOrSuperArgumentFix{ if (!TypeConversionUtil.isAssignable(parameterType, exprType)) { final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(parameterType); if (psiClass != null && containingClasses.contains(psiClass)) { - IntentionAction action = new QualifyThisArgumentFix(expression, psiClass); + var action = new QualifyThisArgumentFix(expression, psiClass); builder.registerFix(action, null, null, fixRange, null); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyThisOrSuperArgumentFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyThisOrSuperArgumentFix.java index 15ea96ade343..df4489ea0902 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyThisOrSuperArgumentFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyThisOrSuperArgumentFix.java @@ -1,74 +1,34 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2023 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.quickfix; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInspection.util.IntentionName; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.java.analysis.JavaAnalysisBundle; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiExpression; -import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -abstract class QualifyThisOrSuperArgumentFix implements IntentionAction { +abstract class QualifyThisOrSuperArgumentFix extends PsiUpdateModCommandAction { protected static final Logger LOG = Logger.getInstance(QualifyThisOrSuperArgumentFix.class); - protected final PsiExpression myExpression; protected final PsiClass myPsiClass; - private @IntentionName String myText; - QualifyThisOrSuperArgumentFix(@NotNull PsiExpression expression, @NotNull PsiClass psiClass) { - myExpression = expression; + super(expression); myPsiClass = psiClass; } - /** - * Must override in subclasses, as we store myExpression in the field, so default strategy won't work - */ - @Override - abstract public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target); - - @Override - public boolean startInWriteAction() { - return true; - } - - @NotNull - @Override - public String getText() { - return myText; - } - protected abstract String getQualifierText(); protected abstract PsiExpression getQualifier(PsiManager manager); - + @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - if (!myExpression.isValid()) return false; - if (!myPsiClass.isValid()) return false; - myText = JavaAnalysisBundle.message("intention.name.qualify.expression", getQualifierText(), myPsiClass.getQualifiedName()); - return true; + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiExpression element) { + if (!myPsiClass.isValid()) return null; + return Presentation.of( + JavaAnalysisBundle.message("intention.name.qualify.expression", getQualifierText(), myPsiClass.getQualifiedName())); } @NotNull @@ -78,7 +38,7 @@ abstract class QualifyThisOrSuperArgumentFix implements IntentionAction { } @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - myExpression.replace(getQualifier(PsiManager.getInstance(project))); + protected void invoke(@NotNull ActionContext context, @NotNull PsiExpression expression, @NotNull ModPsiUpdater updater) { + expression.replace(getQualifier(PsiManager.getInstance(context.project()))); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyWithThisFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyWithThisFix.java index 60dfba1ed4f2..0ecf0f7a3b8f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyWithThisFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QualifyWithThisFix.java @@ -1,72 +1,40 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2023 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.quickfix; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.java.analysis.JavaAnalysisBundle; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.modcommand.ModPsiUpdater; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiReferenceExpression; +import com.intellij.psi.PsiThisExpression; import com.intellij.refactoring.util.RefactoringChangeUtil; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class QualifyWithThisFix implements IntentionAction { +public class QualifyWithThisFix extends PsiUpdateModCommandAction { private final PsiClass myContainingClass; - private final PsiElement myExpression; - public QualifyWithThisFix(@NotNull PsiClass containingClass, @NotNull PsiElement expression) { + public QualifyWithThisFix(@NotNull PsiClass containingClass, @NotNull PsiReferenceExpression expression) { + super(expression); myContainingClass = containingClass; - myExpression = expression; } @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new QualifyWithThisFix(myContainingClass, PsiTreeUtil.findSameElementInCopy(myExpression, target)); - } - - @NotNull - @Override - public String getText() { - return JavaAnalysisBundle.message("qualify.with.0.this", myContainingClass.getName()); + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiReferenceExpression element) { + return myContainingClass.isValid() ? Presentation.of(getFamilyName()) : null; } @NotNull @Override public String getFamilyName() { - return getText(); + return JavaAnalysisBundle.message("qualify.with.0.this", myContainingClass.getName()); } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return true; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + protected void invoke(@NotNull ActionContext context, @NotNull PsiReferenceExpression element, @NotNull ModPsiUpdater updater) { final PsiThisExpression thisExpression = - RefactoringChangeUtil.createThisExpression(PsiManager.getInstance(project), myContainingClass); - ((PsiReferenceExpression)myExpression).setQualifierExpression(thisExpression); - } - - @Override - public boolean startInWriteAction() { - return true; + RefactoringChangeUtil.createThisExpression(PsiManager.getInstance(context.project()), myContainingClass); + element.setQualifierExpression(thisExpression); } } From b6631d682e4510224b27f3a8c7e2d79594a460bb Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Sat, 1 Jul 2023 16:01:44 +0200 Subject: [PATCH 114/226] [kotlin utils] move simpleLazy to lazy.kt and rename it to lazyUnsafe GitOrigin-RevId: 9178d95bf7a2f08607fac8259296557875bc87ff --- platform/util-ex/src/com/intellij/util/lazy.kt | 10 +++++++++- platform/util/src/com/intellij/util/KtUtils.kt | 1 - 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/platform/util-ex/src/com/intellij/util/lazy.kt b/platform/util-ex/src/com/intellij/util/lazy.kt index a4c63046cf97..8c686a8482f1 100644 --- a/platform/util-ex/src/com/intellij/util/lazy.kt +++ b/platform/util-ex/src/com/intellij/util/lazy.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.util import kotlinx.coroutines.CoroutineScope @@ -22,8 +22,16 @@ fun recursionSafeLazy(recursionKey: Any? = null, initializer: () -> T): Lazy return RecursionPreventingSafePublicationLazy(recursionKey, initializer) } +/** + * Creates a lazy property that is thread-safe on publication. + */ fun lazyPub(initializer: () -> T): Lazy = lazy(LazyThreadSafetyMode.PUBLICATION, initializer) +/** + * Creates a lazy property that is thread-unsafe. Do not use it in multithreading environment + */ +fun lazyUnsafe(initializer: () -> T): Lazy = lazy(LazyThreadSafetyMode.NONE, initializer) + /** * Creates a new instance of [SuspendingLazy] that uses the specified initialization function [initializer]. * diff --git a/platform/util/src/com/intellij/util/KtUtils.kt b/platform/util/src/com/intellij/util/KtUtils.kt index 7d4b9c88283d..bde869863618 100644 --- a/platform/util/src/com/intellij/util/KtUtils.kt +++ b/platform/util/src/com/intellij/util/KtUtils.kt @@ -27,4 +27,3 @@ operator fun AtomicReference.getValue(thisRef: Any?, property: KProperty< operator fun AtomicReference.setValue(thisRef: Any?, property: KProperty<*>, value: V): Unit = set(value) -fun simpleLazy(initializer: () -> T): Lazy = lazy(LazyThreadSafetyMode.NONE, initializer) \ No newline at end of file From 83c7af4abc564ea7212997441c64baeebca027ed Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Sat, 1 Jul 2023 15:20:42 +0200 Subject: [PATCH 115/226] Fix possible race condition in test. `onTextAvailable` could be called from 2 threads: stderr and stdout, hence `stdAll` must be thread-safe GitOrigin-RevId: fadf694621d15521221cadfef1d8c6f423a8608a --- .../testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java b/python/testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java index 6c01f4a99a55..ff18c433f605 100644 --- a/python/testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java +++ b/python/testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java @@ -132,7 +132,7 @@ public abstract class PyProcessWithConsoleTestTask failed = new Ref<>(false); final Ref processHandlerRef = new Ref<>(); From a7260ad09af0f563a472ebc0ded2c5c9066467fc Mon Sep 17 00:00:00 2001 From: Ruslan Cheremin Date: Sat, 1 Jul 2023 17:50:03 +0200 Subject: [PATCH 116/226] [core] IDEA-319737: issue fsync on VFS force() & close() calls + Among others, make sure connectionStatus header field is flushed to disk GitOrigin-RevId: 428192bca6e251af484fff36ed2111c2b797c351 --- .../vfs/newvfs/persistent/PersistentFSConnection.java | 1 + .../openapi/vfs/newvfs/persistent/PersistentFSImpl.java | 3 +++ .../PersistentFSRecordsLockFreeOverMMappedFile.java | 9 ++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java index 2a6d87327a7f..738a8788d143 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java @@ -260,6 +260,7 @@ public final class PersistentFSConnection { } writeConnectionState(); + myRecords.force(); closeStorages(myRecords, myNames, myAttributesStorage, diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index 89320c265730..a088bbc2aecf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -1967,6 +1967,9 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { int childId = FSRecords.createRecord(); int nameId = writeAttributesToRecord(childId, parentId, name, parentFile.isCaseSensitive(), attributes, true); + if(nameId < 0){ + throw new AssertionError("writeAttributesToRecord(" + childId + ", " + parentId + ", '" + name + "',...) returns -1"); + } assert childId > 0 : childId; if (attributes.isDirectory()) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsLockFreeOverMMappedFile.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsLockFreeOverMMappedFile.java index 7a92b962cb2a..0d8fac3b0647 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsLockFreeOverMMappedFile.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsLockFreeOverMMappedFile.java @@ -619,7 +619,8 @@ public class PersistentFSRecordsLockFreeOverMMappedFile implements PersistentFSR if (dirty.compareAndSet(true, false)) { setIntHeaderField(HEADER_RECORDS_ALLOCATED, allocatedRecordsCount.get()); setIntHeaderField(HEADER_GLOBAL_MOD_COUNT_OFFSET, globalModCount.get()); - //TODO RC: should we do fsync() here, or we could trust OS will flush mmapped pages to disk? + //MAYBE RC: should we do fsync() here, or we could trust OS will flush mmapped pages to disk? + storage.fsync(); } } @@ -940,6 +941,12 @@ public class PersistentFSRecordsLockFreeOverMMappedFile implements PersistentFSR } } + public void fsync() throws IOException { + if (channel.isOpen()) { + channel.force(true); + } + } + public static class Page implements AutoCloseable { private final int pageIndex; private final long offsetInFile; From f77437706975900793469ae2da58f33206d6e290 Mon Sep 17 00:00:00 2001 From: Yuriy Artamonov Date: Sat, 1 Jul 2023 19:57:03 +0200 Subject: [PATCH 117/226] [testing] Support constructor overloads in Driver GitOrigin-RevId: a5d0611269ccc558189a87ada6c46471dc6cb06f --- .../src/com/intellij/driver/client/Driver.kt | 5 + .../intellij/driver/client/impl/DriverImpl.kt | 6 ++ .../src/com/intellij/driver/impl/Invoker.java | 100 +++++++++++++----- .../intellij/driver/impl/InvokerMBean.java | 2 + 4 files changed, 85 insertions(+), 28 deletions(-) diff --git a/platform/remote-driver/client/src/com/intellij/driver/client/Driver.kt b/platform/remote-driver/client/src/com/intellij/driver/client/Driver.kt index 6ac48db5f077..2a3aa8378220 100644 --- a/platform/remote-driver/client/src/com/intellij/driver/client/Driver.kt +++ b/platform/remote-driver/client/src/com/intellij/driver/client/Driver.kt @@ -15,6 +15,11 @@ interface Driver : AutoCloseable { fun getProductVersion(): ProductVersion + /** + * Forcefully exits the application + */ + fun exitApplication() + @Contract(pure = true) fun service(clazz: KClass): T diff --git a/platform/remote-driver/client/src/com/intellij/driver/client/impl/DriverImpl.kt b/platform/remote-driver/client/src/com/intellij/driver/client/impl/DriverImpl.kt index a142ddd60f87..754ada31a9ed 100644 --- a/platform/remote-driver/client/src/com/intellij/driver/client/impl/DriverImpl.kt +++ b/platform/remote-driver/client/src/com/intellij/driver/client/impl/DriverImpl.kt @@ -39,6 +39,10 @@ internal class DriverImpl(host: JmxHost?) : Driver { return invoker.getProductVersion() } + override fun exitApplication() { + invoker.exit() + } + @Suppress("UNCHECKED_CAST") override fun service(clazz: KClass): T { return appServices.computeIfAbsent(clazz.java, ::serviceBridge) as T @@ -321,6 +325,8 @@ private val NO_SESSION: Session = Session(0, OnDispatcher.DEFAULT, LockSemantics internal interface Invoker : AutoCloseable { fun getProductVersion(): ProductVersion + fun exit() + fun invoke(call: RemoteCall): RemoteCallResult fun newSession(): Int diff --git a/platform/remote-driver/core/src/com/intellij/driver/impl/Invoker.java b/platform/remote-driver/core/src/com/intellij/driver/impl/Invoker.java index cf1dfe4031e7..ba461af686b3 100644 --- a/platform/remote-driver/core/src/com/intellij/driver/impl/Invoker.java +++ b/platform/remote-driver/core/src/com/intellij/driver/impl/Invoker.java @@ -67,6 +67,11 @@ public class Invoker implements InvokerMBean { ); } + @Override + public void exit() { + ApplicationManager.getApplication().exit(true, true, false); + } + @Override public @NotNull RemoteCallResult invoke(@NotNull RemoteCall call) { Object[] transformedArgs = transformArgs(call); @@ -75,11 +80,11 @@ public class Invoker implements InvokerMBean { if (call instanceof NewInstanceCall) { Class targetClass = getTargetClass(call); - Constructor constructor = getConstructor(call, targetClass); + Constructor constructor = getConstructor(call, targetClass, transformedArgs); LOG.debug("Creating instance of " + targetClass); - result = withSemantics(call, () -> constructor.newInstance(transformedArgs)); + result = withSemantics(call, () -> invokeConstructor(constructor, transformedArgs)); } else { CallTarget callTarget = getCallTarget(call, transformedArgs); @@ -165,19 +170,40 @@ public class Invoker implements InvokerMBean { } } + private static @NotNull Object invokeConstructor(Constructor constructor, Object[] transformedArgs) throws Exception { + try { + return constructor.newInstance(transformedArgs); + } + catch (IllegalArgumentException ie) { + String message = "Argument type mismatch for constructor " + constructor + " , actual types are [" + + getExpectedTypesMessage(transformedArgs) + "]"; + LOG.warn(message, ie); + + throw new IllegalArgumentException(message, ie); + } + catch (Throwable e) { + LOG.warn("Error during remote driver call " + constructor, e); + + throw e; + } + } + + private static @NotNull String getExpectedTypesMessage(Object[] transformedArgs) { + return Arrays.stream(transformedArgs) + .map(a -> { + if (a == null) return "null"; + return a.getClass().getSimpleName(); + }) + .collect(Collectors.joining(", ")); + } + private static Object invokeMethod(CallTarget callTarget, Object instance, Object[] args) throws Exception { try { return callTarget.targetMethod().invoke(instance, args); } catch (IllegalArgumentException ie) { - String types = Arrays.stream(args) - .map(a -> { - if (a == null) return "null"; - return a.getClass().getSimpleName(); - }) - .collect(Collectors.joining(", ")); - - String message = "Argument type mismatch for call " + callTarget.targetMethod() + ", actual types are [" + types + "]"; + String message = "Argument type mismatch for call " + callTarget.targetMethod() + ", actual types are [" + + getExpectedTypesMessage(args) + "]"; LOG.warn(message, ie); throw new IllegalArgumentException(message, ie); @@ -238,12 +264,29 @@ public class Invoker implements InvokerMBean { return RefProducer.makeRef(itemId, item); } - private static Constructor getConstructor(@NotNull RemoteCall call, @NotNull Class targetClass) { + private static Constructor getConstructor(@NotNull RemoteCall call, @NotNull Class targetClass, Object[] transformedArgs) { int argCount = call.getArgs().length; - return Arrays.stream(targetClass.getConstructors()) + List> constructors = Arrays.stream(targetClass.getConstructors()) .filter(x -> x.getParameterCount() == argCount) - .findFirst() - .orElseThrow(() -> new IllegalStateException("No such constructor found in " + targetClass)); + .toList(); + + if (constructors.isEmpty()) { + throw new IllegalStateException( + "No constructor with parameter count " + argCount + + " in class " + call.getClassName()); + } + + if (constructors.size() > 1) { + List<@Nullable Class> argumentTypes = getArgumentTypes(transformedArgs); + // take into account argument types + for (Constructor constructor : constructors) { + if (areTypesCompatible(constructor.getParameterTypes(), argumentTypes)) { + return constructor; + } + } + } + + return constructors.get(0); } private @NotNull CallTarget getCallTarget(@NotNull RemoteCall call, Object[] transformedArgs) { @@ -262,16 +305,10 @@ public class Invoker implements InvokerMBean { } if (targetMethods.size() > 1) { - List<@Nullable Class> argumentTypes = Arrays.stream(transformedArgs) - .map(a -> { - if (a == null) return (Class)null; - return a.getClass(); - }) - .toList(); - + List<@Nullable Class> argumentTypes = getArgumentTypes(transformedArgs); // take into account argument types for (Method method : targetMethods) { - if (areTypesCompatible(method, argumentTypes)) { + if (areTypesCompatible(method.getParameterTypes(), argumentTypes)) { return new CallTarget(clazz, method); } } @@ -280,20 +317,27 @@ public class Invoker implements InvokerMBean { return new CallTarget(clazz, targetMethods.get(0)); } - private static boolean areTypesCompatible(@NotNull Method method, @NotNull List<@Nullable Class> argumentTypes) { - Class[] types = method.getParameterTypes(); + private static @NotNull List<@Nullable Class> getArgumentTypes(Object[] transformedArgs) { + return Arrays.stream(transformedArgs) + .map(a -> { + if (a == null) return (Class)null; + return a.getClass(); + }) + .toList(); + } + private static boolean areTypesCompatible(Class @NotNull [] parameterTypes, @NotNull List<@Nullable Class> argumentTypes) { for (int i = 0; i < argumentTypes.size(); i++) { Class argType = argumentTypes.get(i); if (argType == null) continue; - Class parameterType = types[i]; + Class parameterType = parameterTypes[i]; if (!parameterType.isAssignableFrom(argType)) return false; } return true; } - private Class getTargetClass(RemoteCall call) { + private @NotNull Class getTargetClass(RemoteCall call) { Class clazz; try { clazz = getClassLoader(call).loadClass(call.getClassName()); @@ -304,7 +348,7 @@ public class Invoker implements InvokerMBean { return clazz; } - private ClassLoader getClassLoader(RemoteCall call) { + private @NotNull ClassLoader getClassLoader(RemoteCall call) { String pluginId = call.getPluginId(); if (pluginId == null || pluginId.isEmpty()) return getClass().getClassLoader(); @@ -331,7 +375,7 @@ public class Invoker implements InvokerMBean { return plugin.getClassLoader(); } - private Object findInstance(RemoteCall call, Class clazz) { + private @Nullable Object findInstance(RemoteCall call, Class clazz) { if (call instanceof ServiceCall) { Object projectInstance = null; Ref projectRef = ((ServiceCall)call).getProjectRef(); diff --git a/platform/remote-driver/core/src/com/intellij/driver/impl/InvokerMBean.java b/platform/remote-driver/core/src/com/intellij/driver/impl/InvokerMBean.java index f20fde1c79fe..4c95b73f7320 100644 --- a/platform/remote-driver/core/src/com/intellij/driver/impl/InvokerMBean.java +++ b/platform/remote-driver/core/src/com/intellij/driver/impl/InvokerMBean.java @@ -14,6 +14,8 @@ import java.util.function.Supplier; public interface InvokerMBean { ProductVersion getProductVersion(); + void exit(); + RemoteCallResult invoke(RemoteCall call); int newSession(); From 3355c55eac310dda0b422febb853a2f7f08ba1aa Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Sat, 1 Jul 2023 22:27:49 +0200 Subject: [PATCH 118/226] IDEA-321769 Unify shadow painters (progress and notification) and use Java 2D directly instead of SVG GitOrigin-RevId: fc5ce0131c252e79184af9ae47fbfbacfdcda016 --- .../ide/ui/laf/darcula/darcula.theme.json | 8 - .../ide/ui/laf/intellijlaf.theme.json | 8 - .../ui/impl/GlassPaneDialogWrapperPeer.java | 12 +- .../com/intellij/ui/ShadowJava2DPainter.kt | 168 ++++++------------ .../src/themes/expUI/expUI_dark.theme.json | 8 - .../src/themes/expUI/expUI_light.theme.json | 76 ++++---- 6 files changed, 103 insertions(+), 177 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.theme.json b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.theme.json index 44ccc6d3bf20..f46044961e66 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.theme.json +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.theme.json @@ -695,10 +695,6 @@ "Ide.Shadow": { "borderInsets": "6,10,14,10", - "topLeftSize": "18,14", - "topRightSize": "18,14", - "bottomLeftSize": "18,22", - "bottomRightSize": "18,22", "top0Color": "#2C2C2C92", "top1Color": "#24242492", "bottom0Color": "#20202092", @@ -718,10 +714,6 @@ }, "Notification.Shadow": { "borderInsets": "6,10,6,10", - "topLeftSize": "18,14", - "topRightSize": "18,14", - "bottomLeftSize": "18,22", - "bottomRightSize": "18,22", "top0Color": "#2C2C2C32", "top1Color": "#24242432", "bottom0Color": "#20202032", diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.theme.json b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.theme.json index d51b6969c5d0..8f8b32895cbe 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.theme.json +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.theme.json @@ -406,10 +406,6 @@ "Ide.Shadow": { "borderInsets": "6,10,14,10", - "topLeftSize": "18,14", - "topRightSize": "18,14", - "bottomLeftSize": "18,22", - "bottomRightSize": "18,22", "top0Color": "#FCFCFC92", "top1Color": "#F4F4F492", "bottom0Color": "#F0F0F092", @@ -429,10 +425,6 @@ }, "Notification.Shadow": { "borderInsets": "6,10,6,10", - "topLeftSize": "18,14", - "topRightSize": "18,14", - "bottomLeftSize": "18,22", - "bottomRightSize": "18,22", "top0Color": "#FCFCFC32", "top1Color": "#F4F4F432", "bottom0Color": "#F0F0F032", diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java index 7868019834e0..d01be72ab531 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java @@ -24,6 +24,7 @@ import com.intellij.openapi.wm.impl.IdeFrameImpl; import com.intellij.openapi.wm.impl.IdeGlassPaneEx; import com.intellij.ui.ComponentUtil; import com.intellij.ui.ScreenUtil; +import com.intellij.ui.ShadowJava2DPainter; import com.intellij.ui.components.JBLayeredPane; import com.intellij.ui.jcef.HwFacadeJPanel; import com.intellij.util.MathUtil; @@ -348,8 +349,15 @@ public final class GlassPaneDialogWrapperPeer extends DialogWrapperPeer { private MyDialog(IdeGlassPaneEx pane, DialogWrapper wrapper) { setLayout(new BorderLayout()); setOpaque(false); - setBorder(BorderFactory.createEmptyBorder(AllIcons.Ide.Shadow.Top.getIconHeight(), AllIcons.Ide.Shadow.Left.getIconWidth(), - AllIcons.Ide.Shadow.Bottom.getIconHeight(), AllIcons.Ide.Shadow.Right.getIconWidth())); + + if (ShadowJava2DPainter.Companion.enabled()) { + Insets insets = ShadowJava2DPainter.Companion.getInsets("Ide"); + setBorder(BorderFactory.createEmptyBorder(insets.top, insets.left, insets.bottom, insets.right)); + } + else { + setBorder(BorderFactory.createEmptyBorder(AllIcons.Ide.Shadow.Top.getIconHeight(), AllIcons.Ide.Shadow.Left.getIconWidth(), + AllIcons.Ide.Shadow.Bottom.getIconHeight(), AllIcons.Ide.Shadow.Right.getIconWidth())); + } myPane = pane; myDialogWrapper = new WeakReference<>(wrapper); diff --git a/platform/platform-impl/src/com/intellij/ui/ShadowJava2DPainter.kt b/platform/platform-impl/src/com/intellij/ui/ShadowJava2DPainter.kt index c69aa9096323..96e91a5082dc 100644 --- a/platform/platform-impl/src/com/intellij/ui/ShadowJava2DPainter.kt +++ b/platform/platform-impl/src/com/intellij/ui/ShadowJava2DPainter.kt @@ -2,13 +2,15 @@ package com.intellij.ui import com.intellij.openapi.util.registry.Registry -import com.intellij.util.ui.JBDimension import com.intellij.util.ui.JBInsets import com.intellij.util.ui.JBUI -import java.awt.* +import java.awt.Color +import java.awt.GradientPaint +import java.awt.Graphics2D +import java.awt.Insets + private val DEF_INSETS = JBInsets(5) -private val DEF_SIZE = JBDimension(5, 5) private val DEF_COLOR = Gray._200.withAlpha(50) /** @@ -19,136 +21,84 @@ class ShadowJava2DPainter(private val uiKeyGroup: String, private val roundedCor companion object { fun enabled(): Boolean = Registry.`is`("ide.java2d.shadowEnabled", false) + + fun getInsets(uiKeyGroup: String): Insets = JBUI.insets("${uiKeyGroup}.Shadow.borderInsets", DEF_INSETS) } fun hideBottomSide() { hideBottomSide = true } - fun getInsets(): Insets = JBUI.insets("${uiKeyGroup}.Shadow.borderInsets", DEF_INSETS) + fun getInsets() = Companion.getInsets(uiKeyGroup) fun paintShadow(g: Graphics2D, x: Int, y: Int, width: Int, height: Int) { val insets = getInsets() - val topLeftSize = JBUI.size("${uiKeyGroup}.Shadow.topLeftSize", DEF_SIZE) - val topRightSize = JBUI.size("${uiKeyGroup}.Shadow.topRightSize", DEF_SIZE) - val bottomLeftSize = JBUI.size("${uiKeyGroup}.Shadow.bottomLeftSize", DEF_SIZE) - val bottomRightSize = JBUI.size("${uiKeyGroup}.Shadow.bottomRightSize", DEF_SIZE) - - setGradient(g, "top", 0, insets.top) - g.fillRect(x + topLeftSize.width, y, width - topLeftSize.width - topRightSize.width, insets.top) - - if (!hideBottomSide) { - setGradient(g, "bottom", 0, insets.bottom) - g.fillRect(x + bottomLeftSize.width, y + height - insets.bottom, width - bottomLeftSize.width - bottomRightSize.width, insets.bottom) - } - - setGradient(g, "left", insets.left, 0) - g.fillRect(x, y + topLeftSize.height, insets.left, height - topLeftSize.height - bottomLeftSize.height) - - setGradient(g, "right", insets.right, 0) - g.fillRect(x + width - insets.right, y + topRightSize.height, insets.right, height - topRightSize.height - bottomRightSize.height) + val xxLeft = x + insets.left + val yyTop = y + insets.top + val xxRight = x + width - insets.right + val yyBottom = y + height - insets.bottom + val widthLR = width - insets.left - insets.right + val heightTB = height - insets.top - insets.bottom if (roundedCorners) { - paintArcCorner(g, x, y, topLeftSize, true, true, "topLeft") - paintArcCorner(g, x + width - topRightSize.width, y, topRightSize, true, false, "topRight") + val size = JBUI.scale(6) + + g.color = getColor("topLeft", "1") + g.fillRect(x + insets.left, y + insets.top, size, size) + + g.color = getColor("topRight", "1") + g.fillRect(xxRight - size, y + insets.top, size, size) + if (!hideBottomSide) { - paintArcCorner(g, x + width - bottomRightSize.width, y + height - bottomRightSize.height, bottomRightSize, false, false, - "bottomRight") - paintArcCorner(g, x, y + height - bottomLeftSize.height, bottomLeftSize, false, true, "bottomLeft") + g.color = getColor("bottomRight", "1") + g.fillRect(xxRight - size, yyBottom - size, size, size) + + g.color = getColor("bottomLeft", "1") + g.fillRect(x + insets.left, yyBottom - size, size, size) } } - else { - paintPolygonCorner(g, x, y, width, height, insets, topLeftSize, true, true, "topLeft") - paintPolygonCorner(g, x, y, width, height, insets, topRightSize, true, false, "topRight") - if (!hideBottomSide) { - paintPolygonCorner(g, x, y, width, height, insets, bottomRightSize, false, false, "bottomRight") - paintPolygonCorner(g, x, y, width, height, insets, bottomLeftSize, false, true, "bottomLeft") - } + + setGradient(g, "top", "0", "1", xxLeft, y, xxLeft, yyTop) + g.fillRect(xxLeft, y, widthLR, insets.top) + + if (!hideBottomSide) { + setGradient(g, "bottom", "1", "0", xxLeft, yyBottom, xxLeft, y + height) + g.fillRect(xxLeft, yyBottom, widthLR, insets.bottom) + } + + setGradient(g, "left", "0", "1", x, yyTop, xxLeft, yyTop) + g.fillRect(x, yyTop, insets.left, heightTB) + + setGradient(g, "right", "1", "0", xxRight, yyTop, x + width, yyTop) + g.fillRect(xxRight, yyTop, insets.right, heightTB) + + drawCorner(g, "topLeft", x, y, insets.left, insets.top) + drawCorner(g, "topRight", xxRight, y, insets.right, insets.top) + + if (!hideBottomSide) { + drawCorner(g, "bottomRight", xxRight, yyBottom, insets.right, insets.bottom) + drawCorner(g, "bottomLeft", x, yyBottom, insets.left, insets.bottom) } if (borderColor != null) { + val one = JBUI.scale(1) g.color = borderColor - g.drawRect(x + insets.left - 1, y + insets.top - 1, x + width - insets.left - insets.right + 1, - y + height - insets.top - insets.bottom + 1) + g.drawRect(xxLeft - one, yyTop - one, widthLR + one, heightTB + one) } } - private fun paintArcCorner(g: Graphics2D, x: Int, y: Int, size: Dimension, top: Boolean, left: Boolean, side: String) { - val w2 = size.width * 2 - val h2 = size.height * 2 - - setGradient(g, side, size.width, size.height) - - if (top && left) { - g.fillArc(x, y, w2, h2, 90, 90) - } - else if (top/* && !left*/) { - g.fillArc(x - size.width, y, w2, h2, 0, 90) - } - else if (/*!top && */!left) { - g.fillArc(x - size.width, y - size.height, w2, h2, 0, -90) - } - else /*if (!top && left)*/ { - g.fillArc(x, y - size.height, w2, h2, -90, -90) + private fun drawCorner(g: Graphics2D, side: String, x: Int, y: Int, width: Int, height: Int) { + when (side) { + "topLeft" -> setGradient(g, side, "0", "1", x, y, x + width / 2, y + height / 2) + "topRight" -> setGradient(g, side, "0", "1", x + width, y, x + width / 2, y + height / 2) + "bottomRight" -> setGradient(g, side, "0", "1", x + width, y + height, x + width / 2, y + height / 2) + "bottomLeft" -> setGradient(g, side, "0", "1", x, y + height, x + width / 2, y + height / 2) } + g.fillRect(x, y, width, height) } - private fun paintPolygonCorner(g: Graphics2D, - x: Int, - y: Int, - width: Int, - height: Int, - insets: Insets, - sideSize: Dimension, - top: Boolean, - left: Boolean, - side: String) { - setGradient(g, side, sideSize.width, sideSize.height) - - val polygon = Polygon() - - if (top && left) { - polygon.addPoint(x, y + sideSize.height) - polygon.addPoint(x, y) - polygon.addPoint(x + sideSize.width, y) - polygon.addPoint(x + sideSize.width, y + insets.top) - polygon.addPoint(x + insets.left, y + insets.top) - polygon.addPoint(x + insets.left, y + sideSize.height) - polygon.addPoint(x, y + sideSize.height) - } - else if (top/* && !left*/) { - polygon.addPoint(x + width - sideSize.width, y) - polygon.addPoint(x + width, y) - polygon.addPoint(x + width, y + sideSize.height) - polygon.addPoint(x + width - insets.right, y + sideSize.height) - polygon.addPoint(x + width - insets.right, y + insets.top) - polygon.addPoint(x + width - sideSize.width, y + insets.top) - polygon.addPoint(x + width - sideSize.width, y) - } - else if (/*!top && */!left) { - polygon.addPoint(x + width - sideSize.width, y + height - insets.bottom) - polygon.addPoint(x + width - insets.right, y + height - insets.bottom) - polygon.addPoint(x + width - insets.right, y + height - sideSize.height) - polygon.addPoint(x + width, y + height - sideSize.height) - polygon.addPoint(x + width, y + height) - polygon.addPoint(x + width - sideSize.width, y + height) - polygon.addPoint(x + width - sideSize.width, y + height - insets.bottom) - } - else /*if (!top && left)*/ { - polygon.addPoint(x, y + height) - polygon.addPoint(x, y + height - sideSize.height) - polygon.addPoint(x + insets.left, y + height - sideSize.height) - polygon.addPoint(x + insets.left, y + height - insets.bottom) - polygon.addPoint(x + sideSize.width, y + height - insets.bottom) - polygon.addPoint(x + sideSize.width, y + height) - polygon.addPoint(x, y + height) - } - - g.fillPolygon(polygon) - } - - private fun setGradient(g: Graphics2D, sideKey: String, lengthX: Int, lengthY: Int) { - g.paint = GradientPaint(0f, 0f, getColor(sideKey, "0"), lengthX.toFloat(), lengthY.toFloat(), getColor(sideKey, "1"), true) + private fun setGradient(g: Graphics2D, sideKey: String, gKey0: String, gKey1: String, x0: Int, y0: Int, x1: Int, y1: Int) { + g.paint = GradientPaint(x0.toFloat(), y0.toFloat(), getColor(sideKey, gKey0), x1.toFloat(), y1.toFloat(), getColor(sideKey, gKey1)) } private fun getColor(sideKey: String, gradientKey: String): Color { diff --git a/platform/platform-resources/src/themes/expUI/expUI_dark.theme.json b/platform/platform-resources/src/themes/expUI/expUI_dark.theme.json index 53808fa5d472..4b1dcc8ba74f 100644 --- a/platform/platform-resources/src/themes/expUI/expUI_dark.theme.json +++ b/platform/platform-resources/src/themes/expUI/expUI_dark.theme.json @@ -319,10 +319,6 @@ "Ide.Shadow": { "borderInsets": "6,10,14,10", - "topLeftSize": "18,14", - "topRightSize": "18,14", - "bottomLeftSize": "18,22", - "bottomRightSize": "18,22", "top0Color": "#1C1C1C92", "top1Color": "#14141492", "bottom0Color": "#10101092", @@ -342,10 +338,6 @@ }, "Notification.Shadow": { "borderInsets": "6,10,6,10", - "topLeftSize": "18,14", - "topRightSize": "18,14", - "bottomLeftSize": "18,22", - "bottomRightSize": "18,22", "top0Color": "#1C1C1C32", "top1Color": "#14141432", "bottom0Color": "#10101032", diff --git a/platform/platform-resources/src/themes/expUI/expUI_light.theme.json b/platform/platform-resources/src/themes/expUI/expUI_light.theme.json index ecc78c7f1703..21803b4b8949 100644 --- a/platform/platform-resources/src/themes/expUI/expUI_light.theme.json +++ b/platform/platform-resources/src/themes/expUI/expUI_light.theme.json @@ -343,50 +343,42 @@ }, "Ide.Shadow": { - "borderInsets": "6,10,14,10", - "topLeftSize": "18,14", - "topRightSize": "18,14", - "bottomLeftSize": "18,22", - "bottomRightSize": "18,22", - "top0Color": "#FCFCFC92", - "top1Color": "#F4F4F492", - "bottom0Color": "#F0F0F092", - "bottom1Color": "#FDFDFD92", - "left0Color": "#FDFDFD92", - "left1Color": "#F0F0F092", - "right0Color": "#F0F0F092", - "right1Color": "#FDFDFD92", - "topLeft0Color": "#FDFDFD92", - "topLeft1Color": "#F0F0F092", - "topRight0Color": "#F4F4F492", - "topRight1Color": "#FDFDFD92", - "bottomLeft0Color": "#F3F3F392", - "bottomLeft1Color": "#FCFCFC92", - "bottomRight0Color": "#F0F0F092", - "bottomRight1Color": "#FCFCFC92" + "borderInsets": "10,10,10,10", + "top0Color": "#FF0000", + "top1Color": "#00FF00", + "bottom0Color": "#FF0000", + "bottom1Color": "#00FF00", + "left0Color": "#FF0000", + "left1Color": "#00FF00", + "right0Color": "#FF0000", + "right1Color": "#00FF00", + "topLeft0Color": "#FF0000", + "topLeft1Color": "#00FF00", + "topRight0Color": "#FF0000", + "topRight1Color": "#00FF00", + "bottomLeft0Color": "#FF0000", + "bottomLeft1Color": "#00FF00", + "bottomRight0Color": "#FF0000", + "bottomRight1Color": "#00FF00" }, "Notification.Shadow": { - "borderInsets": "6,10,6,10", - "topLeftSize": "18,14", - "topRightSize": "18,14", - "bottomLeftSize": "18,22", - "bottomRightSize": "18,22", - "top0Color": "#FCFCFC32", - "top1Color": "#F4F4F432", - "bottom0Color": "#F0F0F032", - "bottom1Color": "#FDFDFD32", - "left0Color": "#FDFDFD32", - "left1Color": "#F0F0F032", - "right0Color": "#F0F0F032", - "right1Color": "#FDFDFD32", - "topLeft0Color": "#FDFDFD32", - "topLeft1Color": "#F0F0F032", - "topRight0Color": "#F4F4F432", - "topRight1Color": "#FDFDFD32", - "bottomLeft0Color": "#F3F3F332", - "bottomLeft1Color": "#FCFCFC32", - "bottomRight0Color": "#F0F0F032", - "bottomRight1Color": "#FCFCFC32" + "borderInsets": "10,10,10,10", + "top0Color": "#FF0000", + "top1Color": "#00FF00", + "bottom0Color": "#FF0000", + "bottom1Color": "#00FF00", + "left0Color": "#FF0000", + "left1Color": "#00FF00", + "right0Color": "#FF0000", + "right1Color": "#00FF00", + "topLeft0Color": "#FF0000", + "topLeft1Color": "#00FF00", + "topRight0Color": "#FF0000", + "topRight1Color": "#00FF00", + "bottomLeft0Color": "#FF0000", + "bottomLeft1Color": "#00FF00", + "bottomRight0Color": "#FF0000", + "bottomRight1Color": "#00FF00" }, "Notification": { From 0d430aaff02f9a4012e0697f01906c9e4899ae40 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sun, 2 Jul 2023 06:11:40 +0200 Subject: [PATCH 119/226] [java-intentions] PsiElementEditorPredicate -> PsiElementContextPredicate; all uses converted to ModCommand GitOrigin-RevId: b39a2c838f26997b4322cff61d1d9bb8b6e15eeb --- .../impl/CodeInsightTestFixtureImpl.java | 2 +- .../IntentionPowerPackBundle.properties | 1 - .../src/com/siyeh/ipp/base/Intention.java | 20 ++---- .../src/com/siyeh/ipp/base/MCIntention.java | 16 ++--- .../siyeh/ipp/base/MutablyNamedIntention.java | 2 +- ...e.java => PsiElementContextPredicate.java} | 10 +-- .../siyeh/ipp/base/PsiElementPredicate.java | 3 +- .../expression/FlipSetterCallIntention.java | 60 +++++++++-------- .../ipp/psiutils/PsiSelectionSearcher.java | 32 ++++----- ...OctalEscapeWithUnicodeEscapeIntention.java | 61 +++++++---------- .../ipp/unicode/UnicodeUnescapeIntention.java | 65 ++++++++----------- .../flip_setter_call/Parentheses_after.java | 2 +- .../flip_setter_call/Selection.java | 35 ++++++++++ .../flip_setter_call/Selection_after.java | 35 ++++++++++ .../FlipSetterCallIntentionTest.java | 5 +- 15 files changed, 190 insertions(+), 159 deletions(-) rename plugins/IntentionPowerPak/src/com/siyeh/ipp/base/{PsiElementEditorPredicate.java => PsiElementContextPredicate.java} (67%) create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Selection.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Selection_after.java diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 3dc1a8bf1689..fda87dd821bf 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1845,7 +1845,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig throw new FileComparisonFailure(expectedFile, expectedText, actualText, loader.filePath); } - EditorTestUtil.verifyCaretAndSelectionState(editor, loader.caretState, expectedFile); + EditorTestUtil.verifyCaretAndSelectionState(editor, loader.caretState, expectedFile, loader.filePath); } @NotNull diff --git a/plugins/IntentionPowerPak/resources/messages/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/resources/messages/IntentionPowerPackBundle.properties index c07570af2668..2b185d2b8fd4 100644 --- a/plugins/IntentionPowerPak/resources/messages/IntentionPowerPackBundle.properties +++ b/plugins/IntentionPowerPak/resources/messages/IntentionPowerPackBundle.properties @@ -134,7 +134,6 @@ inline.increment.intention.name=Inline ''{0}'' replace.assert.literal.with.assert.equals.intention.name=Replace ''{0}()'' with ''assertEquals({1}, ...)'' replace.assert.literal.with.assert.equals.intention.name2=Replace ''{0}()'' with ''assertEquals()'' replace.assert.literal.with.assert.equals.intention.name1=Replace ''{0}()'' with ''assertEquals(..., {1}, ...)'' -flip.setter.call.intention.name=Flip Setter Call adapter.to.listener.intention.name=Replace extension of ''{0}'' with ''Listener'' implementation adapter.to.listener.intention.family.name=Replace adapter extension with listener implementation change.variable.type.to.rhs.type.intention.name=Declare ''{0}'' with type ''{1}'' diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java index 745212417b9a..561bf261777b 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java @@ -33,38 +33,32 @@ public abstract class Intention extends BaseElementAtCaretIntentionAction { @Override public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element){ - final PsiElement matchingElement = findMatchingElement(element, editor); + final PsiElement matchingElement = findMatchingElement(element); if (matchingElement == null) { return; } - processIntention(editor, matchingElement); + processIntention(matchingElement); } protected abstract void processIntention(@NotNull PsiElement element); - protected void processIntention(Editor editor, @NotNull PsiElement element) { - processIntention(element); - } - @NotNull protected abstract PsiElementPredicate getElementPredicate(); @Nullable - PsiElement findMatchingElement(@Nullable PsiElement element, Editor editor) { + PsiElement findMatchingElement(@Nullable PsiElement element) { if (element == null || !JavaLanguage.INSTANCE.equals(element.getLanguage())) return null; PsiElementPredicate predicate = myPredicate.get(); + if (predicate instanceof PsiElementContextPredicate) { + throw new UnsupportedOperationException("Context predicate must be used with MCIntention"); + } while (element != null) { if (!JavaLanguage.INSTANCE.equals(element.getLanguage())) { break; } - if (predicate instanceof PsiElementEditorPredicate) { - if (((PsiElementEditorPredicate)predicate).satisfiedBy(element, editor)) { - return element; - } - } else if (predicate.satisfiedBy(element)) { return element; } @@ -78,6 +72,6 @@ public abstract class Intention extends BaseElementAtCaretIntentionAction { @Override public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - return findMatchingElement(element, editor) != null; + return findMatchingElement(element) != null; } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/MCIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/MCIntention.java index b4bf172b96e9..322b4302ddfb 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/MCIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/MCIntention.java @@ -15,12 +15,12 @@ */ package com.siyeh.ipp.base; -import com.intellij.modcommand.ModPsiUpdater; import com.intellij.codeInspection.ModCommands; import com.intellij.codeInspection.util.IntentionName; import com.intellij.lang.java.JavaLanguage; import com.intellij.modcommand.ModCommand; import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.concurrency.SynchronizedClearableLazy; @@ -57,19 +57,19 @@ public abstract class MCIntention implements ModCommandAction { @Nullable - PsiElement findMatchingElement(@Nullable PsiElement element) { + PsiElement findMatchingElement(@Nullable PsiElement element, ActionContext context) { if (element == null || !JavaLanguage.INSTANCE.equals(element.getLanguage())) return null; PsiElementPredicate predicate = myPredicate.get(); - if (predicate instanceof PsiElementEditorPredicate) { - throw new UnsupportedOperationException("Editor predicate is not supported"); - } while (element != null) { if (!JavaLanguage.INSTANCE.equals(element.getLanguage())) { break; } - if (predicate.satisfiedBy(element)) { + boolean satisfied = predicate instanceof PsiElementContextPredicate contextPredicate ? + contextPredicate.satisfiedBy(element, context) : + predicate.satisfiedBy(element); + if (satisfied) { return element; } element = element.getParent(); @@ -91,10 +91,10 @@ public abstract class MCIntention implements ModCommandAction { @Nullable protected PsiElement findMatchingElement(@NotNull ActionContext context) { PsiElement leaf = context.findLeaf(); - PsiElement element = findMatchingElement(leaf); + PsiElement element = findMatchingElement(leaf, context); if (element != null) return element; PsiElement leftLeaf = context.findLeafOnTheLeft(); - if (leftLeaf != leaf) return findMatchingElement(leftLeaf); + if (leftLeaf != leaf) return findMatchingElement(leftLeaf, context); return null; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/MutablyNamedIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/MutablyNamedIntention.java index 86ff2d3d394f..87a1a4b63b10 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/MutablyNamedIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/MutablyNamedIntention.java @@ -36,7 +36,7 @@ public abstract class MutablyNamedIntention extends Intention { @Override public final boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement node) { - final PsiElement element = findMatchingElement(node, editor); + final PsiElement element = findMatchingElement(node); if (element == null) { return false; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementEditorPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementContextPredicate.java similarity index 67% rename from plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementEditorPredicate.java rename to plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementContextPredicate.java index 639a4aaa9254..b38193b66e1a 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementEditorPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementContextPredicate.java @@ -15,15 +15,15 @@ */ package com.siyeh.ipp.base; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ModCommandAction; import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; -public abstract class PsiElementEditorPredicate implements PsiElementPredicate { - public abstract boolean satisfiedBy(PsiElement element, @Nullable Editor editor); +public abstract class PsiElementContextPredicate implements PsiElementPredicate { + public abstract boolean satisfiedBy(PsiElement element, @NotNull ModCommandAction.ActionContext context); @Override public boolean satisfiedBy(PsiElement element) { - return satisfiedBy(element, null); + throw new UnsupportedOperationException("Context must be provided"); } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementPredicate.java index 5c016f7fa343..616a4095945d 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/PsiElementPredicate.java @@ -19,7 +19,8 @@ import com.intellij.psi.PsiElement; public interface PsiElementPredicate { /** - * Use {@link PsiElementEditorPredicate} when editor selection should be checked + * Check if element satisfies the predicate. All parent elements are supplied here until the satisfying element is found. + * Use {@link PsiElementContextPredicate} if you need caret position and/or selection. */ boolean satisfiedBy(PsiElement element); } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/expression/FlipSetterCallIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/expression/FlipSetterCallIntention.java index ebcc7bb31d00..6078a3070735 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/expression/FlipSetterCallIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/expression/FlipSetterCallIntention.java @@ -1,17 +1,15 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ipp.expression; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.project.Project; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.psi.*; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiUtil; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ExpressionUtils; -import com.siyeh.ipp.base.Intention; -import com.siyeh.ipp.base.PsiElementEditorPredicate; +import com.siyeh.ipp.base.MCIntention; +import com.siyeh.ipp.base.PsiElementContextPredicate; import com.siyeh.ipp.base.PsiElementPredicate; import com.siyeh.ipp.psiutils.PsiSelectionSearcher; import org.jetbrains.annotations.NotNull; @@ -22,7 +20,11 @@ import java.util.List; /** * @author Konstantin Bulenkov */ -public class FlipSetterCallIntention extends Intention { +public class FlipSetterCallIntention extends MCIntention { + @Override + protected @Nullable String getTextForElement(@NotNull PsiElement element) { + return getFamilyName(); + } @Override public @NotNull String getFamilyName() { @@ -30,27 +32,23 @@ public class FlipSetterCallIntention extends Intention { } @Override - public @NotNull String getText() { - return IntentionPowerPackBundle.message("flip.setter.call.intention.name"); - } - - @Override - protected void processIntention(@NotNull PsiElement element) { - final Project project = element.getProject(); - final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); - if (editor != null) { + protected void processIntention(@NotNull ActionContext context, @NotNull ModPsiUpdater updater, @NotNull PsiElement element) { + if (!context.selection().isEmpty()) { final List methodCalls = - PsiSelectionSearcher.searchElementsInSelection(editor, project, PsiMethodCallExpression.class, false); + PsiSelectionSearcher.searchElementsInSelection(element.getContainingFile(), context.selection(), PsiMethodCallExpression.class, false); if (!methodCalls.isEmpty()) { for (PsiMethodCallExpression call : methodCalls) { - flipCall(call); + PsiMethodCallExpression flipped = flipCall(call); + if (flipped != null) { + updater.highlight(flipped); + updater.moveTo(flipped); + } } - editor.getSelectionModel().removeSelection(); return; } } - if (element instanceof PsiMethodCallExpression) { - flipCall((PsiMethodCallExpression)element); + if (element instanceof PsiMethodCallExpression call) { + flipCall(call); } } @@ -60,24 +58,24 @@ public class FlipSetterCallIntention extends Intention { return new SetterCallPredicate(); } - private static void flipCall(PsiMethodCallExpression call) { + private static PsiMethodCallExpression flipCall(PsiMethodCallExpression call) { final PsiExpression[] arguments = call.getArgumentList().getExpressions(); - if (arguments.length != 1) return; + if (arguments.length != 1) return null; final PsiExpression argument = PsiUtil.skipParenthesizedExprDown(arguments[0]); - if (!(argument instanceof PsiMethodCallExpression call2)) return; + if (!(argument instanceof PsiMethodCallExpression call2)) return null; final PsiExpression qualifierExpression1 = ExpressionUtils.getEffectiveQualifier(call.getMethodExpression()); final PsiExpression qualifierExpression2 = ExpressionUtils.getEffectiveQualifier(call2.getMethodExpression()); - if (qualifierExpression1 == null || qualifierExpression2 == null) return; + if (qualifierExpression1 == null || qualifierExpression2 == null) return null; final PsiMethod setter = call.resolveMethod(); final PsiMethod getter = call2.resolveMethod(); final PsiMethod get = PropertyUtil.getReversePropertyMethod(setter); final PsiMethod set = PropertyUtil.getReversePropertyMethod(getter); - if (get == null || set == null) return; + if (get == null || set == null) return null; CommentTracker ct = new CommentTracker(); final String text = ct.text(qualifierExpression2) + "." + set.getName() + "(" + ct.text(qualifierExpression1) + "." + get.getName() + "())"; - ct.replaceAndRestoreComments(call, text); + return (PsiMethodCallExpression)ct.replaceAndRestoreComments(call, text); } private static boolean isSetGetMethodCall(PsiElement element) { @@ -109,12 +107,12 @@ public class FlipSetterCallIntention extends Intention { return parameter.getType().equals(getter.getReturnType()); } - private static class SetterCallPredicate extends PsiElementEditorPredicate { + private static class SetterCallPredicate extends PsiElementContextPredicate { @Override - public boolean satisfiedBy(PsiElement element, @Nullable Editor editor) { - if (editor != null && editor.getSelectionModel().hasSelection()) { + public boolean satisfiedBy(PsiElement element, @NotNull ActionContext context) { + if (!context.selection().isEmpty()) { final List list = - PsiSelectionSearcher.searchElementsInSelection(editor, element.getProject(), PsiMethodCallExpression.class, false); + PsiSelectionSearcher.searchElementsInSelection(context.file(), context.selection(), PsiMethodCallExpression.class, false); for (PsiMethodCallExpression methodCallExpression : list) { if (isSetGetMethodCall(methodCallExpression)) { return true; diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/PsiSelectionSearcher.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/PsiSelectionSearcher.java index 26d9bbafce6c..f283011ef063 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/PsiSelectionSearcher.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/PsiSelectionSearcher.java @@ -1,14 +1,11 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ipp.psiutils; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.SelectionModel; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.UnfairTextRange; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -24,24 +21,17 @@ public final class PsiSelectionSearcher { /** * Searches elements in selection * - * @param editor editor to get text selection - * @param project Project - * @param filter PsiElement filter, e.g. PsiMethodCallExpression.class + * @param file file to search in + * @param selection selected range + * @param filter PsiElement filter, e.g. PsiMethodCallExpression.class * @param searchChildrenOfFound if true, visitor will look for matching elements in the children of a found element, otherwise will not look inside found element. - * @param type based on PsiElement type + * @param type based on PsiElement type * @return elements in selection */ @NotNull - public static List searchElementsInSelection(Editor editor, - Project project, - final Class filter, - final boolean searchChildrenOfFound) { - final SelectionModel selectionModel = editor.getSelectionModel(); - if (!selectionModel.hasSelection()) { - return Collections.emptyList(); - } - final TextRange selection = new UnfairTextRange(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); - final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); + public static List searchElementsInSelection(@Nullable PsiFile file, + @NotNull TextRange selection, + @NotNull Class filter, boolean searchChildrenOfFound) { if (file == null || file instanceof PsiCompiledElement) { return Collections.emptyList(); } @@ -53,8 +43,8 @@ public final class PsiSelectionSearcher { if (!selection.intersects(element.getTextRange())) { return; } - if (filter.isAssignableFrom(element.getClass())) { - results.add((T)element); + if (filter.isInstance(element)) { + results.add(filter.cast(element)); if (!searchChildrenOfFound) { return; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/ReplaceOctalEscapeWithUnicodeEscapeIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/ReplaceOctalEscapeWithUnicodeEscapeIntention.java index 35a1fdf7c002..a09d5c496137 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/ReplaceOctalEscapeWithUnicodeEscapeIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/ReplaceOctalEscapeWithUnicodeEscapeIntention.java @@ -1,17 +1,15 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ipp.unicode; -import com.intellij.openapi.editor.CaretModel; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiLiteralExpression; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ig.PsiReplacementUtil; -import com.siyeh.ipp.base.Intention; -import com.siyeh.ipp.base.PsiElementEditorPredicate; +import com.siyeh.ipp.base.MCIntention; +import com.siyeh.ipp.base.PsiElementContextPredicate; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -20,7 +18,7 @@ import org.jetbrains.annotations.Nullable; /** * @author Bas Leijdekkers */ -public class ReplaceOctalEscapeWithUnicodeEscapeIntention extends Intention { +public class ReplaceOctalEscapeWithUnicodeEscapeIntention extends MCIntention { @Override public @NotNull String getFamilyName() { @@ -28,23 +26,18 @@ public class ReplaceOctalEscapeWithUnicodeEscapeIntention extends Intention { } @Override - public @NotNull String getText() { + protected @Nullable String getTextForElement(@NotNull PsiElement element) { return IntentionPowerPackBundle.message("replace.octal.escape.with.unicode.escape.intention.name"); } @Override - protected void processIntention(@NotNull PsiElement element) {} - - @Override - protected void processIntention(Editor editor, @NotNull PsiElement element) { - final SelectionModel selectionModel = editor.getSelectionModel(); - if (selectionModel.hasSelection()) { + protected void processIntention(@NotNull ActionContext context, @NotNull ModPsiUpdater updater, @NotNull PsiElement element) { + TextRange selection = context.selection(); + if (!selection.isEmpty()) { // does not check if octal escape is inside char or string literal (garbage in, garbage out) - final Document document = editor.getDocument(); - final int start = selectionModel.getSelectionStart(); - final int end = selectionModel.getSelectionEnd(); - final String text = document.getText(new TextRange(start, end)); - final int textLength = end - start; + final Document document = element.getContainingFile().getViewProvider().getDocument(); + final String text = document.getText(selection); + final int textLength = selection.getLength(); final StringBuilder replacement = new StringBuilder(textLength); int anchor = 0; while (true) { @@ -56,12 +49,13 @@ public class ReplaceOctalEscapeWithUnicodeEscapeIntention extends Intention { anchor = appendUnicodeEscape(text, index, replacement); } replacement.append(text, anchor, textLength); + final int start = selection.getStartOffset(); + final int end = selection.getEndOffset(); document.replaceString(start, end, replacement); } else if (element instanceof PsiLiteralExpression literalExpression) { final String text = literalExpression.getText(); - final CaretModel model = editor.getCaretModel(); - final int offset = model.getOffset() - literalExpression.getTextOffset(); + final int offset = context.offset() - literalExpression.getTextOffset(); final StringBuilder newLiteralText = new StringBuilder(); final int index1 = indexOfOctalEscape(text, offset); final int index2 = indexOfOctalEscape(text, offset + 1); @@ -139,27 +133,20 @@ public class ReplaceOctalEscapeWithUnicodeEscapeIntention extends Intention { return new OctalEscapePredicate(); } - private static class OctalEscapePredicate extends PsiElementEditorPredicate { + private static class OctalEscapePredicate extends PsiElementContextPredicate { @Override - public boolean satisfiedBy(PsiElement element, @Nullable Editor editor) { - if (editor == null) { - return false; - } - final SelectionModel selectionModel = editor.getSelectionModel(); - if (selectionModel.hasSelection()) { - final int start = selectionModel.getSelectionStart(); - final int end = selectionModel.getSelectionEnd(); - if (start < 0 || end < 0 || start > end) { - // shouldn't happen but http://ea.jetbrains.com/browser/ea_problems/51155 - return false; - } - final String text = editor.getDocument().getCharsSequence().subSequence(start, end).toString(); + public boolean satisfiedBy(PsiElement element, @NotNull ActionContext context) { + TextRange selection = context.selection(); + if (!selection.isEmpty()) { + final int start = selection.getStartOffset(); + final int end = selection.getEndOffset(); + final String text = element.getContainingFile().getViewProvider().getDocument() + .getCharsSequence().subSequence(start, end).toString(); return indexOfOctalEscape(text, 1) >= 0; } else if (element instanceof PsiLiteralExpression literalExpression) { final String text = literalExpression.getText(); - final CaretModel model = editor.getCaretModel(); - final int offset = model.getOffset() - literalExpression.getTextOffset(); + final int offset = context.offset() - literalExpression.getTextOffset(); final int index = indexOfOctalEscape(text, offset); return index >= 0 && offset >= index; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java index 5eef781a254e..9151f21954f8 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java @@ -1,16 +1,15 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ipp.unicode; -import com.intellij.openapi.editor.CaretModel; +import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.siyeh.IntentionPowerPackBundle; -import com.siyeh.ipp.base.Intention; -import com.siyeh.ipp.base.PsiElementEditorPredicate; +import com.siyeh.ipp.base.MCIntention; +import com.siyeh.ipp.base.PsiElementContextPredicate; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,7 +17,7 @@ import org.jetbrains.annotations.Nullable; /** * @author Bas Leijdekkers */ -public class UnicodeUnescapeIntention extends Intention { +public class UnicodeUnescapeIntention extends MCIntention { @Override public @NotNull String getFamilyName() { @@ -26,23 +25,18 @@ public class UnicodeUnescapeIntention extends Intention { } @Override - public @NotNull String getText() { + protected @Nullable String getTextForElement(@NotNull PsiElement element) { return IntentionPowerPackBundle.message("unicode.unescape.intention.name"); } @Override - protected void processIntention(@NotNull PsiElement element) {} - - @Override - protected void processIntention(Editor editor, @NotNull PsiElement element) { - final SelectionModel selectionModel = editor.getSelectionModel(); - if (selectionModel.hasSelection()) { + protected void processIntention(@NotNull ActionContext context, @NotNull ModPsiUpdater updater, @NotNull PsiElement element) { + TextRange selection = context.selection(); + final Document document = element.getContainingFile().getViewProvider().getDocument(); + if (!selection.isEmpty()) { // does not check if Unicode escape is inside char or string literal (garbage in, garbage out) - final Document document = editor.getDocument(); - final int start = selectionModel.getSelectionStart(); - final int end = selectionModel.getSelectionEnd(); - final String text = document.getText(new TextRange(start, end)); - final int textLength = end - start; + final String text = document.getText(selection); + final int textLength = selection.getLength(); final StringBuilder replacement = new StringBuilder(textLength); int anchor = 0; while (true) { @@ -60,15 +54,15 @@ public class UnicodeUnescapeIntention extends Intention { replacement.appendCodePoint(c); } replacement.append(text, anchor, textLength); + final int start = selection.getStartOffset(); + final int end = selection.getEndOffset(); document.replaceString(start, end, replacement); } else { - final CaretModel caretModel = editor.getCaretModel(); - final Document document = editor.getDocument(); - final int lineNumber = document.getLineNumber(caretModel.getOffset()); + final int lineNumber = document.getLineNumber(context.offset()); final int lineStartOffset = document.getLineStartOffset(lineNumber); final String line = document.getText(new TextRange(lineStartOffset, document.getLineEndOffset(lineNumber))); - final int column = caretModel.getLogicalPosition().column; + final int column = context.offset() - lineStartOffset; final int index1 = indexOfUnicodeEscape(line, column); final int index2 = indexOfUnicodeEscape(line, column + 1); // if the caret is between two unicode escapes, replace the one to the right @@ -155,17 +149,14 @@ public class UnicodeUnescapeIntention extends Intention { return new UnicodeEscapePredicate(); } - private static class UnicodeEscapePredicate extends PsiElementEditorPredicate { + private static class UnicodeEscapePredicate extends PsiElementContextPredicate { @Override - public boolean satisfiedBy(PsiElement element, @Nullable Editor editor) { - if (editor == null) { - return false; - } - final SelectionModel selectionModel = editor.getSelectionModel(); - final Document document = editor.getDocument(); - if (selectionModel.hasSelection()) { - final int start = selectionModel.getSelectionStart(); - final int end = selectionModel.getSelectionEnd(); + public boolean satisfiedBy(PsiElement element, @NotNull ModCommandAction.ActionContext context) { + TextRange selection = context.selection(); + Document document = element.getContainingFile().getViewProvider().getDocument(); + if (!selection.isEmpty()) { + final int start = selection.getStartOffset(); + final int end = selection.getEndOffset(); if (start < 0 || end < 0 || start > end) { // shouldn't happen but http://ea.jetbrains.com/browser/ea_problems/50192 return false; @@ -174,10 +165,10 @@ public class UnicodeUnescapeIntention extends Intention { return indexOfUnicodeEscape(text, 1) >= 0; } else { - final CaretModel caretModel = editor.getCaretModel(); - final int lineNumber = document.getLineNumber(caretModel.getOffset()); - final String line = document.getText(new TextRange(document.getLineStartOffset(lineNumber), document.getLineEndOffset(lineNumber))); - final int column = caretModel.getLogicalPosition().column; + final int lineNumber = document.getLineNumber(context.offset()); + int lineStart = document.getLineStartOffset(lineNumber); + final String line = document.getText(new TextRange(lineStart, document.getLineEndOffset(lineNumber))); + final int column = context.offset() - lineStart; final int index = indexOfUnicodeEscape(line, column); return index >= 0 && column >= index; } diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Parentheses_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Parentheses_after.java index be17232a18f8..84e4fe8c2d5f 100644 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Parentheses_after.java +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Parentheses_after.java @@ -11,6 +11,6 @@ class X { void test(X a, X b) { /*comment*/ - b.setName(a.getName()); + b.setName(a.getName()); } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Selection.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Selection.java new file mode 100644 index 000000000000..e1c21fa0853d --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Selection.java @@ -0,0 +1,35 @@ +public class MyClass { + String firstName; + String lastName; + int age; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + void copy(MyClass c) { + setFirstName(c.getFirstName()); + setLastName(c.getLastName()); + setAge(c.getAge()); + } +} diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Selection_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Selection_after.java new file mode 100644 index 000000000000..c56e486ee6f1 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/expression/flip_setter_call/Selection_after.java @@ -0,0 +1,35 @@ +public class MyClass { + String firstName; + String lastName; + int age; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + void copy(MyClass c) { + c.setFirstName(this.getFirstName()); + c.setLastName(this.getLastName()); + c.setAge(this.getAge()); + } +} diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/expression/FlipSetterCallIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/expression/FlipSetterCallIntentionTest.java index 76265ad1a2e7..a6636554e36e 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/expression/FlipSetterCallIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/expression/FlipSetterCallIntentionTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ipp.expression; import com.siyeh.IntentionPowerPackBundle; @@ -11,10 +11,11 @@ public class FlipSetterCallIntentionTest extends IPPTestCase { public void testSimple() { doTest(); } public void testUnqualified() { doTest(); } public void testParentheses() { doTest(); } + public void testSelection() { doTest(); } @Override protected String getIntentionName() { - return IntentionPowerPackBundle.message("flip.setter.call.intention.name"); + return IntentionPowerPackBundle.message("flip.setter.call.intention.family.name"); } @Override From 223ed61b317775df87a0e0747666b3e7d66c3b48 Mon Sep 17 00:00:00 2001 From: "eugene.nizienko" Date: Sun, 2 Jul 2023 12:07:06 +0200 Subject: [PATCH 120/226] [IDEA-321907] added flag for UI tests to switch off import config dialog on startup GitOrigin-RevId: 719a66b8dadd6e8c70c211e0d87c93bc4e58d2f6 --- platform/platform-impl/src/com/intellij/idea/StartupUtil.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt b/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt index 301c226da7df..dcd37cb4c363 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt @@ -336,6 +336,10 @@ fun CoroutineScope.startApplication(args: List, } fun isConfigImportNeeded(configPath: Path): Boolean { + // switch off import dialog for UI tests + if (java.lang.Boolean.getBoolean("idea.is.force.import.config.switched.off")) { + return false + } return !Files.exists(configPath) || Files.exists(configPath.resolve(ConfigImportHelper.CUSTOM_MARKER_FILE_NAME)) || customTargetDirectoryToImportConfig != null From ffb895bb5963e46385e08d038361c277c30b18cf Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 30 Jun 2023 15:37:57 +0200 Subject: [PATCH 121/226] Rename .java to .kt GitOrigin-RevId: c1dc98e6e3ac35c65d92eea2f87bb6baa2f55652 --- .../openapi/actionSystem/impl/{ActionMenu.java => ActionMenu.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/{ActionMenu.java => ActionMenu.kt} (100%) diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt similarity index 100% rename from platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.java rename to platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt From 3513975f9ee19fb1461e9031199e2fd786bf6be5 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 30 Jun 2023 15:37:58 +0200 Subject: [PATCH 122/226] convert ActionMenu to kotlin GitOrigin-RevId: 29fbf8ca5cc4176800876dbc28cfed49f46d89d8 --- .../openapi/actionSystem/impl/ActionMenu.kt | 902 ++++++++---------- 1 file changed, 424 insertions(+), 478 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt index 429ceb88fde9..40ca9f11ee10 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt @@ -1,666 +1,612 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.openapi.actionSystem.impl; +package com.intellij.openapi.actionSystem.impl -import com.intellij.ide.DataManager; -import com.intellij.ide.IdeEventQueue; -import com.intellij.ide.ui.UISettings; -import com.intellij.internal.inspector.UiInspectorUtil; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.MainMenuPresentationAware; -import com.intellij.openapi.actionSystem.impl.actionholder.ActionRef; -import com.intellij.openapi.actionSystem.impl.actionholder.ActionRefKt; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.ui.JBPopupMenu; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.openapi.wm.IdeFrame; -import com.intellij.openapi.wm.StatusBar; -import com.intellij.ui.ColorUtil; -import com.intellij.ui.ComponentUtil; -import com.intellij.ui.ExperimentalUI; -import com.intellij.ui.JBColor; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.ui.components.JBMenu; -import com.intellij.ui.icons.IconUtilKt; -import com.intellij.ui.mac.foundation.NSDefaults; -import com.intellij.ui.mac.screenmenu.Menu; -import com.intellij.ui.plaf.beg.BegMenuItemUI; -import com.intellij.ui.plaf.beg.IdeaMenuUI; -import com.intellij.util.*; -import com.intellij.util.concurrency.EdtScheduledExecutorService; -import com.intellij.util.concurrency.annotations.RequiresEdt; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.intellij.ide.DataManager +import com.intellij.ide.IdeEventQueue +import com.intellij.ide.IdeEventQueue.Companion.getInstance +import com.intellij.ide.ui.UISettings.Companion.instanceOrNull +import com.intellij.internal.inspector.UiInspectorContextProvider +import com.intellij.internal.inspector.UiInspectorUtil +import com.intellij.openapi.Disposable +import com.intellij.openapi.actionSystem.* +import com.intellij.openapi.actionSystem.ex.MainMenuPresentationAware +import com.intellij.openapi.actionSystem.impl.actionholder.ActionRef +import com.intellij.openapi.actionSystem.impl.actionholder.createActionRef +import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.ui.JBPopupMenu +import com.intellij.openapi.util.* +import com.intellij.openapi.util.IconLoader.getDarkIcon +import com.intellij.openapi.util.IconLoader.getDisabledIcon +import com.intellij.openapi.util.registry.Registry +import com.intellij.openapi.wm.IdeFocusManager +import com.intellij.openapi.wm.IdeFrame +import com.intellij.openapi.wm.StatusBar +import com.intellij.ui.ColorUtil +import com.intellij.ui.ComponentUtil +import com.intellij.ui.ExperimentalUI +import com.intellij.ui.JBColor +import com.intellij.ui.awt.RelativePoint +import com.intellij.ui.components.JBMenu +import com.intellij.ui.icons.getMenuBarIcon +import com.intellij.ui.mac.foundation.NSDefaults +import com.intellij.ui.mac.screenmenu.Menu +import com.intellij.ui.plaf.beg.BegMenuItemUI +import com.intellij.ui.plaf.beg.IdeaMenuUI +import com.intellij.util.* +import com.intellij.util.concurrency.EdtScheduledExecutorService +import com.intellij.util.concurrency.annotations.RequiresEdt +import java.awt.* +import java.awt.event.AWTEventListener +import java.awt.event.ComponentEvent +import java.awt.event.KeyEvent +import java.awt.event.MouseEvent +import java.util.concurrent.ScheduledFuture +import java.util.concurrent.TimeUnit +import javax.swing.* +import javax.swing.event.ChangeEvent +import javax.swing.event.ChangeListener +import javax.swing.event.MenuEvent +import javax.swing.event.MenuListener -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.event.MenuEvent; -import javax.swing.event.MenuListener; -import java.awt.*; -import java.awt.event.AWTEventListener; -import java.awt.event.ComponentEvent; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; -import java.util.Arrays; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; +class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, + place: String, + group: ActionGroup, + presentationFactory: PresentationFactory, + enableMnemonics: Boolean, + useDarkIcons: Boolean, + headerMenuItem: Boolean = false) : JBMenu() { + private val myPlace: String? + private val myGroup: ActionRef + private val myPresentationFactory: PresentationFactory + private val myPresentation: Presentation + private var myMnemonicEnabled: Boolean + private var myStubItem: StubItem? = null // A PATCH!!! Do not remove this code, otherwise you will lose all keyboard navigation in JMenuBar. + private val myUseDarkIcons: Boolean + private var myDisposable: Disposable? = null + var screenMenuPeer: Menu? = null + private val mySubElementSelector: SubElementSelector? + val isHeaderMenuItem: Boolean + val anAction: AnAction + get() = myGroup.getAction() -public final class ActionMenu extends JBMenu { - /** - * By default, a "performable" non-empty popup action group menu item still shows a submenu. - * Use this key to disable the submenu and avoid children expansion on update as follows: - *

- * {@code presentation.putClientProperty(ActionMenu.SUPPRESS_SUBMENU, true)}. - *

- * Both ordinary and template presentations are supported. - * - * @see Presentation#setPerformGroup(boolean) - */ - public static final Key SUPPRESS_SUBMENU = Key.create("SUPPRESS_SUBMENU"); - - private final String myPlace; - private final DataContext myContext; - private final ActionRef myGroup; - private final PresentationFactory myPresentationFactory; - private final Presentation myPresentation; - private boolean myMnemonicEnabled; - private StubItem myStubItem; // A PATCH!!! Do not remove this code, otherwise you will lose all keyboard navigation in JMenuBar. - private final boolean myUseDarkIcons; - private Disposable myDisposable; - private final @Nullable Menu myScreenMenuPeer; - private final @Nullable SubElementSelector mySubElementSelector; - private final boolean myHeaderMenuItem; - - public ActionMenu(@Nullable DataContext context, - @NotNull String place, - @NotNull ActionGroup group, - @NotNull PresentationFactory presentationFactory, - boolean enableMnemonics, - boolean useDarkIcons) { - this(context, place, group, presentationFactory, enableMnemonics, useDarkIcons, false); + override fun removeNotify() { + super.removeNotify() + if (myDisposable != null) { + Disposer.dispose(myDisposable!!) + myDisposable = null + } } - public ActionMenu(@Nullable DataContext context, - @NotNull String place, - @NotNull ActionGroup group, - @NotNull PresentationFactory presentationFactory, - boolean enableMnemonics, - boolean useDarkIcons, - boolean headerMenuItem) { - myContext = context; - myPlace = place; - myGroup = ActionRefKt.createActionRef(group); - myPresentationFactory = presentationFactory; - myPresentation = myPresentationFactory.getPresentation(group); - myMnemonicEnabled = enableMnemonics; - myUseDarkIcons = useDarkIcons; - myHeaderMenuItem = headerMenuItem; - mySubElementSelector = SubElementSelector.isForceDisabled ? null : new SubElementSelector(this); + private var specialMenu: JPopupMenu? = null - if (Menu.isJbScreenMenuEnabled() && ActionPlaces.MAIN_MENU.equals(myPlace)) { - myScreenMenuPeer = new Menu(myPresentation.getText(enableMnemonics)); - myScreenMenuPeer.setOnOpen(() -> { + init { + myPlace = place + myGroup = createActionRef(group) + myPresentationFactory = presentationFactory + myPresentation = myPresentationFactory.getPresentation(group) + myMnemonicEnabled = enableMnemonics + myUseDarkIcons = useDarkIcons + isHeaderMenuItem = headerMenuItem + mySubElementSelector = if (SubElementSelector.isForceDisabled) null else SubElementSelector(this) + if (Menu.isJbScreenMenuEnabled() && ActionPlaces.MAIN_MENU == myPlace) { + val screenMenuPeer = Menu(myPresentation.getText(enableMnemonics)) + this.screenMenuPeer = screenMenuPeer + screenMenuPeer.setOnOpen(Runnable { // NOTE: setSelected(true) calls fillMenu internally - setSelected(true); - }, this); - myScreenMenuPeer.setOnClose(() -> setSelected(false), this); - myScreenMenuPeer.listenPresentationChanges(myPresentation); + setSelected(true) + }, this) + screenMenuPeer.setOnClose(Runnable { setSelected(false) }, this) + screenMenuPeer.listenPresentationChanges(myPresentation) } else { - myScreenMenuPeer = null; - updateUI(); + screenMenuPeer = null + updateUI() } - - init(); - - if (myScreenMenuPeer == null) { + init() + if (screenMenuPeer == null) { // also triggering initialization of private field "popupMenu" from JMenu with our own JBPopupMenu - BegMenuItemUI.registerMultiChoiceSupport(getPopupMenu(), popupMenu -> { - Utils.updateMenuItems(popupMenu, getDataContext(), myPlace, myPresentationFactory); - }); + BegMenuItemUI.registerMultiChoiceSupport(getPopupMenu()) { popupMenu: JPopupMenu? -> + Utils.updateMenuItems( + popupMenu!!, dataContext, myPlace, myPresentationFactory) + } } } - public @NotNull AnAction getAnAction() { return myGroup.getAction(); } + companion object { + /** + * By default, a "performable" non-empty popup action group menu item still shows a submenu. + * Use this key to disable the submenu and avoid children expansion on update as follows: + * + * + * `presentation.putClientProperty(ActionMenu.SUPPRESS_SUBMENU, true)`. + * + * + * Both ordinary and template presentations are supported. + * + * @see Presentation.setPerformGroup + */ + @JvmField + val SUPPRESS_SUBMENU: Key = Key.create("SUPPRESS_SUBMENU") - @Override - public void removeNotify() { - super.removeNotify(); - if (myDisposable != null) { - Disposer.dispose(myDisposable); - myDisposable = null; + @JvmStatic + fun shouldConvertIconToDarkVariant(): Boolean { + return JBColor.isBright() && ColorUtil.isDark(JBColor.namedColor("MenuItem.background", 0xffffff)) + } + + @JvmStatic + val isShowNoIcons: Boolean + get() { + return SystemInfoRt.isMac && (Registry.get("ide.macos.main.menu.alignment.options").isOptionEnabled("No icons") || ExperimentalUI.isNewUI()) + } + + @JvmStatic + fun isShowNoIcons(action: AnAction?): Boolean { + if (action == null) { + return false + } + return if (action is MainMenuPresentationAware && (action as MainMenuPresentationAware).alwaysShowIconInMainMenu()) { + false + } + else isShowNoIcons + } + + @JvmStatic + val isAligned: Boolean + get() = SystemInfoRt.isMac && Registry.get("ide.macos.main.menu.alignment.options").isOptionEnabled("Aligned") + @JvmStatic + val isAlignedInGroup: Boolean + get() = SystemInfoRt.isMac && Registry.get("ide.macos.main.menu.alignment.options").isOptionEnabled("Aligned in group") + + @JvmStatic + fun showDescriptionInStatusBar(isIncluded: Boolean, component: Component?, description: @NlsContexts.StatusBarText String?) { + val frame = (if (component is IdeFrame) component else SwingUtilities.getAncestorOfClass(IdeFrame::class.java, component)) as? IdeFrame + var statusBar: StatusBar? = null + if (frame != null && frame.getStatusBar().also { statusBar = it!! } != null) { + statusBar!!.setInfo(if (isIncluded) description else null) + } } } - private JPopupMenu mySpecialMenu; - - @Override - public JPopupMenu getPopupMenu() { - if (mySpecialMenu == null) { - mySpecialMenu = new JBPopupMenu(); - mySpecialMenu.setInvoker(this); - popupListener = createWinListener(mySpecialMenu); - ReflectionUtil.setField(JMenu.class, this, JPopupMenu.class, "popupMenu", mySpecialMenu); - UiInspectorUtil.registerProvider(mySpecialMenu, () -> UiInspectorUtil.collectActionGroupInfo("Menu", myGroup.getAction(), myPlace)); + override fun getPopupMenu(): JPopupMenu { + var specialMenu = specialMenu + if (specialMenu == null) { + specialMenu = JBPopupMenu() + this.specialMenu = specialMenu + specialMenu.setInvoker(this) + popupListener = createWinListener(specialMenu) + ReflectionUtil.setField(JMenu::class.java, this, JPopupMenu::class.java, "popupMenu", specialMenu) + UiInspectorUtil.registerProvider(specialMenu, UiInspectorContextProvider { + UiInspectorUtil.collectActionGroupInfo("Menu", myGroup.getAction(), myPlace) + }) } - return super.getPopupMenu(); + return super.getPopupMenu() } - @Override - public void updateUI() { + override fun updateUI() { // null myPlace means that Swing calls updateUI before our constructor - if (myScreenMenuPeer != null || myPlace == null) { - return; + if (screenMenuPeer != null || myPlace == null) { + return } - - setUI(IdeaMenuUI.createUI(this)); - setFont(FontUtil.getMenuFont()); - - JPopupMenu popupMenu = getPopupMenu(); + setUI(IdeaMenuUI.createUI(this)) + setFont(FontUtil.getMenuFont()) + val popupMenu = getPopupMenu() if (popupMenu != null) { - popupMenu.updateUI(); + popupMenu.updateUI() } } - public @Nullable Menu getScreenMenuPeer() { - return myScreenMenuPeer; + private fun init() { + val macSystemMenu = SystemInfo.isMacSystemMenu && isMainMenuPlace + myStubItem = if (macSystemMenu) null else StubItem() + addStubItem() + setBorderPainted(false) + val menuListener = MenuListenerImpl() + addMenuListener(menuListener) + getModel().addChangeListener(menuListener) + updateFromPresentation(myMnemonicEnabled) } - public boolean isHeaderMenuItem() { - return myHeaderMenuItem; + val isMainMenuPlace: Boolean + get() = myPlace == ActionPlaces.MAIN_MENU + + fun updateFromPresentation(enableMnemonics: Boolean) { + myMnemonicEnabled = enableMnemonics + isVisible = myPresentation.isVisible + setEnabled(myPresentation.isEnabled) + setText(myPresentation.getText(myMnemonicEnabled)) + mnemonic = myPresentation.getMnemonic() + displayedMnemonicIndex = myPresentation.getDisplayedMnemonicIndex() + updateIcon() } - private void init() { - boolean macSystemMenu = SystemInfo.isMacSystemMenu && isMainMenuPlace(); - - myStubItem = macSystemMenu ? null : new StubItem(); - addStubItem(); - setBorderPainted(false); - - MenuListenerImpl menuListener = new MenuListenerImpl(); - addMenuListener(menuListener); - getModel().addChangeListener(menuListener); - - updateFromPresentation(myMnemonicEnabled); - } - - public boolean isMainMenuPlace() { - return myPlace.equals(ActionPlaces.MAIN_MENU); - } - - public void updateFromPresentation(boolean enableMnemonics) { - myMnemonicEnabled = enableMnemonics; - setVisible(myPresentation.isVisible()); - setEnabled(myPresentation.isEnabled()); - - setText(myPresentation.getText(myMnemonicEnabled)); - setMnemonic(myPresentation.getMnemonic()); - setDisplayedMnemonicIndex(myPresentation.getDisplayedMnemonicIndex()); - updateIcon(); - } - - private void addStubItem() { + private fun addStubItem() { if (myStubItem != null) { - add(myStubItem); + add(myStubItem) } } - @Override - public void setDisplayedMnemonicIndex(int index) throws IllegalArgumentException { - super.setDisplayedMnemonicIndex(myMnemonicEnabled ? index : -1); + @Throws(IllegalArgumentException::class) + override fun setDisplayedMnemonicIndex(index: Int) { + super.setDisplayedMnemonicIndex(if (myMnemonicEnabled) index else -1) } - @Override - public void setMnemonic(int mnemonic) { - super.setMnemonic(myMnemonicEnabled ? mnemonic : 0); + override fun setMnemonic(mnemonic: Int) { + super.setMnemonic(if (myMnemonicEnabled) mnemonic else 0) } - private void updateIcon() { - UISettings settings = UISettings.getInstanceOrNull(); - Icon icon = myPresentation.getIcon(); - if (icon != null && settings != null && settings.getShowIconsInMenus()) { - if (SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU.equals(myPlace)) { + private fun updateIcon() { + val settings = instanceOrNull + var icon = myPresentation.icon + if (icon != null && settings != null && settings.showIconsInMenus) { + if (SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == myPlace) { // JDK can't paint correctly our HiDPI icons at the system menu bar - icon = IconUtilKt.getMenuBarIcon(icon, myUseDarkIcons); + icon = getMenuBarIcon(icon, myUseDarkIcons) } else if (shouldConvertIconToDarkVariant()) { - icon = IconLoader.getDarkIcon(icon, true); + icon = getDarkIcon(icon, true) } - if (isShowNoIcons()) { - setIcon(null); - setDisabledIcon(null); + if (isShowNoIcons) { + setIcon(null) + setDisabledIcon(null) } else { - setIcon(icon); - Icon presentationDisabledIcon = myPresentation.getDisabledIcon(); - setDisabledIcon(presentationDisabledIcon == null ? IconLoader.getDisabledIcon(icon) : presentationDisabledIcon); - if (myScreenMenuPeer != null) { - myScreenMenuPeer.setIcon(icon); - } + setIcon(icon) + val presentationDisabledIcon = myPresentation.disabledIcon + setDisabledIcon(presentationDisabledIcon ?: getDisabledIcon(icon)) + screenMenuPeer?.setIcon(icon) } } } - static boolean shouldConvertIconToDarkVariant() { - return JBColor.isBright() && ColorUtil.isDark(JBColor.namedColor("MenuItem.background", 0xffffff)); + override fun menuSelectionChanged(isIncluded: Boolean) { + super.menuSelectionChanged(isIncluded) + showDescriptionInStatusBar(isIncluded, this, myPresentation.description) } - static boolean isShowNoIcons() { - return SystemInfoRt.isMac && (Registry.get("ide.macos.main.menu.alignment.options").isOptionEnabled("No icons") || ExperimentalUI.isNewUI()); - } - - static boolean isShowNoIcons(AnAction action) { - if (action == null) { - return false; - } - if (action instanceof MainMenuPresentationAware && ((MainMenuPresentationAware)action).alwaysShowIconInMainMenu()) { - return false; - } - return isShowNoIcons(); - } - - static boolean isAligned() { - return SystemInfoRt.isMac && Registry.get("ide.macos.main.menu.alignment.options").isOptionEnabled("Aligned"); - } - - static boolean isAlignedInGroup() { - return SystemInfoRt.isMac && Registry.get("ide.macos.main.menu.alignment.options").isOptionEnabled("Aligned in group"); - } - - @Override - public void menuSelectionChanged(boolean isIncluded) { - super.menuSelectionChanged(isIncluded); - showDescriptionInStatusBar(isIncluded, this, myPresentation.getDescription()); - } - - public static void showDescriptionInStatusBar(boolean isIncluded, Component component, @NlsContexts.StatusBarText String description) { - IdeFrame frame = (IdeFrame)(component instanceof IdeFrame ? component : SwingUtilities.getAncestorOfClass(IdeFrame.class, component)); - StatusBar statusBar; - if (frame != null && (statusBar = frame.getStatusBar()) != null) { - statusBar.setInfo(isIncluded ? description : null); - } - } - - @Override - protected void processMouseEvent(MouseEvent e) { - boolean shouldCancelIgnoringOfNextSelectionRequest = false; - + override fun processMouseEvent(e: MouseEvent) { + var shouldCancelIgnoringOfNextSelectionRequest = false if (mySubElementSelector != null) { - switch (e.getID()) { - case MouseEvent.MOUSE_PRESSED -> { - mySubElementSelector.ignoreNextSelectionRequest(); - shouldCancelIgnoringOfNextSelectionRequest = true; + when (e.id) { + MouseEvent.MOUSE_PRESSED -> { + mySubElementSelector.ignoreNextSelectionRequest() + shouldCancelIgnoringOfNextSelectionRequest = true } - case MouseEvent.MOUSE_ENTERED -> mySubElementSelector.ignoreNextSelectionRequest(getDelay() * 2); + MouseEvent.MOUSE_ENTERED -> mySubElementSelector.ignoreNextSelectionRequest(delay * 2) } } - try { - super.processMouseEvent(e); + super.processMouseEvent(e) } finally { if (shouldCancelIgnoringOfNextSelectionRequest) { - mySubElementSelector.cancelIgnoringOfNextSelectionRequest(); + mySubElementSelector!!.cancelIgnoringOfNextSelectionRequest() } } } - private class MenuListenerImpl implements ChangeListener, MenuListener { - ScheduledFuture myDelayedClear; - boolean isSelected = false; - - @Override - public void stateChanged(ChangeEvent e) { + private inner class MenuListenerImpl : ChangeListener, MenuListener { + var myDelayedClear: ScheduledFuture<*>? = null + var isSelected: Boolean = false + override fun stateChanged(e: ChangeEvent) { // Re-implement javax.swing.JMenu.MenuChangeListener to avoid recursive event notifications // if 'menuSelected' fires unrelated 'stateChanged' event, without changing 'model.isSelected()' value. - ButtonModel model = (ButtonModel)e.getSource(); - boolean modelSelected = model.isSelected(); - + val model = e.source as ButtonModel + val modelSelected = model.isSelected if (modelSelected != isSelected) { - isSelected = modelSelected; - + isSelected = modelSelected if (modelSelected) { - menuSelected(); + menuSelected() } else { - menuDeselected(); + menuDeselected() } } } - @Override - public void menuCanceled(MenuEvent e) { - onMenuHidden(); + override fun menuCanceled(e: MenuEvent) { + onMenuHidden() } - @Override - public void menuDeselected(MenuEvent e) { + override fun menuDeselected(e: MenuEvent) { // Use ChangeListener instead to guard against recursive calls } - @Override - public void menuSelected(MenuEvent e) { + override fun menuSelected(e: MenuEvent) { // Use ChangeListener instead to guard against recursive calls } - private void menuDeselected() { + private fun menuDeselected() { if (myDisposable != null) { - Disposer.dispose(myDisposable); - myDisposable = null; + Disposer.dispose(myDisposable!!) + myDisposable = null } - onMenuHidden(); - - if (mySubElementSelector != null) mySubElementSelector.cancelNextSelection(); + onMenuHidden() + mySubElementSelector?.cancelNextSelection() } - private void onMenuHidden() { - Runnable clearSelf = () -> { - clearItems(); - addStubItem(); - }; - - if (SystemInfo.isMacSystemMenu && isMainMenuPlace()) { + private fun onMenuHidden() { + val clearSelf = Runnable { + clearItems() + addStubItem() + } + if (SystemInfo.isMacSystemMenu && isMainMenuPlace) { // Menu items may contain mnemonic, and they can affect key-event dispatching (when Alt pressed) // To avoid the influence of mnemonic it's necessary to clear items when a menu was hidden. // When a user selects item of a system menu (under macOS), AppKit generates such sequence: CloseParentMenu -> PerformItemAction // So we can destroy menu-item before item's action performed, and because of that action will not be executed. // Defer clearing to avoid this problem. - myDelayedClear = EdtScheduledExecutorService.getInstance().schedule(clearSelf, 1000, TimeUnit.MILLISECONDS); + myDelayedClear = EdtScheduledExecutorService.getInstance().schedule(clearSelf, 1000, TimeUnit.MILLISECONDS) } else { - clearSelf.run(); + clearSelf.run() } } - private void menuSelected() { - UsabilityHelper helper = new UsabilityHelper(ActionMenu.this); + private fun menuSelected() { + val helper = UsabilityHelper(this@ActionMenu) if (myDisposable == null) { - myDisposable = Disposer.newDisposable(); + myDisposable = Disposer.newDisposable() } - Disposer.register(myDisposable, helper); + Disposer.register(myDisposable!!, helper) if (myDelayedClear != null) { - myDelayedClear.cancel(false); - myDelayedClear = null; - clearItems(); + myDelayedClear!!.cancel(false) + myDelayedClear = null + clearItems() } - if (SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU.equals(myPlace)) { - fillMenu(); + if (SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == myPlace) { + fillMenu() } } } - @Override - public void setPopupMenuVisible(boolean b) { - if (b && !(SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU.equals(myPlace))) { - fillMenu(); - if (!isSelected()) { - return; + override fun setPopupMenuVisible(b: Boolean) { + if (b && !(SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == myPlace)) { + fillMenu() + if (!isSelected) { + return } } - - super.setPopupMenuVisible(b); - - if (b && (mySubElementSelector != null)) { - mySubElementSelector.selectSubElementIfNecessary(); + super.setPopupMenuVisible(b) + if (b && mySubElementSelector != null) { + mySubElementSelector.selectSubElementIfNecessary() } } - public void clearItems() { - if (SystemInfo.isMacSystemMenu && isMainMenuPlace()) { - for (Component menuComponent : getMenuComponents()) { - if (menuComponent instanceof ActionMenu) { - ((ActionMenu)menuComponent).clearItems(); + fun clearItems() { + if (SystemInfo.isMacSystemMenu && isMainMenuPlace) { + for (menuComponent in getMenuComponents()) { + if (menuComponent is ActionMenu) { + menuComponent.clearItems() } - else if (menuComponent instanceof ActionMenuItem) { + else if (menuComponent is ActionMenuItem) { // Looks like an old-fashioned ugly workaround // JDK 1.7 on Mac works wrong with such functional keys if (!SystemInfo.isMac) { - ((ActionMenuItem)menuComponent).setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F24, 0)); + menuComponent.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F24, 0)) } } } } - - removeAll(); - validate(); + removeAll() + validate() } - private @NotNull DataContext getDataContext() { - DataContext context; - - if (myContext != null) { - context = myContext; - } - else { - DataManager dataManager = DataManager.getInstance(); - @SuppressWarnings("deprecation") DataContext contextFromFocus = dataManager.getDataContext(); - context = contextFromFocus; - if (PlatformCoreDataKeys.CONTEXT_COMPONENT.getData(context) == null) { - IdeFrame frame = ComponentUtil.getParentOfType((Class)IdeFrame.class, (Component)this); - context = dataManager.getDataContext(IdeFocusManager.getGlobalInstance().getLastFocusedFor((Window)frame)); + private val dataContext: DataContext + private get() { + var context: DataContext + if (myContext != null) { + context = myContext } - context = Utils.wrapDataContext(context); - } - return context; - } - - public void fillMenu() { - DataContext context = getDataContext(); - boolean isDarkMenu = SystemInfo.isMacSystemMenu && NSDefaults.isDarkMenuBar(); - Utils.fillMenu(myGroup.getAction(), this, myMnemonicEnabled, myPresentationFactory, context, myPlace, true, isDarkMenu, - RelativePoint.getNorthEastOf(this), () -> !isSelected()); - } - - private static final class UsabilityHelper implements IdeEventQueue.EventDispatcher, AWTEventListener, Disposable { - private Component myComponent; - private Point myStartMousePoint; - private Point myUpperTargetPoint; - private Point myLowerTargetPoint; - private SingleAlarm myCallbackAlarm; - private MouseEvent myEventToRedispatch; - - private UsabilityHelper(Component component) { - myCallbackAlarm = new SingleAlarm(() -> { - Disposer.dispose(myCallbackAlarm); - myCallbackAlarm = null; - if (myEventToRedispatch != null) { - IdeEventQueue.getInstance().dispatchEvent(myEventToRedispatch); + else { + val dataManager = DataManager.getInstance() + @Suppress("deprecation") val contextFromFocus = dataManager.getDataContext() + context = contextFromFocus + if (PlatformCoreDataKeys.CONTEXT_COMPONENT.getData(context) == null) { + val frame = ComponentUtil.getParentOfType(IdeFrame::class.java as Class, this as Component) + context = dataManager.getDataContext(IdeFocusManager.getGlobalInstance().getLastFocusedFor(frame as Window?)) } - }, 50, this, Alarm.ThreadToUse.SWING_THREAD, ModalityState.any()); - myComponent = component; - PointerInfo info = MouseInfo.getPointerInfo(); - myStartMousePoint = info != null ? info.getLocation() : null; + context = Utils.wrapDataContext(context) + } + return context + } + + fun fillMenu() { + val context = dataContext + val isDarkMenu = SystemInfo.isMacSystemMenu && NSDefaults.isDarkMenuBar() + Utils.fillMenu(myGroup.getAction(), this, myMnemonicEnabled, myPresentationFactory, context, myPlace!!, true, isDarkMenu, + RelativePoint.getNorthEastOf(this)) { !isSelected } + } + + private class UsabilityHelper(component: Component) : IdeEventQueue.EventDispatcher, AWTEventListener, Disposable { + private var myComponent: Component? + private var myStartMousePoint: Point? + private var myUpperTargetPoint: Point? = null + private var myLowerTargetPoint: Point? = null + private var callbackAlarm: SingleAlarm? + private var myEventToRedispatch: MouseEvent? = null + + init { + callbackAlarm = SingleAlarm({ + //Disposer.dispose(callbackAlarm!!) + callbackAlarm = null + if (myEventToRedispatch != null) { + getInstance().dispatchEvent(myEventToRedispatch!!) + } + }, 50, this, Alarm.ThreadToUse.SWING_THREAD, ModalityState.any()) + myComponent = component + val info = MouseInfo.getPointerInfo() + myStartMousePoint = info?.location if (myStartMousePoint != null) { - Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.COMPONENT_EVENT_MASK); - IdeEventQueue.getInstance().addDispatcher(this, this); + Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.COMPONENT_EVENT_MASK) + getInstance().addDispatcher(this, this) } } - @Override - public void eventDispatched(AWTEvent event) { - if (event instanceof ComponentEvent componentEvent) { - Component component = componentEvent.getComponent(); - JPopupMenu popup = ComponentUtil.getParentOfType((Class)JPopupMenu.class, component); - if (popup != null && popup.getInvoker() == myComponent && popup.isShowing()) { - Rectangle bounds = popup.getBounds(); - if (bounds.isEmpty()) return; - bounds.setLocation(popup.getLocationOnScreen()); - if (myStartMousePoint.x < bounds.x) { - myUpperTargetPoint = new Point(bounds.x, bounds.y); - myLowerTargetPoint = new Point(bounds.x, bounds.y + bounds.height); + override fun eventDispatched(event: AWTEvent) { + if (event is ComponentEvent) { + val component: Component = event.component + val popup = ComponentUtil.getParentOfType(JPopupMenu::class.java as Class, component) + if (popup != null && popup.invoker === myComponent && popup.isShowing()) { + val bounds = popup.bounds + if (bounds.isEmpty) return + bounds.location = popup.locationOnScreen + if (myStartMousePoint!!.x < bounds.x) { + myUpperTargetPoint = Point(bounds.x, bounds.y) + myLowerTargetPoint = Point(bounds.x, bounds.y + bounds.height) } - if (myStartMousePoint.x > bounds.x + bounds.width) { - myUpperTargetPoint = new Point(bounds.x + bounds.width, bounds.y); - myLowerTargetPoint = new Point(bounds.x + bounds.width, bounds.y + bounds.height); + if (myStartMousePoint!!.x > bounds.x + bounds.width) { + myUpperTargetPoint = Point(bounds.x + bounds.width, bounds.y) + myLowerTargetPoint = Point(bounds.x + bounds.width, bounds.y + bounds.height) } } } } - @Override - public boolean dispatch(@NotNull AWTEvent e) { - if (e instanceof MouseEvent && myUpperTargetPoint != null && myLowerTargetPoint != null && myCallbackAlarm != null) { + override fun dispatch(e: AWTEvent): Boolean { + if (e is MouseEvent && myUpperTargetPoint != null && myLowerTargetPoint != null && callbackAlarm != null) { if (e.getID() == MouseEvent.MOUSE_PRESSED || e.getID() == MouseEvent.MOUSE_RELEASED || e.getID() == MouseEvent.MOUSE_CLICKED) { - return false; + return false } - Point point = ((MouseEvent)e).getLocationOnScreen(); - Rectangle bounds = myComponent.getBounds(); - bounds.setLocation(myComponent.getLocationOnScreen()); - boolean isMouseMovingTowardsSubmenu = bounds.contains(point) || new Polygon( - new int[]{myStartMousePoint.x, myUpperTargetPoint.x, myLowerTargetPoint.x}, - new int[]{myStartMousePoint.y, myUpperTargetPoint.y, myLowerTargetPoint.y}, - 3).contains(point); - - myEventToRedispatch = (MouseEvent)e; - + val point = e.locationOnScreen + val bounds = myComponent!!.bounds + bounds.location = myComponent!!.locationOnScreen + val isMouseMovingTowardsSubmenu = bounds.contains(point) || Polygon(intArrayOf( + myStartMousePoint!!.x, myUpperTargetPoint!!.x, myLowerTargetPoint!!.x), intArrayOf(myStartMousePoint!!.y, myUpperTargetPoint!!.y, + myLowerTargetPoint!!.y), + 3).contains(point) + myEventToRedispatch = e if (!isMouseMovingTowardsSubmenu) { - myCallbackAlarm.request(); + callbackAlarm!!.request() } else { - myCallbackAlarm.cancel(); + callbackAlarm!!.cancel() } - return true; + return true } - return false; + return false } - @Override - public void dispose() { - myComponent = null; - myEventToRedispatch = null; - myStartMousePoint = myUpperTargetPoint = myLowerTargetPoint = null; - Toolkit.getDefaultToolkit().removeAWTEventListener(this); + override fun dispose() { + myComponent = null + myEventToRedispatch = null + myLowerTargetPoint = null + myUpperTargetPoint = myLowerTargetPoint + myStartMousePoint = myUpperTargetPoint + Toolkit.getDefaultToolkit().removeAWTEventListener(this) } } - private static final class SubElementSelector { - static final boolean isForceDisabled = - SystemInfo.isMacSystemMenu || - !Registry.is("ide.popup.menu.navigation.keyboard.selectFirstEnabledSubItem", false); - - - SubElementSelector(@NotNull ActionMenu owner) { - if (isForceDisabled) { - throw new IllegalStateException("Attempt to create an instance of ActionMenu.SubElementSelector class when it is force disabled"); - } - - myOwner = owner; - myShouldIgnoreNextSelectionRequest = false; - myShouldIgnoreNextSelectionRequestSinceTimestamp = -1; - myShouldIgnoreNextSelectionRequestTimeoutMs = -1; - myCurrentRequestId = -1; - } - + private class SubElementSelector(owner: ActionMenu) { @RequiresEdt - void ignoreNextSelectionRequest(int timeoutMs) { - myShouldIgnoreNextSelectionRequest = true; - myShouldIgnoreNextSelectionRequestTimeoutMs = timeoutMs; - if (timeoutMs >= 0) { - myShouldIgnoreNextSelectionRequestSinceTimestamp = System.currentTimeMillis(); + fun ignoreNextSelectionRequest(timeoutMs: Int) { + myShouldIgnoreNextSelectionRequest = true + myShouldIgnoreNextSelectionRequestTimeoutMs = timeoutMs + myShouldIgnoreNextSelectionRequestSinceTimestamp = if (timeoutMs >= 0) { + System.currentTimeMillis() } else { - myShouldIgnoreNextSelectionRequestSinceTimestamp = -1; + -1 } } @RequiresEdt - void ignoreNextSelectionRequest() { - ignoreNextSelectionRequest(-1); + fun ignoreNextSelectionRequest() { + ignoreNextSelectionRequest(-1) } @RequiresEdt - void cancelIgnoringOfNextSelectionRequest() { - myShouldIgnoreNextSelectionRequest = false; - myShouldIgnoreNextSelectionRequestSinceTimestamp = -1; - myShouldIgnoreNextSelectionRequestTimeoutMs = -1; + fun cancelIgnoringOfNextSelectionRequest() { + myShouldIgnoreNextSelectionRequest = false + myShouldIgnoreNextSelectionRequestSinceTimestamp = -1 + myShouldIgnoreNextSelectionRequestTimeoutMs = -1 } @RequiresEdt - void selectSubElementIfNecessary() { - final boolean shouldIgnoreThisSelectionRequest; - if (myShouldIgnoreNextSelectionRequest) { + fun selectSubElementIfNecessary() { + val shouldIgnoreThisSelectionRequest: Boolean + shouldIgnoreThisSelectionRequest = if (myShouldIgnoreNextSelectionRequest) { if (myShouldIgnoreNextSelectionRequestTimeoutMs >= 0) { - shouldIgnoreThisSelectionRequest = - ( (System.currentTimeMillis() - myShouldIgnoreNextSelectionRequestSinceTimestamp) <= myShouldIgnoreNextSelectionRequestTimeoutMs ); + System.currentTimeMillis() - myShouldIgnoreNextSelectionRequestSinceTimestamp <= myShouldIgnoreNextSelectionRequestTimeoutMs } else { - shouldIgnoreThisSelectionRequest = true; + true } } else { - shouldIgnoreThisSelectionRequest = false; + false } - - cancelIgnoringOfNextSelectionRequest(); - + cancelIgnoringOfNextSelectionRequest() if (shouldIgnoreThisSelectionRequest) { - return; + return } - - final int thisRequestId = ++myCurrentRequestId; - SwingUtilities.invokeLater(() -> selectFirstEnabledElement(thisRequestId)); + val thisRequestId = ++myCurrentRequestId + SwingUtilities.invokeLater { selectFirstEnabledElement(thisRequestId) } } @RequiresEdt - void cancelNextSelection() { - ++myCurrentRequestId; + fun cancelNextSelection() { + ++myCurrentRequestId } + private val myOwner: ActionMenu + private var myShouldIgnoreNextSelectionRequest: Boolean + private var myShouldIgnoreNextSelectionRequestSinceTimestamp: Long + private var myShouldIgnoreNextSelectionRequestTimeoutMs: Int + private var myCurrentRequestId: Int - private final @NotNull ActionMenu myOwner; - private boolean myShouldIgnoreNextSelectionRequest; - private long myShouldIgnoreNextSelectionRequestSinceTimestamp; - private int myShouldIgnoreNextSelectionRequestTimeoutMs; - private int myCurrentRequestId; - + init { + if (isForceDisabled) { + throw IllegalStateException("Attempt to create an instance of ActionMenu.SubElementSelector class when it is force disabled") + } + myOwner = owner + myShouldIgnoreNextSelectionRequest = false + myShouldIgnoreNextSelectionRequestSinceTimestamp = -1 + myShouldIgnoreNextSelectionRequestTimeoutMs = -1 + myCurrentRequestId = -1 + } @RequiresEdt - private void selectFirstEnabledElement(final int requestId) { + private fun selectFirstEnabledElement(requestId: Int) { if (requestId != myCurrentRequestId) { // the request was cancelled or a newer request was created - return; + return } - - if (!myOwner.isSelected()) { - return; + if (!myOwner.isSelected) { + return } - - final var menuSelectionManager = MenuSelectionManager.defaultManager(); - - final var currentSelectedPath = menuSelectionManager.getSelectedPath(); - if (currentSelectedPath.length < 2) { - return; + val menuSelectionManager = MenuSelectionManager.defaultManager() + val currentSelectedPath = menuSelectionManager.getSelectedPath() + if (currentSelectedPath.size < 2) { + return } - - final var lastElementInCurrentPath = currentSelectedPath[currentSelectedPath.length - 1]; - - final MenuElement[] newSelectionPath; - if (lastElementInCurrentPath == myOwner.myStubItem) { - newSelectionPath = currentSelectedPath.clone(); + val lastElementInCurrentPath = currentSelectedPath[currentSelectedPath.size - 1] + val newSelectionPath: Array + newSelectionPath = if (lastElementInCurrentPath === myOwner.myStubItem) { + currentSelectedPath.clone() } - else if (lastElementInCurrentPath == myOwner.getPopupMenu()) { - newSelectionPath = Arrays.copyOf(currentSelectedPath, currentSelectedPath.length + 1); + else if (lastElementInCurrentPath === myOwner.getPopupMenu()) { + currentSelectedPath.copyOf(currentSelectedPath.size + 1) } - else if ( (currentSelectedPath[currentSelectedPath.length - 2] == myOwner.getPopupMenu()) && - !ArrayUtil.contains(lastElementInCurrentPath.getComponent(), myOwner.getMenuComponents()) ) { - newSelectionPath = currentSelectedPath.clone(); + else if (currentSelectedPath[currentSelectedPath.size - 2] === myOwner.getPopupMenu() && + !ArrayUtil.contains(lastElementInCurrentPath!!.component, *myOwner.getMenuComponents())) { + currentSelectedPath.clone() } else { - return; + return } - - final var menuComponents = myOwner.getMenuComponents(); - for (final var component : menuComponents) { - if ((component != myOwner.myStubItem) && component.isEnabled() && (component instanceof JMenuItem)) { - newSelectionPath[newSelectionPath.length - 1] = (MenuElement)component; - menuSelectionManager.setSelectedPath(newSelectionPath); - - return; + val menuComponents = myOwner.getMenuComponents() + for (component in menuComponents) { + if (component !== myOwner.myStubItem && component.isEnabled && component is JMenuItem) { + newSelectionPath[newSelectionPath.size - 1] = component as MenuElement + menuSelectionManager.setSelectedPath(newSelectionPath) + return } } } + + companion object { + val isForceDisabled: Boolean = SystemInfo.isMacSystemMenu || + !Registry.`is`("ide.popup.menu.navigation.keyboard.selectFirstEnabledSubItem", false) + } } } \ No newline at end of file From 4198e4adf51ff982a18771282ed0cfc30fe6816d Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 17:22:30 +0200 Subject: [PATCH 123/226] move com.intellij.ide.menu GitOrigin-RevId: b88f5384f2aa4ae0bd55fee4961b1df830063104 --- .../menu}/FloatingMenuBarFlavor.kt | 4 +- .../wm/impl => ide/menu}/IdeMenuBarHelper.kt | 194 ++----- .../ide/menu/JMenuBasedIdeMenuBarHelper.kt | 66 +++ .../wm/impl => ide/menu}/MacMenuBar.kt | 4 +- .../ide/menu/PeerBasedIdeMenuBarHelper.kt | 44 ++ .../actionSystem/impl/ActionManagerImpl.kt | 2 +- .../openapi/actionSystem/impl/ActionMenu.kt | 478 +++++++++--------- .../openapi/wm/impl/IdeFrameDecorator.java | 9 +- .../intellij/openapi/wm/impl/IdeMenuBar.kt | 1 + .../intellij/openapi/wm/impl/IdeRootPane.kt | 2 + 10 files changed, 412 insertions(+), 392 deletions(-) rename platform/platform-impl/src/com/intellij/{openapi/wm/impl => ide/menu}/FloatingMenuBarFlavor.kt (98%) rename platform/platform-impl/src/com/intellij/{openapi/wm/impl => ide/menu}/IdeMenuBarHelper.kt (51%) create mode 100644 platform/platform-impl/src/com/intellij/ide/menu/JMenuBasedIdeMenuBarHelper.kt rename platform/platform-impl/src/com/intellij/{openapi/wm/impl => ide/menu}/MacMenuBar.kt (91%) create mode 100644 platform/platform-impl/src/com/intellij/ide/menu/PeerBasedIdeMenuBarHelper.kt diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingMenuBarFlavor.kt b/platform/platform-impl/src/com/intellij/ide/menu/FloatingMenuBarFlavor.kt similarity index 98% rename from platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingMenuBarFlavor.kt rename to platform/platform-impl/src/com/intellij/ide/menu/FloatingMenuBarFlavor.kt index 72e4efff6fef..5da18d6f5df1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingMenuBarFlavor.kt +++ b/platform/platform-impl/src/com/intellij/ide/menu/FloatingMenuBarFlavor.kt @@ -1,7 +1,9 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.openapi.wm.impl +package com.intellij.ide.menu import com.intellij.ide.IdeEventQueue +import com.intellij.openapi.wm.impl.* +import com.intellij.openapi.wm.impl.IdeMenuBarState import com.intellij.openapi.wm.impl.status.ClockPanel import com.intellij.ui.ColorUtil import com.intellij.util.ui.Animator diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBarHelper.kt b/platform/platform-impl/src/com/intellij/ide/menu/IdeMenuBarHelper.kt similarity index 51% rename from platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBarHelper.kt rename to platform/platform-impl/src/com/intellij/ide/menu/IdeMenuBarHelper.kt index 02cb229e840c..83a7633445cb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBarHelper.kt +++ b/platform/platform-impl/src/com/intellij/ide/menu/IdeMenuBarHelper.kt @@ -1,7 +1,7 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. @file:OptIn(FlowPreview::class) -package com.intellij.openapi.wm.impl +package com.intellij.ide.menu import com.intellij.diagnostic.StartUpMeasurer import com.intellij.diagnostic.rootTask @@ -13,25 +13,32 @@ import com.intellij.ide.ui.customization.CustomActionsSchema import com.intellij.openapi.actionSystem.* import com.intellij.openapi.actionSystem.ex.ActionManagerEx import com.intellij.openapi.actionSystem.ex.ActionUtil -import com.intellij.openapi.actionSystem.impl.* +import com.intellij.openapi.actionSystem.impl.ActionMenu +import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory +import com.intellij.openapi.actionSystem.impl.PresentationFactory +import com.intellij.openapi.actionSystem.impl.Utils import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.EDT import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.asContextElement import com.intellij.openapi.components.serviceAsync +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.wm.WindowManager -import com.intellij.ui.mac.screenmenu.MenuBar +import com.intellij.openapi.wm.impl.IdeFrameDecorator +import com.intellij.openapi.wm.impl.IdeMenuBarState +import com.intellij.openapi.wm.impl.IdeRootPane import kotlinx.coroutines.* import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.debounce +import org.jetbrains.concurrency.await import java.awt.Component import java.awt.Dialog import java.awt.Dimension import java.awt.KeyboardFocusManager import javax.swing.JComponent import javax.swing.JFrame -import javax.swing.MenuSelectionManager import kotlin.coroutines.EmptyCoroutineContext import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -69,7 +76,7 @@ internal sealed class IdeMenuBarHelper(@JvmField val flavor: IdeMenuFlavor, @JvmField protected val presentationFactory: PresentationFactory = MenuItemPresentationFactory() - private val updateRequests = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) + private val updateRequests = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) interface MenuBarImpl { val frame: JFrame @@ -110,7 +117,8 @@ internal sealed class IdeMenuBarHelper(@JvmField val flavor: IdeMenuFlavor, } updateRequests - .debounce(50.milliseconds) + // as ActionManagerImpl TIMER_DELAY + .debounce(500.milliseconds) .collect { forceRebuild -> presentationFactory.reset() updateMenuActions(mainActionGroup = menuBar.getMainMenuActionGroup(), forceRebuild = forceRebuild, isFirstUpdate = false) @@ -120,16 +128,6 @@ internal sealed class IdeMenuBarHelper(@JvmField val flavor: IdeMenuFlavor, private suspend fun updateOnTimer() { withContext(Dispatchers.EDT) { - if (!menuBar.frame.isShowing || !menuBar.frame.isActive) { - return@withContext - } - - // do not update when a popup menu is shown - // (if a popup menu contains action which is also in the menu bar, it should not be enabled/disabled) - if (isUpdateForbidden()) { - return@withContext - } - // don't update the toolbar if there is currently active modal dialog val window = KeyboardFocusManager.getCurrentKeyboardFocusManager().focusedWindow if (window !is Dialog || !window.isModal) { @@ -165,105 +163,48 @@ internal sealed class IdeMenuBarHelper(@JvmField val flavor: IdeMenuFlavor, } } -internal open class JMenuBasedIdeMenuBarHelper(flavor: IdeMenuFlavor, menuBar: MenuBarImpl) : IdeMenuBarHelper(flavor, menuBar) { - override fun isUpdateForbidden() = MenuSelectionManager.defaultManager().selectedPath.isNotEmpty() - - override suspend fun postInitActions(actions: List) { - withContext(Dispatchers.EDT) { - for (action in actions) { - PopupMenuPreloader.install(menuBar.component, ActionPlaces.MAIN_MENU, null) { action } - } - } - } - - override suspend fun updateMenuActions(mainActionGroup: ActionGroup?, forceRebuild: Boolean, isFirstUpdate: Boolean): List { - val menuBarComponent = menuBar.component - val newVisibleActions = mainActionGroup?.let { - expandMainActionGroup(mainActionGroup = it, - menuBar = menuBarComponent, - frame = menuBar.frame, - presentationFactory = presentationFactory, - isFirstUpdate = isFirstUpdate) - } ?: emptyList() - - if (!forceRebuild && newVisibleActions == visibleActions && !presentationFactory.isNeedRebuild) { - val enableMnemonics = !UISettings.getInstance().disableMnemonics - withContext(Dispatchers.EDT) { - for (child in menuBarComponent.components) { - if (child is ActionMenu) { - child.updateFromPresentation(enableMnemonics) - } - } - } - return newVisibleActions - } - - // should rebuild UI - val changeBarVisibility = newVisibleActions.isEmpty() || visibleActions.isEmpty() - withContext(Dispatchers.EDT) { - visibleActions = newVisibleActions - menuBarComponent.removeAll() - createActionMenuList(newVisibleActions) { - menuBarComponent.add(it) - } - presentationFactory.resetNeedRebuild() - flavor.updateAppMenu() - menuBar.updateGlobalMenuRoots() - menuBarComponent.validate() - if (changeBarVisibility) { - menuBarComponent.invalidate() - menuBar.frame.validate() - } - } - return newVisibleActions - } -} - -internal open class PeerBasedIdeMenuBarHelper(private val screenMenuPeer: MenuBar, - flavor: IdeMenuFlavor, - menuBar: MenuBarImpl) : IdeMenuBarHelper(flavor, menuBar) { - override fun isUpdateForbidden() = screenMenuPeer.isAnyChildOpened - - override suspend fun updateMenuActions(mainActionGroup: ActionGroup?, forceRebuild: Boolean, isFirstUpdate: Boolean): List { - val newVisibleActions = mainActionGroup?.let { - expandMainActionGroup(mainActionGroup = it, - menuBar = menuBar.component, - frame = menuBar.frame, - presentationFactory = presentationFactory, - isFirstUpdate = isFirstUpdate) - } ?: emptyList() - - if (!forceRebuild && newVisibleActions == visibleActions && !presentationFactory.isNeedRebuild) { - return newVisibleActions - } - - withContext(Dispatchers.EDT) { - visibleActions = newVisibleActions - screenMenuPeer.beginFill() - try { - createActionMenuList(newVisibleActions) { - screenMenuPeer.add(it.screenMenuPeer) - } - } - finally { - screenMenuPeer.endFill() - presentationFactory.resetNeedRebuild() - } - flavor.updateAppMenu() - } - return newVisibleActions - } -} - @Suppress("unused") private val firstUpdateFastTrackUpdateTimeout = 30.seconds.inWholeMilliseconds +private val useAsyncExpand = System.getProperty("idea.app.menu.async.expand", "false").toBoolean() -private suspend fun expandMainActionGroup(mainActionGroup: ActionGroup, - menuBar: Component, - frame: JFrame, - presentationFactory: PresentationFactory, - @Suppress("UNUSED_PARAMETER") isFirstUpdate: Boolean): List { +internal suspend fun expandMainActionGroup(mainActionGroup: ActionGroup, + menuBar: Component, + frame: JFrame, + presentationFactory: PresentationFactory, + isFirstUpdate: Boolean): List { val actionManager = serviceAsync() + if (!useAsyncExpand) { + return syncExpandMainActionGroup(mainActionGroup, actionManager, frame, menuBar, presentationFactory) + } + + try { + return withContext(CoroutineName("expandMainActionGroup") + Dispatchers.EDT) { + val targetComponent = WindowManager.getInstance().getFocusedComponent(frame) ?: menuBar + val dataContext = Utils.wrapToAsyncDataContext(DataManager.getInstance().getDataContext(targetComponent)) + val fastTrackTimeout = if (isFirstUpdate) firstUpdateFastTrackUpdateTimeout else Utils.getFastTrackTimeout() + Utils.expandActionGroupAsync(/* group = */ mainActionGroup, + /* presentationFactory = */ presentationFactory, + /* context = */ dataContext, + /* place = */ ActionPlaces.MAIN_MENU, + /* isToolbarAction = */ false, + /* fastTrackTimeout = */ fastTrackTimeout) + }.await().filterIsInstance() + } + catch (e: ProcessCanceledException) { + if (isFirstUpdate) { + logger().warn("Cannot expand action group", e) + } + + // don't repeat - will do on next timer event + return emptyList() + } +} + +private suspend fun syncExpandMainActionGroup(mainActionGroup: ActionGroup, + actionManager: ActionManager, + frame: JFrame, + menuBar: Component, + presentationFactory: PresentationFactory): List { return subtask("expandMainActionGroup", Dispatchers.EDT) { val children = mainActionGroup.getChildren(null, actionManager) if (children.isEmpty()) { @@ -287,37 +228,6 @@ private suspend fun expandMainActionGroup(mainActionGroup: ActionGroup, } list } - - // don't repeat for JetBrains Client - deadlock possible - //repeat(if (PlatformUtils.isJetBrainsClient()) 1 else 3) { - // presentationFactory.resetNeedRebuild() - // try { - // return withContext(CoroutineName("expandMainActionGroup") + Dispatchers.EDT) { - // val targetComponent = WindowManager.getInstance().getFocusedComponent(frame) ?: menuBar - // val dataContext = Utils.wrapToAsyncDataContext(DataManager.getInstance().getDataContext(targetComponent)) - // // disable fast track for JetBrains Client - deadlock otherwise - // val fastTrackTimeout = when { - // // disable fast track for JetBrains Client - deadlock otherwise - // PlatformUtils.isJetBrainsClient() -> -1 - // isFirstUpdate -> firstUpdateFastTrackUpdateTimeout - // else -> Utils.getFastTrackTimeout() - // } - // Utils.expandActionGroupAsync(/* group = */ mainActionGroup, - // /* presentationFactory = */ presentationFactory, - // /* context = */ dataContext, - // /* place = */ ActionPlaces.MAIN_MENU, - // /* isToolbarAction = */ false, - // /* fastTrackTimeout = */ fastTrackTimeout) - // }.await().filterIsInstance() - // } - // catch (e: ProcessCanceledException) { - // if (isFirstUpdate) { - // logger().warn("Cannot expand action group", e) - // return emptyList() - // } - // } - //} - //return emptyList() } internal suspend fun getMainMenuActionGroup(frame: JFrame): ActionGroup? { diff --git a/platform/platform-impl/src/com/intellij/ide/menu/JMenuBasedIdeMenuBarHelper.kt b/platform/platform-impl/src/com/intellij/ide/menu/JMenuBasedIdeMenuBarHelper.kt new file mode 100644 index 000000000000..9483874ef8bc --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/menu/JMenuBasedIdeMenuBarHelper.kt @@ -0,0 +1,66 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.ide.menu + +import com.intellij.ide.ui.UISettings +import com.intellij.openapi.actionSystem.ActionGroup +import com.intellij.openapi.actionSystem.ActionPlaces +import com.intellij.openapi.actionSystem.impl.ActionMenu +import com.intellij.openapi.actionSystem.impl.PopupMenuPreloader +import com.intellij.openapi.application.EDT +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.swing.MenuSelectionManager + +internal open class JMenuBasedIdeMenuBarHelper(flavor: IdeMenuFlavor, menuBar: MenuBarImpl) : IdeMenuBarHelper(flavor, menuBar) { + override fun isUpdateForbidden() = MenuSelectionManager.defaultManager().selectedPath.isNotEmpty() + + override suspend fun postInitActions(actions: List) { + withContext(Dispatchers.EDT) { + for (action in actions) { + PopupMenuPreloader.install(menuBar.component, ActionPlaces.MAIN_MENU, null) { action } + } + } + } + + override suspend fun updateMenuActions(mainActionGroup: ActionGroup?, forceRebuild: Boolean, isFirstUpdate: Boolean): List { + val menuBarComponent = menuBar.component + val newVisibleActions = mainActionGroup?.let { + expandMainActionGroup(mainActionGroup = it, + menuBar = menuBarComponent, + frame = menuBar.frame, + presentationFactory = presentationFactory, + isFirstUpdate = isFirstUpdate) + } ?: emptyList() + + if (!forceRebuild && newVisibleActions == visibleActions && !presentationFactory.isNeedRebuild) { + val enableMnemonics = !UISettings.getInstance().disableMnemonics + withContext(Dispatchers.EDT) { + for (child in menuBarComponent.components) { + if (child is ActionMenu) { + child.updateFromPresentation(enableMnemonics) + } + } + } + return newVisibleActions + } + + // should rebuild UI + val changeBarVisibility = newVisibleActions.isEmpty() || visibleActions.isEmpty() + withContext(Dispatchers.EDT) { + visibleActions = newVisibleActions + menuBarComponent.removeAll() + createActionMenuList(newVisibleActions) { + menuBarComponent.add(it) + } + presentationFactory.resetNeedRebuild() + flavor.updateAppMenu() + menuBar.updateGlobalMenuRoots() + menuBarComponent.validate() + if (changeBarVisibility) { + menuBarComponent.invalidate() + menuBar.frame.validate() + } + } + return newVisibleActions + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/MacMenuBar.kt b/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt similarity index 91% rename from platform/platform-impl/src/com/intellij/openapi/wm/impl/MacMenuBar.kt rename to platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt index b3b522b95197..d2571c95cd38 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/MacMenuBar.kt +++ b/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt @@ -1,7 +1,9 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.openapi.wm.impl +package com.intellij.ide.menu import com.intellij.diagnostic.runActivity +import com.intellij.openapi.wm.impl.createScreeMenuPeer +import com.intellij.openapi.wm.impl.doUpdateAppMenu import com.intellij.ui.mac.foundation.NSDefaults import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.job diff --git a/platform/platform-impl/src/com/intellij/ide/menu/PeerBasedIdeMenuBarHelper.kt b/platform/platform-impl/src/com/intellij/ide/menu/PeerBasedIdeMenuBarHelper.kt new file mode 100644 index 000000000000..2382f56a7167 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/menu/PeerBasedIdeMenuBarHelper.kt @@ -0,0 +1,44 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.ide.menu + +import com.intellij.openapi.actionSystem.ActionGroup +import com.intellij.openapi.application.EDT +import com.intellij.ui.mac.screenmenu.MenuBar +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +internal open class PeerBasedIdeMenuBarHelper(private val screenMenuPeer: MenuBar, + flavor: IdeMenuFlavor, + menuBar: MenuBarImpl) : IdeMenuBarHelper(flavor, menuBar) { + override fun isUpdateForbidden() = screenMenuPeer.isAnyChildOpened + + override suspend fun updateMenuActions(mainActionGroup: ActionGroup?, forceRebuild: Boolean, isFirstUpdate: Boolean): List { + val newVisibleActions = mainActionGroup?.let { + expandMainActionGroup(mainActionGroup = it, + menuBar = menuBar.component, + frame = menuBar.frame, + presentationFactory = presentationFactory, + isFirstUpdate = isFirstUpdate) + } ?: emptyList() + + if (!forceRebuild && newVisibleActions == visibleActions && !presentationFactory.isNeedRebuild) { + return newVisibleActions + } + + withContext(Dispatchers.EDT) { + visibleActions = newVisibleActions + screenMenuPeer.beginFill() + try { + createActionMenuList(newVisibleActions) { + screenMenuPeer.add(it.screenMenuPeer) + } + } + finally { + screenMenuPeer.endFill() + presentationFactory.resetNeedRebuild() + } + flavor.updateAppMenu() + } + return newVisibleActions + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.kt index 0048c4719907..1b48ded4dd49 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.kt @@ -1334,7 +1334,7 @@ open class ActionManagerImpl protected constructor(private val coroutineScope: C } } - private val _timerEvents = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_LATEST) + private val _timerEvents = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_LATEST) @Internal @Experimental diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt index 40ca9f11ee10..d4543c0caa14 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.kt @@ -4,13 +4,12 @@ package com.intellij.openapi.actionSystem.impl import com.intellij.ide.DataManager import com.intellij.ide.IdeEventQueue import com.intellij.ide.IdeEventQueue.Companion.getInstance -import com.intellij.ide.ui.UISettings.Companion.instanceOrNull +import com.intellij.ide.ui.UISettings import com.intellij.internal.inspector.UiInspectorContextProvider import com.intellij.internal.inspector.UiInspectorUtil import com.intellij.openapi.Disposable import com.intellij.openapi.actionSystem.* import com.intellij.openapi.actionSystem.ex.MainMenuPresentationAware -import com.intellij.openapi.actionSystem.impl.actionholder.ActionRef import com.intellij.openapi.actionSystem.impl.actionholder.createActionRef import com.intellij.openapi.application.ModalityState import com.intellij.openapi.ui.JBPopupMenu @@ -20,7 +19,6 @@ import com.intellij.openapi.util.IconLoader.getDisabledIcon import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.wm.IdeFocusManager import com.intellij.openapi.wm.IdeFrame -import com.intellij.openapi.wm.StatusBar import com.intellij.ui.ColorUtil import com.intellij.ui.ComponentUtil import com.intellij.ui.ExperimentalUI @@ -32,7 +30,10 @@ import com.intellij.ui.mac.foundation.NSDefaults import com.intellij.ui.mac.screenmenu.Menu import com.intellij.ui.plaf.beg.BegMenuItemUI import com.intellij.ui.plaf.beg.IdeaMenuUI -import com.intellij.util.* +import com.intellij.util.Alarm +import com.intellij.util.FontUtil +import com.intellij.util.ReflectionUtil +import com.intellij.util.SingleAlarm import com.intellij.util.concurrency.EdtScheduledExecutorService import com.intellij.util.concurrency.annotations.RequiresEdt import java.awt.* @@ -48,66 +49,55 @@ import javax.swing.event.ChangeListener import javax.swing.event.MenuEvent import javax.swing.event.MenuListener -class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, - place: String, +class ActionMenu @JvmOverloads constructor(private val context: DataContext?, + private val place: String, group: ActionGroup, - presentationFactory: PresentationFactory, - enableMnemonics: Boolean, - useDarkIcons: Boolean, - headerMenuItem: Boolean = false) : JBMenu() { - private val myPlace: String? - private val myGroup: ActionRef - private val myPresentationFactory: PresentationFactory - private val myPresentation: Presentation - private var myMnemonicEnabled: Boolean - private var myStubItem: StubItem? = null // A PATCH!!! Do not remove this code, otherwise you will lose all keyboard navigation in JMenuBar. - private val myUseDarkIcons: Boolean - private var myDisposable: Disposable? = null + private val presentationFactory: PresentationFactory, + private var isMnemonicEnabled: Boolean, + private val useDarkIcons: Boolean, + val isHeaderMenuItem: Boolean = false) : JBMenu() { + private val group = createActionRef(group) + private val presentation = presentationFactory.getPresentation(group) + // A PATCH!!! Do not remove this code, otherwise you will lose all keyboard navigation in JMenuBar. + private var stubItem: StubItem? = null + private var disposable: Disposable? = null var screenMenuPeer: Menu? = null - private val mySubElementSelector: SubElementSelector? - val isHeaderMenuItem: Boolean + private val subElementSelector = if (SubElementSelector.isForceDisabled) null else SubElementSelector(this) val anAction: AnAction - get() = myGroup.getAction() - - override fun removeNotify() { - super.removeNotify() - if (myDisposable != null) { - Disposer.dispose(myDisposable!!) - myDisposable = null - } - } + get() = group.getAction() private var specialMenu: JPopupMenu? = null + override fun removeNotify() { + super.removeNotify() + if (disposable != null) { + Disposer.dispose(disposable!!) + disposable = null + } + } + init { - myPlace = place - myGroup = createActionRef(group) - myPresentationFactory = presentationFactory - myPresentation = myPresentationFactory.getPresentation(group) - myMnemonicEnabled = enableMnemonics - myUseDarkIcons = useDarkIcons - isHeaderMenuItem = headerMenuItem - mySubElementSelector = if (SubElementSelector.isForceDisabled) null else SubElementSelector(this) - if (Menu.isJbScreenMenuEnabled() && ActionPlaces.MAIN_MENU == myPlace) { - val screenMenuPeer = Menu(myPresentation.getText(enableMnemonics)) + if (Menu.isJbScreenMenuEnabled() && ActionPlaces.MAIN_MENU == place) { + val screenMenuPeer = Menu(presentation.getText(isMnemonicEnabled)) this.screenMenuPeer = screenMenuPeer screenMenuPeer.setOnOpen(Runnable { // NOTE: setSelected(true) calls fillMenu internally setSelected(true) }, this) screenMenuPeer.setOnClose(Runnable { setSelected(false) }, this) - screenMenuPeer.listenPresentationChanges(myPresentation) + screenMenuPeer.listenPresentationChanges(presentation) } else { screenMenuPeer = null updateUI() } + init() + if (screenMenuPeer == null) { // also triggering initialization of private field "popupMenu" from JMenu with our own JBPopupMenu - BegMenuItemUI.registerMultiChoiceSupport(getPopupMenu()) { popupMenu: JPopupMenu? -> - Utils.updateMenuItems( - popupMenu!!, dataContext, myPlace, myPresentationFactory) + BegMenuItemUI.registerMultiChoiceSupport(getPopupMenu()) { popupMenu -> + Utils.updateMenuItems(popupMenu, getDataContext(), this.place, this.presentationFactory) } } } @@ -117,12 +107,9 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, * By default, a "performable" non-empty popup action group menu item still shows a submenu. * Use this key to disable the submenu and avoid children expansion on update as follows: * - * * `presentation.putClientProperty(ActionMenu.SUPPRESS_SUBMENU, true)`. * - * * Both ordinary and template presentations are supported. - * * @see Presentation.setPerformGroup */ @JvmField @@ -136,18 +123,17 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, @JvmStatic val isShowNoIcons: Boolean get() { - return SystemInfoRt.isMac && (Registry.get("ide.macos.main.menu.alignment.options").isOptionEnabled("No icons") || ExperimentalUI.isNewUI()) + return SystemInfoRt.isMac && (ExperimentalUI.isNewUI() || + Registry.get("ide.macos.main.menu.alignment.options").isOptionEnabled("No icons")) } @JvmStatic fun isShowNoIcons(action: AnAction?): Boolean { - if (action == null) { - return false + return when { + action == null -> false + action is MainMenuPresentationAware && (action as MainMenuPresentationAware).alwaysShowIconInMainMenu() -> false + else -> isShowNoIcons } - return if (action is MainMenuPresentationAware && (action as MainMenuPresentationAware).alwaysShowIconInMainMenu()) { - false - } - else isShowNoIcons } @JvmStatic @@ -160,10 +146,7 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, @JvmStatic fun showDescriptionInStatusBar(isIncluded: Boolean, component: Component?, description: @NlsContexts.StatusBarText String?) { val frame = (if (component is IdeFrame) component else SwingUtilities.getAncestorOfClass(IdeFrame::class.java, component)) as? IdeFrame - var statusBar: StatusBar? = null - if (frame != null && frame.getStatusBar().also { statusBar = it!! } != null) { - statusBar!!.setInfo(if (isIncluded) description else null) - } + frame?.getStatusBar()?.setInfo(if (isIncluded) description else null) } } @@ -176,7 +159,7 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, popupListener = createWinListener(specialMenu) ReflectionUtil.setField(JMenu::class.java, this, JPopupMenu::class.java, "popupMenu", specialMenu) UiInspectorUtil.registerProvider(specialMenu, UiInspectorContextProvider { - UiInspectorUtil.collectActionGroupInfo("Menu", myGroup.getAction(), myPlace) + UiInspectorUtil.collectActionGroupInfo("Menu", group.getAction(), place) }) } return super.getPopupMenu() @@ -184,109 +167,111 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, override fun updateUI() { // null myPlace means that Swing calls updateUI before our constructor - if (screenMenuPeer != null || myPlace == null) { + @Suppress("SENSELESS_COMPARISON") + if (screenMenuPeer != null || place == null) { return } + setUI(IdeaMenuUI.createUI(this)) setFont(FontUtil.getMenuFont()) - val popupMenu = getPopupMenu() - if (popupMenu != null) { - popupMenu.updateUI() - } + getPopupMenu().updateUI() } private fun init() { - val macSystemMenu = SystemInfo.isMacSystemMenu && isMainMenuPlace - myStubItem = if (macSystemMenu) null else StubItem() + stubItem = if (SystemInfo.isMacSystemMenu && isMainMenuPlace) null else StubItem() addStubItem() setBorderPainted(false) val menuListener = MenuListenerImpl() addMenuListener(menuListener) getModel().addChangeListener(menuListener) - updateFromPresentation(myMnemonicEnabled) + updateFromPresentation(isMnemonicEnabled) } val isMainMenuPlace: Boolean - get() = myPlace == ActionPlaces.MAIN_MENU + get() = place == ActionPlaces.MAIN_MENU fun updateFromPresentation(enableMnemonics: Boolean) { - myMnemonicEnabled = enableMnemonics - isVisible = myPresentation.isVisible - setEnabled(myPresentation.isEnabled) - setText(myPresentation.getText(myMnemonicEnabled)) - mnemonic = myPresentation.getMnemonic() - displayedMnemonicIndex = myPresentation.getDisplayedMnemonicIndex() + isMnemonicEnabled = enableMnemonics + isVisible = presentation.isVisible + setEnabled(presentation.isEnabled) + setText(presentation.getText(isMnemonicEnabled)) + mnemonic = presentation.getMnemonic() + displayedMnemonicIndex = presentation.getDisplayedMnemonicIndex() updateIcon() } private fun addStubItem() { - if (myStubItem != null) { - add(myStubItem) + stubItem?.let { + add(it) } } - @Throws(IllegalArgumentException::class) override fun setDisplayedMnemonicIndex(index: Int) { - super.setDisplayedMnemonicIndex(if (myMnemonicEnabled) index else -1) + super.setDisplayedMnemonicIndex(if (isMnemonicEnabled) index else -1) } override fun setMnemonic(mnemonic: Int) { - super.setMnemonic(if (myMnemonicEnabled) mnemonic else 0) + super.setMnemonic(if (isMnemonicEnabled) mnemonic else 0) } private fun updateIcon() { - val settings = instanceOrNull - var icon = myPresentation.icon - if (icon != null && settings != null && settings.showIconsInMenus) { - if (SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == myPlace) { - // JDK can't paint correctly our HiDPI icons at the system menu bar - icon = getMenuBarIcon(icon, myUseDarkIcons) - } - else if (shouldConvertIconToDarkVariant()) { - icon = getDarkIcon(icon, true) - } - if (isShowNoIcons) { - setIcon(null) - setDisabledIcon(null) - } - else { - setIcon(icon) - val presentationDisabledIcon = myPresentation.disabledIcon - setDisabledIcon(presentationDisabledIcon ?: getDisabledIcon(icon)) - screenMenuPeer?.setIcon(icon) - } + var icon = presentation.icon ?: return + if (!UISettings.getInstance().showIconsInMenus) { + return + } + + if (SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == place) { + // JDK can't paint correctly our HiDPI icons at the system menu bar + icon = getMenuBarIcon(icon, useDarkIcons) + } + else if (shouldConvertIconToDarkVariant()) { + icon = getDarkIcon(icon, true) + } + + if (isShowNoIcons) { + setIcon(null) + setDisabledIcon(null) + } + else { + setIcon(icon) + val presentationDisabledIcon = presentation.disabledIcon + setDisabledIcon(presentationDisabledIcon ?: getDisabledIcon(icon)) + screenMenuPeer?.setIcon(icon) } } override fun menuSelectionChanged(isIncluded: Boolean) { super.menuSelectionChanged(isIncluded) - showDescriptionInStatusBar(isIncluded, this, myPresentation.description) + showDescriptionInStatusBar(isIncluded = isIncluded, component = this, description = presentation.description) } override fun processMouseEvent(e: MouseEvent) { var shouldCancelIgnoringOfNextSelectionRequest = false - if (mySubElementSelector != null) { + val subElementSelector = subElementSelector + if (subElementSelector != null) { when (e.id) { MouseEvent.MOUSE_PRESSED -> { - mySubElementSelector.ignoreNextSelectionRequest() + subElementSelector.ignoreNextSelectionRequest() shouldCancelIgnoringOfNextSelectionRequest = true } - MouseEvent.MOUSE_ENTERED -> mySubElementSelector.ignoreNextSelectionRequest(delay * 2) + MouseEvent.MOUSE_ENTERED -> subElementSelector.ignoreNextSelectionRequest(delay * 2) } } + try { super.processMouseEvent(e) } finally { if (shouldCancelIgnoringOfNextSelectionRequest) { - mySubElementSelector!!.cancelIgnoringOfNextSelectionRequest() + subElementSelector?.cancelIgnoringOfNextSelectionRequest() } } } private inner class MenuListenerImpl : ChangeListener, MenuListener { - var myDelayedClear: ScheduledFuture<*>? = null + var delayedClear: ScheduledFuture<*>? = null var isSelected: Boolean = false + override fun stateChanged(e: ChangeEvent) { // Re-implement javax.swing.JMenu.MenuChangeListener to avoid recursive event notifications // if 'menuSelected' fires unrelated 'stateChanged' event, without changing 'model.isSelected()' value. @@ -316,12 +301,12 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, } private fun menuDeselected() { - if (myDisposable != null) { - Disposer.dispose(myDisposable!!) - myDisposable = null + if (disposable != null) { + Disposer.dispose(disposable!!) + disposable = null } onMenuHidden() - mySubElementSelector?.cancelNextSelection() + subElementSelector?.cancelNextSelection() } private fun onMenuHidden() { @@ -329,13 +314,14 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, clearItems() addStubItem() } + if (SystemInfo.isMacSystemMenu && isMainMenuPlace) { // Menu items may contain mnemonic, and they can affect key-event dispatching (when Alt pressed) // To avoid the influence of mnemonic it's necessary to clear items when a menu was hidden. // When a user selects item of a system menu (under macOS), AppKit generates such sequence: CloseParentMenu -> PerformItemAction // So we can destroy menu-item before item's action performed, and because of that action will not be executed. // Defer clearing to avoid this problem. - myDelayedClear = EdtScheduledExecutorService.getInstance().schedule(clearSelf, 1000, TimeUnit.MILLISECONDS) + delayedClear = EdtScheduledExecutorService.getInstance().schedule(clearSelf, 1000, TimeUnit.MILLISECONDS) } else { clearSelf.run() @@ -344,31 +330,33 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, private fun menuSelected() { val helper = UsabilityHelper(this@ActionMenu) - if (myDisposable == null) { - myDisposable = Disposer.newDisposable() + if (disposable == null) { + disposable = Disposer.newDisposable() } - Disposer.register(myDisposable!!, helper) - if (myDelayedClear != null) { - myDelayedClear!!.cancel(false) - myDelayedClear = null + Disposer.register(disposable!!, helper) + if (delayedClear != null) { + delayedClear!!.cancel(false) + delayedClear = null clearItems() } - if (SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == myPlace) { + if (SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == place) { fillMenu() } } } - override fun setPopupMenuVisible(b: Boolean) { - if (b && !(SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == myPlace)) { + override fun setPopupMenuVisible(value: Boolean) { + if (value && !(SystemInfo.isMacSystemMenu && ActionPlaces.MAIN_MENU == place)) { fillMenu() if (!isSelected) { return } } - super.setPopupMenuVisible(b) - if (b && mySubElementSelector != null) { - mySubElementSelector.selectSubElementIfNecessary() + + super.setPopupMenuVisible(value) + + if (value) { + subElementSelector?.selectSubElementIfNecessary() } } @@ -381,7 +369,7 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, else if (menuComponent is ActionMenuItem) { // Looks like an old-fashioned ugly workaround // JDK 1.7 on Mac works wrong with such functional keys - if (!SystemInfo.isMac) { + if (!SystemInfoRt.isMac) { menuComponent.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F24, 0)) } } @@ -391,117 +379,134 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, validate() } - private val dataContext: DataContext - private get() { - var context: DataContext - if (myContext != null) { - context = myContext - } - else { - val dataManager = DataManager.getInstance() - @Suppress("deprecation") val contextFromFocus = dataManager.getDataContext() - context = contextFromFocus - if (PlatformCoreDataKeys.CONTEXT_COMPONENT.getData(context) == null) { - val frame = ComponentUtil.getParentOfType(IdeFrame::class.java as Class, this as Component) - context = dataManager.getDataContext(IdeFocusManager.getGlobalInstance().getLastFocusedFor(frame as Window?)) - } - context = Utils.wrapDataContext(context) - } + private fun getDataContext(): DataContext { + var context = context + if (context != null) { return context } + val dataManager = DataManager.getInstance() + @Suppress("DEPRECATION") + context = dataManager.getDataContext() + if (PlatformCoreDataKeys.CONTEXT_COMPONENT.getData(context) == null) { + val frame = ComponentUtil.getParentOfType(IdeFrame::class.java, this) + context = dataManager.getDataContext(IdeFocusManager.getGlobalInstance().getLastFocusedFor(frame as Window?)) + } + return Utils.wrapDataContext(context) + } + fun fillMenu() { - val context = dataContext + val context = getDataContext() val isDarkMenu = SystemInfo.isMacSystemMenu && NSDefaults.isDarkMenuBar() - Utils.fillMenu(myGroup.getAction(), this, myMnemonicEnabled, myPresentationFactory, context, myPlace!!, true, isDarkMenu, - RelativePoint.getNorthEastOf(this)) { !isSelected } + Utils.fillMenu(/* group = */ group.getAction(), + /* component = */ this, + /* enableMnemonics = */ isMnemonicEnabled, + /* presentationFactory = */ presentationFactory, + /* context = */ context, + /* place = */ place, + /* isWindowMenu = */ true, + /* useDarkIcons = */ isDarkMenu, + /* progressPoint = */ RelativePoint.getNorthEastOf(this)) { !isSelected } } private class UsabilityHelper(component: Component) : IdeEventQueue.EventDispatcher, AWTEventListener, Disposable { - private var myComponent: Component? - private var myStartMousePoint: Point? - private var myUpperTargetPoint: Point? = null - private var myLowerTargetPoint: Point? = null - private var callbackAlarm: SingleAlarm? - private var myEventToRedispatch: MouseEvent? = null + private var component: Component? + private var startMousePoint: Point? + private var upperTargetPoint: Point? = null + private var lowerTargetPoint: Point? = null + private var callbackAlarm: SingleAlarm? = null + private var eventToRedispatch: MouseEvent? = null init { callbackAlarm = SingleAlarm({ - //Disposer.dispose(callbackAlarm!!) - callbackAlarm = null - if (myEventToRedispatch != null) { - getInstance().dispatchEvent(myEventToRedispatch!!) - } - }, 50, this, Alarm.ThreadToUse.SWING_THREAD, ModalityState.any()) - myComponent = component + Disposer.dispose(callbackAlarm!!) + callbackAlarm = null + if (eventToRedispatch != null) { + getInstance().dispatchEvent(eventToRedispatch!!) + } + }, 50, this, Alarm.ThreadToUse.SWING_THREAD, ModalityState.any()) + this.component = component val info = MouseInfo.getPointerInfo() - myStartMousePoint = info?.location - if (myStartMousePoint != null) { + startMousePoint = info?.location + if (startMousePoint != null) { Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.COMPONENT_EVENT_MASK) getInstance().addDispatcher(this, this) } } override fun eventDispatched(event: AWTEvent) { - if (event is ComponentEvent) { - val component: Component = event.component - val popup = ComponentUtil.getParentOfType(JPopupMenu::class.java as Class, component) - if (popup != null && popup.invoker === myComponent && popup.isShowing()) { - val bounds = popup.bounds - if (bounds.isEmpty) return - bounds.location = popup.locationOnScreen - if (myStartMousePoint!!.x < bounds.x) { - myUpperTargetPoint = Point(bounds.x, bounds.y) - myLowerTargetPoint = Point(bounds.x, bounds.y + bounds.height) - } - if (myStartMousePoint!!.x > bounds.x + bounds.width) { - myUpperTargetPoint = Point(bounds.x + bounds.width, bounds.y) - myLowerTargetPoint = Point(bounds.x + bounds.width, bounds.y + bounds.height) - } + if (event !is ComponentEvent) { + return + } + + val component = event.component + val popup = ComponentUtil.getParentOfType(JPopupMenu::class.java, component) + if (popup != null && popup.invoker === this.component && popup.isShowing()) { + val bounds = popup.bounds + if (bounds.isEmpty) { + return + } + + bounds.location = popup.locationOnScreen + if (startMousePoint!!.x < bounds.x) { + upperTargetPoint = Point(bounds.x, bounds.y) + lowerTargetPoint = Point(bounds.x, bounds.y + bounds.height) + } + if (startMousePoint!!.x > bounds.x + bounds.width) { + upperTargetPoint = Point(bounds.x + bounds.width, bounds.y) + lowerTargetPoint = Point(bounds.x + bounds.width, bounds.y + bounds.height) } } } override fun dispatch(e: AWTEvent): Boolean { - if (e is MouseEvent && myUpperTargetPoint != null && myLowerTargetPoint != null && callbackAlarm != null) { - if (e.getID() == MouseEvent.MOUSE_PRESSED || e.getID() == MouseEvent.MOUSE_RELEASED || e.getID() == MouseEvent.MOUSE_CLICKED) { - return false - } - val point = e.locationOnScreen - val bounds = myComponent!!.bounds - bounds.location = myComponent!!.locationOnScreen - val isMouseMovingTowardsSubmenu = bounds.contains(point) || Polygon(intArrayOf( - myStartMousePoint!!.x, myUpperTargetPoint!!.x, myLowerTargetPoint!!.x), intArrayOf(myStartMousePoint!!.y, myUpperTargetPoint!!.y, - myLowerTargetPoint!!.y), - 3).contains(point) - myEventToRedispatch = e - if (!isMouseMovingTowardsSubmenu) { - callbackAlarm!!.request() - } - else { - callbackAlarm!!.cancel() - } - return true + val callbackAlarm = callbackAlarm + if (e !is MouseEvent || upperTargetPoint == null || lowerTargetPoint == null || callbackAlarm == null) { + return false } - return false + + if (e.getID() == MouseEvent.MOUSE_PRESSED || e.getID() == MouseEvent.MOUSE_RELEASED || e.getID() == MouseEvent.MOUSE_CLICKED) { + return false + } + + val point = e.locationOnScreen + val bounds = component!!.bounds + bounds.location = component!!.locationOnScreen + val isMouseMovingTowardsSubmenu = bounds.contains(point) || + Polygon(intArrayOf(startMousePoint!!.x, upperTargetPoint!!.x, lowerTargetPoint!!.x), + intArrayOf(startMousePoint!!.y, upperTargetPoint!!.y, lowerTargetPoint!!.y), 3) + .contains(point) + eventToRedispatch = e + if (!isMouseMovingTowardsSubmenu) { + callbackAlarm.request() + } + else { + callbackAlarm.cancel() + } + return true } override fun dispose() { - myComponent = null - myEventToRedispatch = null - myLowerTargetPoint = null - myUpperTargetPoint = myLowerTargetPoint - myStartMousePoint = myUpperTargetPoint + component = null + eventToRedispatch = null + lowerTargetPoint = null + upperTargetPoint = null + startMousePoint = null Toolkit.getDefaultToolkit().removeAWTEventListener(this) } } - private class SubElementSelector(owner: ActionMenu) { + private class SubElementSelector(private val owner: ActionMenu) { + companion object { + val isForceDisabled: Boolean = SystemInfo.isMacSystemMenu || + !Registry.`is`("ide.popup.menu.navigation.keyboard.selectFirstEnabledSubItem", false) + } + @RequiresEdt fun ignoreNextSelectionRequest(timeoutMs: Int) { - myShouldIgnoreNextSelectionRequest = true - myShouldIgnoreNextSelectionRequestTimeoutMs = timeoutMs - myShouldIgnoreNextSelectionRequestSinceTimestamp = if (timeoutMs >= 0) { + shouldIgnoreNextSelectionRequest = true + shouldIgnoreNextSelectionRequestTimeoutMs = timeoutMs + shouldIgnoreNextSelectionRequestSinceTimestamp = if (timeoutMs >= 0) { System.currentTimeMillis() } else { @@ -516,17 +521,16 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, @RequiresEdt fun cancelIgnoringOfNextSelectionRequest() { - myShouldIgnoreNextSelectionRequest = false - myShouldIgnoreNextSelectionRequestSinceTimestamp = -1 - myShouldIgnoreNextSelectionRequestTimeoutMs = -1 + shouldIgnoreNextSelectionRequest = false + shouldIgnoreNextSelectionRequestSinceTimestamp = -1 + shouldIgnoreNextSelectionRequestTimeoutMs = -1 } @RequiresEdt fun selectSubElementIfNecessary() { - val shouldIgnoreThisSelectionRequest: Boolean - shouldIgnoreThisSelectionRequest = if (myShouldIgnoreNextSelectionRequest) { - if (myShouldIgnoreNextSelectionRequestTimeoutMs >= 0) { - System.currentTimeMillis() - myShouldIgnoreNextSelectionRequestSinceTimestamp <= myShouldIgnoreNextSelectionRequestTimeoutMs + val shouldIgnoreThisSelectionRequest = if (shouldIgnoreNextSelectionRequest) { + if (shouldIgnoreNextSelectionRequestTimeoutMs >= 0) { + System.currentTimeMillis() - shouldIgnoreNextSelectionRequestSinceTimestamp <= shouldIgnoreNextSelectionRequestTimeoutMs } else { true @@ -535,78 +539,66 @@ class ActionMenu @JvmOverloads constructor(private val myContext: DataContext?, else { false } + cancelIgnoringOfNextSelectionRequest() if (shouldIgnoreThisSelectionRequest) { return } - val thisRequestId = ++myCurrentRequestId + + val thisRequestId = ++currentRequestId SwingUtilities.invokeLater { selectFirstEnabledElement(thisRequestId) } } @RequiresEdt fun cancelNextSelection() { - ++myCurrentRequestId + ++currentRequestId } - private val myOwner: ActionMenu - private var myShouldIgnoreNextSelectionRequest: Boolean - private var myShouldIgnoreNextSelectionRequestSinceTimestamp: Long - private var myShouldIgnoreNextSelectionRequestTimeoutMs: Int - private var myCurrentRequestId: Int + private var shouldIgnoreNextSelectionRequest = false + private var shouldIgnoreNextSelectionRequestSinceTimestamp = -1L + private var shouldIgnoreNextSelectionRequestTimeoutMs = -1 + private var currentRequestId = -1 init { if (isForceDisabled) { throw IllegalStateException("Attempt to create an instance of ActionMenu.SubElementSelector class when it is force disabled") } - myOwner = owner - myShouldIgnoreNextSelectionRequest = false - myShouldIgnoreNextSelectionRequestSinceTimestamp = -1 - myShouldIgnoreNextSelectionRequestTimeoutMs = -1 - myCurrentRequestId = -1 } @RequiresEdt private fun selectFirstEnabledElement(requestId: Int) { - if (requestId != myCurrentRequestId) { - // the request was cancelled or a newer request was created + if (requestId != currentRequestId) { + // the request was canceled or a newer request was created return } - if (!myOwner.isSelected) { + + if (!owner.isSelected) { return } + val menuSelectionManager = MenuSelectionManager.defaultManager() val currentSelectedPath = menuSelectionManager.getSelectedPath() if (currentSelectedPath.size < 2) { return } + val lastElementInCurrentPath = currentSelectedPath[currentSelectedPath.size - 1] - val newSelectionPath: Array - newSelectionPath = if (lastElementInCurrentPath === myOwner.myStubItem) { - currentSelectedPath.clone() + val newSelectionPath = when { + lastElementInCurrentPath === owner.stubItem -> currentSelectedPath.clone() + lastElementInCurrentPath === owner.getPopupMenu() -> currentSelectedPath.copyOf(currentSelectedPath.size + 1) + currentSelectedPath[currentSelectedPath.size - 2] === owner.getPopupMenu() && + !owner.getMenuComponents().contains(lastElementInCurrentPath!!.component) -> currentSelectedPath.clone() + else -> return } - else if (lastElementInCurrentPath === myOwner.getPopupMenu()) { - currentSelectedPath.copyOf(currentSelectedPath.size + 1) - } - else if (currentSelectedPath[currentSelectedPath.size - 2] === myOwner.getPopupMenu() && - !ArrayUtil.contains(lastElementInCurrentPath!!.component, *myOwner.getMenuComponents())) { - currentSelectedPath.clone() - } - else { - return - } - val menuComponents = myOwner.getMenuComponents() + + val menuComponents = owner.getMenuComponents() for (component in menuComponents) { - if (component !== myOwner.myStubItem && component.isEnabled && component is JMenuItem) { - newSelectionPath[newSelectionPath.size - 1] = component as MenuElement + if (component != owner.stubItem && component.isEnabled && component is JMenuItem) { + newSelectionPath[newSelectionPath.size - 1] = component menuSelectionManager.setSelectedPath(newSelectionPath) return } } } - - companion object { - val isForceDisabled: Boolean = SystemInfo.isMacSystemMenu || - !Registry.`is`("ide.popup.menu.navigation.keyboard.selectFirstEnabledSubItem", false) - } } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameDecorator.java index a5981dc725d0..2c5b0c47ad4c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameDecorator.java @@ -29,7 +29,7 @@ import static com.intellij.openapi.ui.impl.DialogWrapperPeerImpl.isDisableAutoRe import static com.intellij.openapi.wm.impl.WindowManagerImplKt.IDE_FRAME_EVENT_LOG; public abstract class IdeFrameDecorator { - static final String FULL_SCREEN = "ide.frame.full.screen"; + public static final String FULL_SCREEN = "ide.frame.full.screen"; protected final IdeFrameImpl frame; @@ -152,8 +152,9 @@ public abstract class IdeFrameDecorator { if (toFocus != null && !(toFocus instanceof JRootPane)) { // Window 'forgets' last focused component on disposal, so we need to restore it explicitly. - // Special case is toggling fullscreen mode from menu. In this case menu UI moves focus to the root pane before performing - // the action. We shouldn't explicitly request focus in this case - menu UI will restore the focus without our help. + // Special case is toggling fullscreen mode from a menu. + // In this case menu UI moves focus to the root pane before performing the action. + // We shouldn't explicitly request focus in this case - menu UI will restore the focus without our help. toFocus.requestFocusInWindow(); } } @@ -234,7 +235,7 @@ public abstract class IdeFrameDecorator { public static boolean isCustomDecorationActive() { UISettings settings = UISettings.getInstanceOrNull(); if (settings == null) { - // true by default if no settings is available (e.g. during the initial IDE setup wizard) and not overridden (only for Windows) + // true by default if no settings are available (e.g., during the initial IDE setup wizard) and not overridden (only for Windows) return isCustomDecorationAvailable() && getDefaultCustomDecorationState(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt index ab646ba9b696..edb96240c5c8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt @@ -3,6 +3,7 @@ package com.intellij.openapi.wm.impl import com.intellij.DynamicBundle import com.intellij.diagnostic.runActivity +import com.intellij.ide.menu.* import com.intellij.ide.ui.UISettings import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.diagnostic.Logger diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt index 4e7b29004f55..1a0a22cf1dd5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt @@ -8,6 +8,8 @@ import com.intellij.diagnostic.rootTask import com.intellij.diagnostic.subtask import com.intellij.ide.GeneralSettings import com.intellij.ide.actions.ToggleDistractionFreeModeAction +import com.intellij.ide.menu.ActionAwareIdeMenuBar +import com.intellij.ide.menu.createMacMenuBar import com.intellij.ide.ui.UISettings import com.intellij.ide.ui.UISettingsListener import com.intellij.ide.ui.customization.CustomActionsSchema From d0d59f38804ac421c8d284d601d31ffe54efab8a Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 17:47:15 +0200 Subject: [PATCH 124/226] make sure we don't menu update too often GitOrigin-RevId: b56bc8fb571ea5462fa858a91d57e501deff43bf --- .../com/intellij/ide/menu/IdeMenuBarHelper.kt | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/menu/IdeMenuBarHelper.kt b/platform/platform-impl/src/com/intellij/ide/menu/IdeMenuBarHelper.kt index 83a7633445cb..a24913e77778 100644 --- a/platform/platform-impl/src/com/intellij/ide/menu/IdeMenuBarHelper.kt +++ b/platform/platform-impl/src/com/intellij/ide/menu/IdeMenuBarHelper.kt @@ -1,6 +1,4 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -@file:OptIn(FlowPreview::class) - package com.intellij.ide.menu import com.intellij.diagnostic.StartUpMeasurer @@ -31,16 +29,15 @@ import com.intellij.openapi.wm.impl.IdeRootPane import kotlinx.coroutines.* import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.debounce import org.jetbrains.concurrency.await import java.awt.Component import java.awt.Dialog import java.awt.Dimension import java.awt.KeyboardFocusManager +import java.util.concurrent.atomic.AtomicLong import javax.swing.JComponent import javax.swing.JFrame import kotlin.coroutines.EmptyCoroutineContext -import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds internal interface ActionAwareIdeMenuBar { @@ -102,8 +99,7 @@ internal sealed class IdeMenuBarHelper(@JvmField val flavor: IdeMenuFlavor, coroutineScope.launch(ModalityState.any().asContextElement()) { withContext(if (StartUpMeasurer.isEnabled()) (rootTask() + CoroutineName("ide menu bar actions init")) else EmptyCoroutineContext) { - val mainActionGroup = menuBar.getMainMenuActionGroup() - val actions = updateMenuActions(mainActionGroup = mainActionGroup, forceRebuild = false, isFirstUpdate = true) + val actions = updateMenuActions(mainActionGroup = menuBar.getMainMenuActionGroup(), forceRebuild = false, isFirstUpdate = true) postInitActions(actions) } @@ -116,16 +112,41 @@ internal sealed class IdeMenuBarHelper(@JvmField val flavor: IdeMenuFlavor, } } + val lastUpdate = AtomicLong(System.currentTimeMillis()) updateRequests - // as ActionManagerImpl TIMER_DELAY - .debounce(500.milliseconds) .collect { forceRebuild -> + // as ActionManagerImpl TIMER_DELAY + if ((System.currentTimeMillis() - lastUpdate.get()) < 500) { + return@collect + } + + if (!withContext(Dispatchers.EDT) { filterUpdate() }) { + return@collect + } + presentationFactory.reset() updateMenuActions(mainActionGroup = menuBar.getMainMenuActionGroup(), forceRebuild = forceRebuild, isFirstUpdate = false) + lastUpdate.set(System.currentTimeMillis()) } } } + private fun filterUpdate(): Boolean { + if (!menuBar.frame.isShowing || !menuBar.frame.isActive) { + return false + } + + // do not update when a popup menu is shown + // (if a popup menu contains action which is also in the menu bar, it should not be enabled/disabled) + if (isUpdateForbidden()) { + return false + } + + // don't update the toolbar if there is currently active modal dialog + val window = KeyboardFocusManager.getCurrentKeyboardFocusManager().focusedWindow + return window !is Dialog || !window.isModal + } + private suspend fun updateOnTimer() { withContext(Dispatchers.EDT) { // don't update the toolbar if there is currently active modal dialog @@ -172,14 +193,13 @@ internal suspend fun expandMainActionGroup(mainActionGroup: ActionGroup, frame: JFrame, presentationFactory: PresentationFactory, isFirstUpdate: Boolean): List { - val actionManager = serviceAsync() if (!useAsyncExpand) { - return syncExpandMainActionGroup(mainActionGroup, actionManager, frame, menuBar, presentationFactory) + return syncExpandMainActionGroup(mainActionGroup, serviceAsync(), frame, menuBar, presentationFactory) } try { return withContext(CoroutineName("expandMainActionGroup") + Dispatchers.EDT) { - val targetComponent = WindowManager.getInstance().getFocusedComponent(frame) ?: menuBar + val targetComponent = serviceAsync().getFocusedComponent(frame) ?: menuBar val dataContext = Utils.wrapToAsyncDataContext(DataManager.getInstance().getDataContext(targetComponent)) val fastTrackTimeout = if (isFirstUpdate) firstUpdateFastTrackUpdateTimeout else Utils.getFastTrackTimeout() Utils.expandActionGroupAsync(/* group = */ mainActionGroup, @@ -212,7 +232,7 @@ private suspend fun syncExpandMainActionGroup(mainActionGroup: ActionGroup, } val targetComponent = WindowManager.getInstance().getFocusedComponent(frame) ?: menuBar - val dataContext = Utils.wrapToAsyncDataContext(DataManager.getInstance().getDataContext(targetComponent)) + val dataContext = DataManager.getInstance().getDataContext(targetComponent) val list = mutableListOf() for (action in children) { if (action !is ActionGroup) { From 681defeda87fd5e0b33cfb6741c28e3b0978951e Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 18:10:45 +0200 Subject: [PATCH 125/226] apple.laf.useScreenMenuBar is deprecated GitOrigin-RevId: 58fa1694cc3db41524f318955030357ed04f45b2 --- build/launch/src/com/intellij/tools/launch/Launcher.kt | 2 -- platform/util/src/com/intellij/openapi/util/SystemInfo.java | 3 +-- plugins/devkit/devkit-core/src/run/PluginRunConfiguration.java | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/build/launch/src/com/intellij/tools/launch/Launcher.kt b/build/launch/src/com/intellij/tools/launch/Launcher.kt index 4ec0dd0e8c31..6d3b97ee461d 100644 --- a/build/launch/src/com/intellij/tools/launch/Launcher.kt +++ b/build/launch/src/com/intellij/tools/launch/Launcher.kt @@ -7,7 +7,6 @@ import org.jetbrains.intellij.build.dependencies.TeamCityHelper import java.io.File import java.net.InetAddress import java.net.ServerSocket -import java.nio.file.Files import java.util.logging.Logger object Launcher { @@ -33,7 +32,6 @@ object Launcher { val cmd = mutableListOf( paths.javaExecutable.canonicalPath, "-ea", - "-Dapple.laf.useScreenMenuBar=true", "-Dfus.internal.test.mode=true", "-Djb.privacy.policy.text=\"\"", "-Djb.consents.confirmation.enabled=false", diff --git a/platform/util/src/com/intellij/openapi/util/SystemInfo.java b/platform/util/src/com/intellij/openapi/util/SystemInfo.java index fd3ac82d639f..c5743e466191 100644 --- a/platform/util/src/com/intellij/openapi/util/SystemInfo.java +++ b/platform/util/src/com/intellij/openapi/util/SystemInfo.java @@ -75,10 +75,9 @@ public final class SystemInfo { } } - public static final boolean isAppleSystemMenu = isMac && Boolean.getBoolean("apple.laf.useScreenMenuBar"); public static final boolean isJBSystemMenu = isMac && Boolean.getBoolean("jbScreenMenuBar.enabled"); - public static final boolean isMacSystemMenu = isAppleSystemMenu || isJBSystemMenu; + public static final boolean isMacSystemMenu = isJBSystemMenu || Boolean.getBoolean("apple.laf.useScreenMenuBar"); public static final boolean isFileSystemCaseSensitive = SystemInfoRt.isFileSystemCaseSensitive; diff --git a/plugins/devkit/devkit-core/src/run/PluginRunConfiguration.java b/plugins/devkit/devkit-core/src/run/PluginRunConfiguration.java index a26e024135aa..7bae670b784c 100644 --- a/plugins/devkit/devkit-core/src/run/PluginRunConfiguration.java +++ b/plugins/devkit/devkit-core/src/run/PluginRunConfiguration.java @@ -223,7 +223,6 @@ public class PluginRunConfiguration extends RunConfigurationBase implem } if (SystemInfo.isMac) { - vm.defineProperty("apple.laf.useScreenMenuBar", "true"); vm.defineProperty("apple.awt.fileDialogForDirectories", "true"); } From 1ea5b103b768a6fe5022c253052e2264867e6f73 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 18:19:32 +0200 Subject: [PATCH 126/226] simplify IdeMenuBar creation GitOrigin-RevId: d6e607df83aac70ac03848f1e01d0a7e937e8219 --- .../src/com/intellij/ide/menu/MacMenuBar.kt | 17 +-- .../ui/impl/DialogWrapperPeerImpl.java | 2 +- .../intellij/openapi/wm/impl/IdeMenuBar.kt | 22 +--- .../intellij/openapi/wm/impl/IdeRootPane.kt | 13 +- .../CustomFrameTitleButtons.kt | 78 ++++++------ .../header/CustomHeader.kt | 33 +++--- .../header/DefaultFrameHeader.kt | 4 +- .../header/DialogHeader.kt | 112 ++++++++++-------- .../header/FrameHeader.kt | 11 +- .../header/MacToolbarFrameHeader.kt | 4 +- .../header/MenuFrameHeader.kt | 2 +- 11 files changed, 141 insertions(+), 157 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt b/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt index d2571c95cd38..d28b6aa26347 100644 --- a/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt +++ b/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt @@ -2,9 +2,10 @@ package com.intellij.ide.menu import com.intellij.diagnostic.runActivity -import com.intellij.openapi.wm.impl.createScreeMenuPeer +import com.intellij.openapi.util.Disposer import com.intellij.openapi.wm.impl.doUpdateAppMenu import com.intellij.ui.mac.foundation.NSDefaults +import com.intellij.ui.mac.screenmenu.MenuBar import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.job import javax.swing.JComponent @@ -33,19 +34,11 @@ internal fun createMacMenuBar(coroutineScope: CoroutineScope, component: JCompon override suspend fun getMainMenuActionGroup() = getMainMenuActionGroup(frame) } - val screenMenuPeer = runActivity("ide menu bar init") { createScreeMenuPeer(frame) } - val menuBarHelper = if (screenMenuPeer == null) { - JMenuBasedIdeMenuBarHelper(flavor = flavor, menuBar = facade) - } - else { - PeerBasedIdeMenuBarHelper(screenMenuPeer = screenMenuPeer, flavor = flavor, menuBar = facade) - } + val screenMenuPeer = runActivity("ide menu bar init") { MenuBar("MainMenu", frame) } + val menuBarHelper = PeerBasedIdeMenuBarHelper(screenMenuPeer = screenMenuPeer, flavor = flavor, menuBar = facade) coroutineScope.coroutineContext.job.invokeOnCompletion { - screenMenuPeer?.let { - @Suppress("SSBasedInspection") - it.dispose() - } + Disposer.dispose(screenMenuPeer) } return menuBarHelper } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java index d6e015ab5c14..e7a030862fed 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java @@ -663,7 +663,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer { @Override public void addNotify() { if (IdeFrameDecorator.isCustomDecorationActive()) { - CustomHeader.enableCustomHeader(this); + CustomHeader.Companion.enableCustomHeader(this); } super.addNotify(); if (SystemInfo.isMacOSVentura && Registry.is("ide.mac.stage.manager.support", false)) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt index edb96240c5c8..3450f58a133a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt @@ -2,7 +2,6 @@ package com.intellij.openapi.wm.impl import com.intellij.DynamicBundle -import com.intellij.diagnostic.runActivity import com.intellij.ide.menu.* import com.intellij.ide.ui.UISettings import com.intellij.openapi.actionSystem.ActionGroup @@ -15,7 +14,6 @@ import com.intellij.ui.Gray import com.intellij.ui.ScreenUtil import com.intellij.ui.mac.foundation.NSDefaults import com.intellij.ui.mac.screenmenu.Menu -import com.intellij.ui.mac.screenmenu.MenuBar import com.intellij.ui.plaf.beg.IdeaMenuUI import com.intellij.util.ui.JBUI import com.intellij.util.ui.StartupUiUtil @@ -43,8 +41,6 @@ open class IdeMenuBar internal constructor(@JvmField internal val coroutineScope @JvmField internal val frame: JFrame) : JMenuBar(), ActionAwareIdeMenuBar { private val menuBarHelper: IdeMenuBarHelper - private val screenMenuPeer: MenuBar? - init { val flavor = if (isFloatingMenuBarSupported) { FloatingMenuBarFlavor(this) @@ -74,14 +70,7 @@ open class IdeMenuBar internal constructor(@JvmField internal val coroutineScope override suspend fun getMainMenuActionGroup(): ActionGroup? = this@IdeMenuBar.getMainMenuActionGroup() } - screenMenuPeer = runActivity("ide menu bar init") { createScreeMenuPeer(frame) } - if (screenMenuPeer == null) { - menuBarHelper = JMenuBasedIdeMenuBarHelper(flavor = flavor, menuBar = facade) - } - else { - menuBarHelper = PeerBasedIdeMenuBarHelper(screenMenuPeer = screenMenuPeer, flavor = flavor, menuBar = facade) - } - + menuBarHelper = JMenuBasedIdeMenuBarHelper(flavor = flavor, menuBar = facade) if (IdeFrameDecorator.isCustomDecorationActive()) { isOpaque = false } @@ -148,11 +137,6 @@ open class IdeMenuBar internal constructor(@JvmField internal val coroutineScope override fun removeNotify() { if (ScreenUtil.isStandardAddRemoveNotify(this)) { - screenMenuPeer?.let { - @Suppress("SSBasedInspection") - it.dispose() - } - menuBarHelper.flavor.suspendAnimator() } super.removeNotify() @@ -241,10 +225,6 @@ internal fun doUpdateAppMenu() { //} } -internal fun createScreeMenuPeer(frame: JFrame): MenuBar? { - return if (Menu.isJbScreenMenuEnabled()) MenuBar("MainMenu", frame) else null -} - internal fun createMenuBar(coroutineScope: CoroutineScope, frame: JFrame): IdeMenuBar { return if (SystemInfoRt.isLinux) LinuxIdeMenuBar(coroutineScope, frame) else IdeMenuBar(coroutineScope, frame) } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt index 1a0a22cf1dd5..17882915c503 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt @@ -178,20 +178,19 @@ open class IdeRootPane internal constructor(private val frame: IdeFrameImpl, val customFrameTitlePane = if (ExperimentalUI.isNewUI()) { selectedEditorFilePath = null if (SystemInfoRt.isMac) { - ideMenu = if (isFloatingMenuBarSupported || !Menu.isJbScreenMenuEnabled()) { - val menuBar = IdeMenuBar(coroutineScope.childScope(), frame) + ideMenu = if (Menu.isJbScreenMenuEnabled()) { + createMacMenuBar(coroutineScope = coroutineScope.childScope(), component = this, frame = frame) + } + else { + val menuBar = IdeMenuBar(coroutineScope = coroutineScope.childScope(), frame = frame) // if -DjbScreenMenuBar.enabled=false frame.jMenuBar = menuBar menuBar } - else { - createMacMenuBar(coroutineScope = coroutineScope.childScope(), component = this, frame = frame) - } - MacToolbarFrameHeader(coroutineScope = coroutineScope.childScope(), frame = frame, root = this) } else { - ideMenu = createMenuBar(coroutineScope.childScope(), frame) + ideMenu = createMenuBar(coroutineScope = coroutineScope.childScope(), frame = frame) ToolbarFrameHeader(coroutineScope = coroutineScope.childScope(), frame = frame, root = this, ideMenuBar = ideMenu) } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt index 59f5262e0498..d92b7285e4f0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations import com.intellij.icons.AllIcons @@ -6,10 +6,7 @@ import com.intellij.ide.ui.UISettings import com.intellij.openapi.wm.impl.customFrameDecorations.style.ComponentStyle import com.intellij.openapi.wm.impl.customFrameDecorations.style.ComponentStyleState import com.intellij.openapi.wm.impl.customFrameDecorations.style.StyleManager -import com.intellij.ui.icons.overrideIconScale import com.intellij.ui.scale.JBUIScale -import com.intellij.ui.scale.ScaleType -import com.intellij.util.IconUtil import com.intellij.util.ui.JBInsets import com.intellij.util.ui.JBUI.Borders import com.intellij.util.ui.JBUI.CurrentTheme @@ -22,12 +19,8 @@ import javax.swing.plaf.basic.BasicButtonUI internal open class CustomFrameTitleButtons(myCloseAction: Action) { companion object { - private val closeIcon = AllIcons.Windows.CloseActive - private val closeHoverIcon = AllIcons.Windows.CloseHover - private val closeInactive = AllIcons.Windows.CloseInactive - - fun create(myCloseAction: Action): CustomFrameTitleButtons { - val darculaTitleButtons = CustomFrameTitleButtons(myCloseAction) + fun create(closeAction: Action): CustomFrameTitleButtons { + val darculaTitleButtons = CustomFrameTitleButtons(closeAction) darculaTitleButtons.createChildren() return darculaTitleButtons } @@ -67,24 +60,24 @@ internal open class CustomFrameTitleButtons(myCloseAction: Action) { val closeStyleBuilder: ComponentStyle.ComponentStyleBuilder = ComponentStyle.ComponentStyleBuilder { isOpaque = false border = Borders.empty() - icon = closeIcon + icon = AllIcons.Windows.CloseActive }.apply { style(ComponentStyleState.HOVERED) { isOpaque = true background = Color(0xe81123) - icon = closeHoverIcon + icon = AllIcons.Windows.CloseHover } style(ComponentStyleState.PRESSED) { isOpaque = true background = Color(0xf1707a) - icon = closeHoverIcon + icon = AllIcons.Windows.CloseHover } } private val activeCloseStyle = closeStyleBuilder.build() private val inactiveCloseStyle = closeStyleBuilder .updateDefault { - icon = closeInactive + icon = AllIcons.Windows.CloseInactive }.build() private val panel = TitleButtonsPanel() @@ -165,41 +158,42 @@ internal open class CustomFrameTitleButtons(myCloseAction: Action) { button.text = null return button } +} - private class TitleButtonsPanel : JPanel(FlowLayout(FlowLayout.LEADING, 0, 0)) { - var isCompactMode = false - set(value) { - field = value - updateScaledPreferredSize() - } - - init { - isOpaque = false +private class TitleButtonsPanel : JPanel(FlowLayout(FlowLayout.LEADING, 0, 0)) { + var isCompactMode = false + set(value) { + field = value + updateScaledPreferredSize() } - fun addComponent(component: JComponent) { - component.setScaledPreferredSize() - add(component, "top") - } + init { + isOpaque = false + } - private fun updateScaledPreferredSize() { - components.forEach { (it as? JComponent)?.setScaledPreferredSize() } - } + fun addComponent(component: JComponent) { + component.setScaledPreferredSize() + add(component, "top") + } - private fun JComponent.setScaledPreferredSize() { - val size = CurrentTheme.TitlePane.buttonPreferredSize().clone() as Dimension - if (isCompactMode) size.height = JBUIScale.scale(30) - preferredSize = Dimension((size.width * UISettings.defFontScale).toInt(), (size.height * UISettings.defFontScale).toInt()) - } + private fun updateScaledPreferredSize() { + components.forEach { (it as? JComponent)?.setScaledPreferredSize() } + } - override fun updateUI() { - super.updateUI() - components?.forEach { component -> - if (component is JComponent) { - component.setScaledPreferredSize() - } + private fun JComponent.setScaledPreferredSize() { + val size = CurrentTheme.TitlePane.buttonPreferredSize().clone() as Dimension + if (isCompactMode) { + size.height = JBUIScale.scale(30) + } + preferredSize = Dimension((size.width * UISettings.defFontScale).toInt(), (size.height * UISettings.defFontScale).toInt()) + } + + override fun updateUI() { + super.updateUI() + components?.forEach { component -> + if (component is JComponent) { + component.setScaledPreferredSize() } } } - } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt index f04372a858a4..041aa8cada7c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt @@ -39,7 +39,7 @@ private const val HEADER_HEIGHT_DFM = 30 private const val HEADER_HEIGHT_COMPACT = 34 private const val HEADER_HEIGHT_NORMAL = 40 -internal abstract class CustomHeader(private val window: Window) : JPanel() { +internal sealed class CustomHeader(private val window: Window) : JPanel() { companion object { val H: Int get() = 12 @@ -49,6 +49,10 @@ internal abstract class CustomHeader(private val window: Window) : JPanel() { val LABEL_BORDER: JBEmptyBorder get() = JBUI.Borders.empty(V, 0) + internal fun createCloseAction(header: CustomHeader): Action { + return CustomFrameAction(name = CommonBundle.getCloseButtonText(), icon = AllIcons.Windows.CloseSmall, action = header::close) + } + private val windowBorderThicknessInPhysicalPx: Int = run { // Windows 10 (tested on 1809) determines the window border size by the main display scaling, rounded down. This value is // calculated once on desktop session start, so it should be okay to store once per IDE session. @@ -56,13 +60,16 @@ internal abstract class CustomHeader(private val window: Window) : JPanel() { floor(scale).toInt() } - @JvmStatic fun enableCustomHeader(w: Window) { JBR.getWindowDecorations()?.let { val bar = it.createCustomTitleBar() bar.height = 1f - if (w is Dialog) it.setCustomTitleBar(w, bar) - else if (w is Frame) it.setCustomTitleBar(w, bar) + if (w is Dialog) { + it.setCustomTitleBar(w, bar) + } + else if (w is Frame) { + it.setCustomTitleBar(w, bar) + } } } } @@ -74,7 +81,7 @@ internal abstract class CustomHeader(private val window: Window) : JPanel() { AppUIUtil.loadSmallApplicationIcon(it) } - protected var myActive = false + protected var isActive = false private var customFrameTopBorder: CustomFrameTopBorder? = null @@ -92,7 +99,7 @@ internal abstract class CustomHeader(private val window: Window) : JPanel() { init { isOpaque = true background = getHeaderBackground() - myActive = window.isActive + isActive = window.isActive windowListener = object : WindowAdapter() { override fun windowActivated(ev: WindowEvent?) { @@ -223,7 +230,7 @@ internal abstract class CustomHeader(private val window: Window) : JPanel() { } private fun setActive(value: Boolean) { - myActive = value + isActive = value updateActive() updateCustomTitleBar() } @@ -231,12 +238,10 @@ internal abstract class CustomHeader(private val window: Window) : JPanel() { protected open fun updateActive() { customFrameTopBorder?.repaintBorder() - background = getHeaderBackground(myActive) + background = getHeaderBackground(isActive) updateWinControlsTheme() } - protected val myCloseAction: Action = CustomFrameAction(CommonBundle.getCloseButtonText(), AllIcons.Windows.CloseSmall) { close() } - protected fun close() { window.dispatchEvent(WindowEvent(window, WindowEvent.WINDOW_CLOSING)) } @@ -268,7 +273,7 @@ internal abstract class CustomHeader(private val window: Window) : JPanel() { } open fun addMenuItems(menu: JPopupMenu) { - val closeMenuItem = menu.add(myCloseAction) + val closeMenuItem = menu.add(createCloseAction(this)) closeMenuItem.font = JBFont.label().deriveFont(Font.BOLD) } @@ -400,15 +405,15 @@ internal abstract class CustomHeader(private val window: Window) : JPanel() { private val shouldDrawTopBorder: Boolean get() { - val drawTopBorderActive = myActive && (colorizationAffectsBorders || UIUtil.isUnderIntelliJLaF()) // omit in Darcula with colorization disabled - val drawTopBorderInactive = !myActive && UIUtil.isUnderIntelliJLaF() + val drawTopBorderActive = isActive && (colorizationAffectsBorders || UIUtil.isUnderIntelliJLaF()) // omit in Darcula with colorization disabled + val drawTopBorderInactive = !isActive && UIUtil.isUnderIntelliJLaF() return drawTopBorderActive || drawTopBorderInactive } override fun paintBorder(c: Component, g: Graphics, x: Int, y: Int, width: Int, height: Int) { val thickness = calculateWindowBorderThicknessInLogicalPx() if (isTopNeeded() && shouldDrawTopBorder) { - g.color = if (myActive) activeColor else inactiveColor + g.color = if (isActive) activeColor else inactiveColor LinePainter2D.paint(g as Graphics2D, x.toDouble(), y.toDouble(), width.toDouble(), y.toDouble(), LinePainter2D.StrokeType.INSIDE, thickness) } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DefaultFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DefaultFrameHeader.kt index 2bbfb4267de0..a559a0b5a477 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DefaultFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DefaultFrameHeader.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations.header import com.intellij.openapi.wm.impl.customFrameDecorations.header.titleLabel.CustomDecorationTitle @@ -29,7 +29,7 @@ internal class DefaultFrameHeader(frame: JFrame, isForDockContainerProvider: Boo } override fun updateActive() { - customDecorationTitle.setActive(myActive) + customDecorationTitle.setActive(isActive) super.updateActive() } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt index fb9ca3a2d8a8..00b808218a26 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations.header import com.intellij.openapi.util.NlsContexts @@ -17,70 +17,80 @@ import javax.swing.JLabel import javax.swing.UIManager internal class DialogHeader(val window: Window) : CustomHeader(window) { - private val titleLabel = JLabel().apply { - border = LABEL_BORDER - } - private val titleChangeListener = PropertyChangeListener{ - titleLabel.text = getTitle() + private val titleLabel = JLabel().apply { + border = LABEL_BORDER + } + private val titleChangeListener = PropertyChangeListener { + titleLabel.text = getTitle() + } + + init { + layout = GridBagLayout() + titleLabel.text = getTitle() + + productIcon.border = JBUI.Borders.empty(0, H, 0, H) + + val gb = GridBag().setDefaultFill(GridBagConstraints.VERTICAL).setDefaultAnchor(GridBagConstraints.WEST) + add(productIcon, gb.next()) + add(titleLabel, gb.next().fillCell().weightx(1.0)) + buttonPanes?.let { add(it.getView(), gb.next().anchor(GridBagConstraints.EAST)) } + } + + private val dragListener = object : MouseAdapter() { //passing events to OS handler to make it draggable + override fun mouseDragged(e: MouseEvent?) { + customTitleBar?.forceHitTest(false) } - init { - layout = GridBagLayout() - titleLabel.text = getTitle() - - productIcon.border = JBUI.Borders.empty(0, H, 0, H) - - val gb = GridBag().setDefaultFill(GridBagConstraints.VERTICAL).setDefaultAnchor(GridBagConstraints.WEST) - add(productIcon, gb.next()) - add(titleLabel, gb.next().fillCell().weightx(1.0)) - buttonPanes?.let { add(it.getView(), gb.next().anchor(GridBagConstraints.EAST)) } + override fun mouseClicked(e: MouseEvent?) { + customTitleBar?.forceHitTest(false) } - private val dragListener = object : MouseAdapter() { //passing events to OS handler to make it draggable - override fun mouseDragged(e: MouseEvent?) { customTitleBar?.forceHitTest(false) } - override fun mouseClicked(e: MouseEvent?) { customTitleBar?.forceHitTest(false) } - override fun mouseMoved(e: MouseEvent?) { customTitleBar?.forceHitTest(false) } + override fun mouseMoved(e: MouseEvent?) { + customTitleBar?.forceHitTest(false) } + } - override fun installListeners() { - super.installListeners() - window.addPropertyChangeListener("title", titleChangeListener) - addMouseListener(dragListener) - addMouseMotionListener(dragListener) - } + override fun installListeners() { + super.installListeners() + window.addPropertyChangeListener("title", titleChangeListener) + addMouseListener(dragListener) + addMouseMotionListener(dragListener) + } - override fun uninstallListeners() { - super.uninstallListeners() - window.removePropertyChangeListener(titleChangeListener) - removeMouseListener(dragListener) - removeMouseMotionListener(dragListener) - } + override fun uninstallListeners() { + super.uninstallListeners() + window.removePropertyChangeListener(titleChangeListener) + removeMouseListener(dragListener) + removeMouseMotionListener(dragListener) + } - override fun updateActive() { - titleLabel.foreground = if (myActive) UIManager.getColor("Panel.foreground") else UIManager.getColor("Label.disabledForeground") - super.updateActive() - } + override fun updateActive() { + titleLabel.foreground = if (isActive) UIManager.getColor("Panel.foreground") else UIManager.getColor("Label.disabledForeground") + super.updateActive() + } - override fun windowStateChanged() { - super.windowStateChanged() - titleLabel.text = getTitle() - } + override fun windowStateChanged() { + super.windowStateChanged() + titleLabel.text = getTitle() + } - override fun addNotify() { - super.addNotify() - titleLabel.text = getTitle() - } + override fun addNotify() { + super.addNotify() + titleLabel.text = getTitle() + } - @NlsContexts.DialogTitle - private fun getTitle(): String? { - when (window) { - is Dialog -> return window.title - else -> return "" - } + @NlsContexts.DialogTitle + private fun getTitle(): String? { + when (window) { + is Dialog -> return window.title + else -> return "" } + } override fun createButtonsPane(): CustomFrameTitleButtons? { - if (IdeRootPane.hideNativeLinuxTitle) CustomFrameTitleButtons.create(myCloseAction) + if (IdeRootPane.hideNativeLinuxTitle) { + CustomFrameTitleButtons.create(createCloseAction(this)) + } return null } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt index 58612eaf27d4..2959c2e1a44c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations.header import com.intellij.CommonBundle @@ -30,6 +30,9 @@ internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(fram private var windowStateListener: WindowStateListener protected var myState = 0 + @Suppress("LeakingThis") + private val closeAction = createCloseAction(this) + init { windowStateListener = object : WindowAdapter() { override fun windowStateChanged(e: java.awt.event.WindowEvent?) { @@ -82,7 +85,7 @@ internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(fram restoreAction.isEnabled = false } iconifyAction.isEnabled = true - myCloseAction.isEnabled = true + closeAction.isEnabled = true buttonPanes?.updateVisibility() updateCustomTitleBar() @@ -97,13 +100,13 @@ internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(fram menu.add(JSeparator()) - val closeMenuItem = menu.add(myCloseAction) + val closeMenuItem = menu.add(closeAction) closeMenuItem.font = JBFont.label().deriveFont(Font.BOLD) } override fun createButtonsPane(): CustomFrameTitleButtons? { if (IdeRootPane.hideNativeLinuxTitle) - return ResizableCustomFrameTitleButtons.create(myCloseAction, restoreAction, iconifyAction, maximizeAction) + return ResizableCustomFrameTitleButtons.create(closeAction, restoreAction, iconifyAction, maximizeAction) return null } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt index f66f46aab018..a32e0fe30fa3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt @@ -43,7 +43,7 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, private var currentComponent: JComponent - private val updateRequests = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) + private val updateRequests = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) private var lastHeight = DEFAULT_HEADER_HEIGHT @@ -200,7 +200,7 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, override fun updateActive() { super.updateActive() - toolbar.background = getHeaderBackground(myActive) + toolbar.background = getHeaderBackground(isActive) } override fun uiSettingsChanged(uiSettings: UISettings) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MenuFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MenuFrameHeader.kt index 7573b72aa5b8..acca0c94e913 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MenuFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MenuFrameHeader.kt @@ -66,7 +66,7 @@ internal class MenuFrameHeader(frame: JFrame, override fun updateActive() { super.updateActive() - headerTitle.setActive(myActive) + headerTitle.setActive(isActive) } override fun installListeners() { From 91886d6c920a0eb644131c4a27dee43b70f3620e Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 18:34:19 +0200 Subject: [PATCH 127/226] convert CustomFrameTopBorder from inner to static class GitOrigin-RevId: ccc4710850531425a3869636a40a134ea3e3e812 --- .../header/CustomHeader.kt | 332 +++++++++--------- .../header/DialogHeader.kt | 2 +- 2 files changed, 172 insertions(+), 162 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt index 041aa8cada7c..7ce2471b605f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt @@ -6,12 +6,15 @@ import com.intellij.accessibility.AccessibilityUtils import com.intellij.icons.AllIcons import com.intellij.ide.ui.UISettings import com.intellij.ide.ui.customization.CustomActionsSchema +import com.intellij.internal.inspector.ConfigureCustomSizeAction.CustomSizeModel.height +import com.intellij.internal.inspector.ConfigureCustomSizeAction.CustomSizeModel.width import com.intellij.openapi.MnemonicHelper import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.ui.JBPopupMenu import com.intellij.openapi.util.NlsActions import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.util.SystemInfoRt import com.intellij.openapi.wm.impl.IdeRootPane import com.intellij.openapi.wm.impl.customFrameDecorations.CustomFrameTitleButtons import com.intellij.openapi.wm.impl.headertoolbar.computeMainActionGroups @@ -39,7 +42,14 @@ private const val HEADER_HEIGHT_DFM = 30 private const val HEADER_HEIGHT_COMPACT = 34 private const val HEADER_HEIGHT_NORMAL = 40 -internal sealed class CustomHeader(private val window: Window) : JPanel() { +private val windowBorderThicknessInPhysicalPx: Int = run { + // Windows 10 (tested on 1809) determines the window border size by the main display scaling, rounded down. This value is + // calculated once on desktop session start, so it should be okay to store once per IDE session. + val scale = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration.defaultTransform.scaleY + floor(scale).toInt() +} + +internal sealed class CustomHeader(@JvmField internal val window: Window) : JPanel() { companion object { val H: Int get() = 12 @@ -53,13 +63,6 @@ internal sealed class CustomHeader(private val window: Window) : JPanel() { return CustomFrameAction(name = CommonBundle.getCloseButtonText(), icon = AllIcons.Windows.CloseSmall, action = header::close) } - private val windowBorderThicknessInPhysicalPx: Int = run { - // Windows 10 (tested on 1809) determines the window border size by the main display scaling, rounded down. This value is - // calculated once on desktop session start, so it should be okay to store once per IDE session. - val scale = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration.defaultTransform.scaleY - floor(scale).toInt() - } - fun enableCustomHeader(w: Window) { JBR.getWindowDecorations()?.let { val bar = it.createCustomTitleBar() @@ -74,14 +77,32 @@ internal sealed class CustomHeader(private val window: Window) : JPanel() { } } - private var windowListener: WindowAdapter - private val componentListener: ComponentListener + private val windowListener = object : WindowAdapter() { + override fun windowActivated(ev: WindowEvent?) { + setActive(true) + } + + override fun windowDeactivated(ev: WindowEvent?) { + setActive(false) + } + + override fun windowStateChanged(e: WindowEvent?) { + windowStateChanged() + } + } + + private val componentListener = object : ComponentAdapter() { + override fun componentResized(e: ComponentEvent?) { + SwingUtilities.invokeLater { updateCustomTitleBar() } + } + } private val iconProvider = ScaleContextCache { AppUIUtil.loadSmallApplicationIcon(it) } - protected var isActive = false + @JvmField + internal var isActive = false private var customFrameTopBorder: CustomFrameTopBorder? = null @@ -101,26 +122,6 @@ internal sealed class CustomHeader(private val window: Window) : JPanel() { background = getHeaderBackground() isActive = window.isActive - windowListener = object : WindowAdapter() { - override fun windowActivated(ev: WindowEvent?) { - setActive(true) - } - - override fun windowDeactivated(ev: WindowEvent?) { - setActive(false) - } - - override fun windowStateChanged(e: WindowEvent?) { - windowStateChanged() - } - } - - componentListener = object : ComponentAdapter() { - override fun componentResized(e: ComponentEvent?) { - SwingUtilities.invokeLater { updateCustomTitleBar() } - } - } - setCustomFrameTopBorder() customTitleBar = JBR.getWindowDecorations()?.createCustomTitleBar() @@ -157,7 +158,7 @@ internal sealed class CustomHeader(private val window: Window) : JPanel() { protected open fun getHeaderBackground(active: Boolean = true) = JBUI.CurrentTheme.CustomFrameDecorations.titlePaneBackground(active) protected fun setCustomFrameTopBorder(isTopNeeded: () -> Boolean = { true }, isBottomNeeded: () -> Boolean = { false }) { - customFrameTopBorder = CustomFrameTopBorder(isTopNeeded = isTopNeeded, isBottomNeeded = isBottomNeeded) + customFrameTopBorder = CustomFrameTopBorder(isTopNeeded = isTopNeeded, isBottomNeeded = isBottomNeeded, header = this) border = customFrameTopBorder } @@ -290,152 +291,161 @@ internal sealed class CustomHeader(private val window: Window) : JPanel() { return AccessibilityUtils.GROUPED_ELEMENTS } } +} - inner class CustomFrameTopBorder(val isTopNeeded: () -> Boolean = { true }, val isBottomNeeded: () -> Boolean = { false }) : Border { - // Bottom border is a line between a window title/main menu area and the frame content. - private val bottomBorderWidthLogicalPx = JBUI.scale(1) +private class CustomFrameTopBorder(@JvmField val isTopNeeded: () -> Boolean = { true }, + @JvmField val isBottomNeeded: () -> Boolean = { false }, + @JvmField val header: CustomHeader) : Border { + // The bottom border is a line between a window title/main menu area and the frame content. + private val bottomBorderWidthLogicalPx = JBUI.scale(1) - // In reality, Windows uses #262626 with alpha-blending with alpha=0.34, but we have no (easy) way of doing the same, so let's just - // use the value on white background (since it is most noticeable on white). - // - // Unfortunately, DWM doesn't offer an API to determine this value, so it has to be hardcoded here. - private val defaultActiveBorder = Color(0x707070) - private val inactiveColor = Color(0xaaaaaa) + // In reality, Windows uses #262626 with alpha-blending with alpha=0.34, but we have no (easy) way of doing the same, so let's just + // use the value on a white background (since it is most noticeable on white). + // + // Unfortunately, DWM doesn't offer an API to determine this value, so it has to be hardcoded here. + private val defaultActiveBorder = Color(0x707070) + private val inactiveColor = Color(0xaaaaaa) - private val menuBarBorderColor: Color = JBColor.namedColor("MenuBar.borderColor", JBColor(Gray.xCD, Gray.x51)) - private var colorizationAffectsBorders: Boolean = false - private var activeColor: Color = defaultActiveBorder + private val menuBarBorderColor = JBColor.namedColor("MenuBar.borderColor", JBColor(Gray.xCD, Gray.x51)) + private var colorizationAffectsBorders: Boolean = false + private var activeColor = defaultActiveBorder - private fun calculateAffectsBorders(): Boolean { + private fun calculateAffectsBorders(): Boolean { + if (SystemInfoRt.isWindows) { val windowsBuild = SystemInfo.getWinBuildNumber() ?: 0 - if (windowsBuild < 17763) return true // should always be active on older versions on Windows - return Toolkit.getDefaultToolkit().getDesktopProperty("win.dwm.colorizationColor.affects.borders") as Boolean? ?: true + if (windowsBuild < 17763) { + // should always be active on older versions on Windows + return true + } + } + return Toolkit.getDefaultToolkit().getDesktopProperty("win.dwm.colorizationColor.affects.borders") as Boolean? ?: true + } + + private fun calculateActiveBorderColor(): Color { + if (!colorizationAffectsBorders) { + return defaultActiveBorder } - private fun calculateActiveBorderColor(): Color { - if (!colorizationAffectsBorders) - return defaultActiveBorder + try { + val toolkit = Toolkit.getDefaultToolkit() + val colorizationColor = toolkit.getDesktopProperty("win.dwm.colorizationColor") as Color? + if (colorizationColor != null) { + // The border color is a result of an alpha blend of colorization color and #D9D9D9 with the alpha value set by the + // colorization color balance. + var colorizationColorBalance = toolkit.getDesktopProperty("win.dwm.colorizationColorBalance") as Int? + if (colorizationColorBalance != null) { + if (colorizationColorBalance > 100) { + // May be caused by custom Windows themes installed. + colorizationColorBalance = 100 + } - try { - val toolkit = Toolkit.getDefaultToolkit() - val colorizationColor = toolkit.getDesktopProperty("win.dwm.colorizationColor") as Color? - if (colorizationColor != null) { - // The border color is a result of an alpha blend of colorization color and #D9D9D9 with the alpha value set by the - // colorization color balance. - var colorizationColorBalance = toolkit.getDesktopProperty("win.dwm.colorizationColorBalance") as Int? - if (colorizationColorBalance != null) { - if (colorizationColorBalance > 100) { - // May be caused by custom Windows themes installed. - colorizationColorBalance = 100 - } + // If the desktop setting "Automatically pick an accent color from my background" is active, then the border + // color should be the same as the colorization color read from the registry. To detect that setting, we use the + // fact that colorization color balance is set to 0xfffffff3 when the setting is active. + if (colorizationColorBalance < 0) + colorizationColorBalance = 100 - // If the desktop setting "Automatically pick an accent color from my background" is active, then the border - // color should be the same as the colorization color read from the registry. To detect that setting, we use the - // fact that colorization color balance is set to 0xfffffff3 when the setting is active. - if (colorizationColorBalance < 0) - colorizationColorBalance = 100 - - return when (colorizationColorBalance) { - 0 -> Color(0xD9D9D9) - 100 -> colorizationColor - else -> { - val alpha = colorizationColorBalance / 100.0f - val remainder = 1 - alpha - val r = (colorizationColor.red * alpha + 0xD9 * remainder).roundToInt() - val g = (colorizationColor.green * alpha + 0xD9 * remainder).roundToInt() - val b = (colorizationColor.blue * alpha + 0xD9 * remainder).roundToInt() - Color(r, g, b) - } + return when (colorizationColorBalance) { + 0 -> Color(0xD9D9D9) + 100 -> colorizationColor + else -> { + val alpha = colorizationColorBalance / 100.0f + val remainder = 1 - alpha + val r = (colorizationColor.red * alpha + 0xD9 * remainder).roundToInt() + val g = (colorizationColor.green * alpha + 0xD9 * remainder).roundToInt() + val b = (colorizationColor.blue * alpha + 0xD9 * remainder).roundToInt() + Color(r, g, b) } } } - - return colorizationColor - ?: toolkit.getDesktopProperty("win.frame.activeBorderColor") as Color? - ?: menuBarBorderColor - } - catch (t: Throwable) { - // Should be as fail-safe as possible, since any errors during border coloring could lead to an IDE being broken. - logger().error(t) - return defaultActiveBorder - } - } - - private fun calculateWindowBorderThicknessInLogicalPx(): Double { - return windowBorderThicknessInPhysicalPx.toDouble() / JBUIScale.sysScale(window) - } - - private val listeners = mutableListOf>() - private inline fun listenForPropertyChanges(vararg propertyNames: String, crossinline action: () -> Unit) { - val toolkit = Toolkit.getDefaultToolkit() - val listener = PropertyChangeListener { action() } - for (property in propertyNames) { - toolkit.addPropertyChangeListener(property, listener) - listeners.add(property to listener) - } - } - - fun addNotify() { - colorizationAffectsBorders = calculateAffectsBorders() - listenForPropertyChanges("win.dwm.colorizationColor.affects.borders") { - colorizationAffectsBorders = calculateAffectsBorders() - activeColor = calculateActiveBorderColor() // active border color is dependent on whether colorization affects borders or not } - activeColor = calculateActiveBorderColor() - listenForPropertyChanges("win.dwm.colorizationColor", "win.dwm.colorizationColorBalance", "win.frame.activeBorderColor") { - activeColor = calculateActiveBorderColor() - } + return colorizationColor + ?: toolkit.getDesktopProperty("win.frame.activeBorderColor") as Color? + ?: menuBarBorderColor } - - fun removeNotify() { - val toolkit = Toolkit.getDefaultToolkit() - for ((propertyName, listener) in listeners) - toolkit.removePropertyChangeListener(propertyName, listener) - listeners.clear() + catch (t: Throwable) { + // Should be as fail-safe as possible, since any errors during border coloring could lead to an IDE being broken. + logger().error(t) + return defaultActiveBorder } - - fun repaintBorder() { - val borderInsets = getBorderInsets(this@CustomHeader) - - val thickness = calculateWindowBorderThicknessInLogicalPx() - repaint(0, 0, width, ceil(thickness).toInt()) - repaint(0, height - borderInsets.bottom, width, borderInsets.bottom) - } - - private val shouldDrawTopBorder: Boolean - get() { - val drawTopBorderActive = isActive && (colorizationAffectsBorders || UIUtil.isUnderIntelliJLaF()) // omit in Darcula with colorization disabled - val drawTopBorderInactive = !isActive && UIUtil.isUnderIntelliJLaF() - return drawTopBorderActive || drawTopBorderInactive - } - - override fun paintBorder(c: Component, g: Graphics, x: Int, y: Int, width: Int, height: Int) { - val thickness = calculateWindowBorderThicknessInLogicalPx() - if (isTopNeeded() && shouldDrawTopBorder) { - g.color = if (isActive) activeColor else inactiveColor - LinePainter2D.paint(g as Graphics2D, x.toDouble(), y.toDouble(), width.toDouble(), y.toDouble(), LinePainter2D.StrokeType.INSIDE, - thickness) - } - - if (isBottomNeeded()) { - g.color = menuBarBorderColor - val y1 = y + height - bottomBorderWidthLogicalPx - LinePainter2D.paint(g as Graphics2D, x.toDouble(), y1.toDouble(), width.toDouble(), y1.toDouble()) - } - } - - override fun getBorderInsets(c: Component): Insets { - val thickness = calculateWindowBorderThicknessInLogicalPx() - val top = if (isTopNeeded() && (colorizationAffectsBorders || StartupUiUtil.isUnderIntelliJLaF())) ceil(thickness).toInt() else 0 - val bottom = if (isBottomNeeded()) bottomBorderWidthLogicalPx else 0 - val left = customTitleBar?.leftInset?.toInt() ?: 0 - val right = customTitleBar?.rightInset?.toInt() ?: 0 - return Insets(top, left, bottom, right) - } - - override fun isBorderOpaque(): Boolean = true } + + private fun calculateWindowBorderThicknessInLogicalPx(): Double { + return windowBorderThicknessInPhysicalPx.toDouble() / JBUIScale.sysScale(header.window) + } + + private val listeners = mutableListOf>() + private inline fun listenForPropertyChanges(vararg propertyNames: String, crossinline action: () -> Unit) { + val toolkit = Toolkit.getDefaultToolkit() + val listener = PropertyChangeListener { action() } + for (property in propertyNames) { + toolkit.addPropertyChangeListener(property, listener) + listeners.add(property to listener) + } + } + + fun addNotify() { + colorizationAffectsBorders = calculateAffectsBorders() + listenForPropertyChanges("win.dwm.colorizationColor.affects.borders") { + colorizationAffectsBorders = calculateAffectsBorders() + activeColor = calculateActiveBorderColor() // active border color is dependent on whether colorization affects borders or not + } + + activeColor = calculateActiveBorderColor() + listenForPropertyChanges("win.dwm.colorizationColor", "win.dwm.colorizationColorBalance", "win.frame.activeBorderColor") { + activeColor = calculateActiveBorderColor() + } + } + + fun removeNotify() { + val toolkit = Toolkit.getDefaultToolkit() + for ((propertyName, listener) in listeners) { + toolkit.removePropertyChangeListener(propertyName, listener) + } + listeners.clear() + } + + fun repaintBorder() { + val borderInsets = getBorderInsets(header) + + val thickness = calculateWindowBorderThicknessInLogicalPx() + header.repaint(0, 0, width, ceil(thickness).toInt()) + header.repaint(0, height - borderInsets.bottom, width, borderInsets.bottom) + } + + private val shouldDrawTopBorder: Boolean + get() { + val drawTopBorderActive = header.isActive && (colorizationAffectsBorders || UIUtil.isUnderIntelliJLaF()) // omit in Darcula with colorization disabled + val drawTopBorderInactive = !header.isActive && UIUtil.isUnderIntelliJLaF() + return drawTopBorderActive || drawTopBorderInactive + } + + override fun paintBorder(c: Component, g: Graphics, x: Int, y: Int, width: Int, height: Int) { + val thickness = calculateWindowBorderThicknessInLogicalPx() + if (isTopNeeded() && shouldDrawTopBorder) { + g.color = if (header.isActive) activeColor else inactiveColor + LinePainter2D.paint(g as Graphics2D, x.toDouble(), y.toDouble(), width.toDouble(), y.toDouble(), LinePainter2D.StrokeType.INSIDE, + thickness) + } + + if (isBottomNeeded()) { + g.color = menuBarBorderColor + val y1 = y + height - bottomBorderWidthLogicalPx + LinePainter2D.paint(g as Graphics2D, x.toDouble(), y1.toDouble(), width.toDouble(), y1.toDouble()) + } + } + + override fun getBorderInsets(c: Component): Insets { + val thickness = calculateWindowBorderThicknessInLogicalPx() + val top = if (isTopNeeded() && (colorizationAffectsBorders || StartupUiUtil.isUnderIntelliJLaF())) ceil(thickness).toInt() else 0 + val bottom = if (isBottomNeeded()) bottomBorderWidthLogicalPx else 0 + val left = header.customTitleBar?.leftInset?.toInt() ?: 0 + val right = header.customTitleBar?.rightInset?.toInt() ?: 0 + return Insets(top, left, bottom, right) + } + + override fun isBorderOpaque(): Boolean = true } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt index 00b808218a26..0176ee6294d9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt @@ -16,7 +16,7 @@ import java.beans.PropertyChangeListener import javax.swing.JLabel import javax.swing.UIManager -internal class DialogHeader(val window: Window) : CustomHeader(window) { +internal class DialogHeader(window: Window) : CustomHeader(window) { private val titleLabel = JLabel().apply { border = LABEL_BORDER } From f6a3921f3f1a2e21c5b5d131c31c32e860990857 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 18:43:13 +0200 Subject: [PATCH 128/226] refactor - CustomFrameTitleButtons not used by CustomHeader base class GitOrigin-RevId: 9d1baafe5455ad592331bdd164dedcdc695b57f2 --- .../ResizableCustomFrameTitleButtons.kt | 24 +++++++------- .../header/CustomHeader.kt | 32 ++++++++----------- .../header/DialogHeader.kt | 9 ++---- .../header/FrameHeader.kt | 10 ++++-- 4 files changed, 35 insertions(+), 40 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/ResizableCustomFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/ResizableCustomFrameTitleButtons.kt index 2b5aee6c50fd..5dd3606a582e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/ResizableCustomFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/ResizableCustomFrameTitleButtons.kt @@ -1,17 +1,16 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations import com.intellij.icons.AllIcons import com.intellij.openapi.wm.impl.customFrameDecorations.style.StyleManager import javax.swing.Action -import javax.swing.JButton internal class ResizableCustomFrameTitleButtons(closeAction: Action, private val myRestoreAction: Action, private val myIconifyAction: Action, private val myMaximizeAction: Action ) : CustomFrameTitleButtons(closeAction) { - companion object{ + companion object { private val restoreIcon = AllIcons.Windows.Restore private val restoreInactiveIcon = AllIcons.Windows.RestoreInactive @@ -21,16 +20,19 @@ internal class ResizableCustomFrameTitleButtons(closeAction: Action, private val minimizeIcon = AllIcons.Windows.Minimize private val minimizeInactiveIcon = AllIcons.Windows.MinimizeInactive - fun create(myCloseAction: Action, myRestoreAction: Action, myIconifyAction: Action, myMaximizeAction: Action) : ResizableCustomFrameTitleButtons { + fun create(myCloseAction: Action, + myRestoreAction: Action, + myIconifyAction: Action, + myMaximizeAction: Action): ResizableCustomFrameTitleButtons { val darculaTitleButtons = ResizableCustomFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) darculaTitleButtons.createChildren() return darculaTitleButtons } } - val restoreButton: JButton = createButton("Restore", myRestoreAction) - val maximizeButton: JButton = createButton("Maximize", myMaximizeAction) - val minimizeButton: JButton = createButton("Iconify", myIconifyAction) + private val restoreButton = createButton("Restore", myRestoreAction) + private val maximizeButton = createButton("Maximize", myMaximizeAction) + private val minimizeButton = createButton("Iconify", myIconifyAction) override fun fillButtonPane() { super.fillButtonPane() @@ -48,10 +50,8 @@ internal class ResizableCustomFrameTitleButtons(closeAction: Action, override fun updateStyles() { super.updateStyles() - StyleManager.applyStyle(restoreButton, getStyle(if(isSelected) restoreIcon else restoreInactiveIcon, restoreIcon)) - StyleManager.applyStyle(maximizeButton, getStyle(if(isSelected) maximizeIcon else maximizeInactiveIcon, maximizeIcon)) - StyleManager.applyStyle(minimizeButton, getStyle(if(isSelected) minimizeIcon else minimizeInactiveIcon, minimizeIcon)) + StyleManager.applyStyle(restoreButton, getStyle(if (isSelected) restoreIcon else restoreInactiveIcon, restoreIcon)) + StyleManager.applyStyle(maximizeButton, getStyle(if (isSelected) maximizeIcon else maximizeInactiveIcon, maximizeIcon)) + StyleManager.applyStyle(minimizeButton, getStyle(if (isSelected) minimizeIcon else minimizeInactiveIcon, minimizeIcon)) } - - } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt index 7ce2471b605f..ed0a7c05e02a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt @@ -16,7 +16,6 @@ import com.intellij.openapi.util.NlsActions import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.SystemInfoRt import com.intellij.openapi.wm.impl.IdeRootPane -import com.intellij.openapi.wm.impl.customFrameDecorations.CustomFrameTitleButtons import com.intellij.openapi.wm.impl.headertoolbar.computeMainActionGroups import com.intellij.ui.* import com.intellij.ui.paint.LinePainter2D @@ -113,10 +112,6 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan createProductIcon() } - protected val buttonPanes: CustomFrameTitleButtons? by lazy { - createButtonsPane() - } - init { isOpaque = true background = getHeaderBackground() @@ -138,21 +133,22 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan return } - preferredSize = preferredSize.apply { - height = JBUI.scale( - when { - (rootPane as? IdeRootPane)?.isCompactHeader(mainToolbarActionSupplier) == true -> HEADER_HEIGHT_DFM - UISettings.getInstance().compactMode -> HEADER_HEIGHT_COMPACT - else -> HEADER_HEIGHT_NORMAL - } - ) - } + val size = preferredSize + size.height = JBUI.scale( + when { + (rootPane as? IdeRootPane)?.isCompactHeader(mainToolbarActionSupplier) == true -> HEADER_HEIGHT_DFM + UISettings.getInstance().compactMode -> HEADER_HEIGHT_COMPACT + else -> HEADER_HEIGHT_NORMAL + } + ) + preferredSize = size } private fun updateWinControlsTheme() { - customTitleBar?.putProperty("controls.dark", ColorUtil.isDark(background)) - customTitleBar?.putProperty("controls.foreground.normal", UIManager.getColor("WindowControls.foreground")) - customTitleBar?.putProperty("controls.foreground.inactive", UIManager.getColor("WindowControls.inactiveForeground")) + val customTitleBar = customTitleBar ?: return + customTitleBar.putProperty("controls.dark", ColorUtil.isDark(background)) + customTitleBar.putProperty("controls.foreground.normal", UIManager.getColor("WindowControls.foreground")) + customTitleBar.putProperty("controls.foreground.inactive", UIManager.getColor("WindowControls.inactiveForeground")) } protected open fun getHeaderBackground(active: Boolean = true) = JBUI.CurrentTheme.CustomFrameDecorations.titlePaneBackground(active) @@ -162,8 +158,6 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan border = customFrameTopBorder } - open fun createButtonsPane(): CustomFrameTitleButtons? = null - open fun windowStateChanged() { updateCustomTitleBar() } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt index 0176ee6294d9..1e34b8659250 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt @@ -33,7 +33,7 @@ internal class DialogHeader(window: Window) : CustomHeader(window) { val gb = GridBag().setDefaultFill(GridBagConstraints.VERTICAL).setDefaultAnchor(GridBagConstraints.WEST) add(productIcon, gb.next()) add(titleLabel, gb.next().fillCell().weightx(1.0)) - buttonPanes?.let { add(it.getView(), gb.next().anchor(GridBagConstraints.EAST)) } + createButtonsPane()?.let { add(it.getView(), gb.next().anchor(GridBagConstraints.EAST)) } } private val dragListener = object : MouseAdapter() { //passing events to OS handler to make it draggable @@ -87,10 +87,7 @@ internal class DialogHeader(window: Window) : CustomHeader(window) { } } - override fun createButtonsPane(): CustomFrameTitleButtons? { - if (IdeRootPane.hideNativeLinuxTitle) { - CustomFrameTitleButtons.create(createCloseAction(this)) - } - return null + private fun createButtonsPane(): CustomFrameTitleButtons? { + return if (IdeRootPane.hideNativeLinuxTitle) CustomFrameTitleButtons.create(createCloseAction(this)) else null } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt index 2959c2e1a44c..6c788e400689 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt @@ -33,6 +33,10 @@ internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(fram @Suppress("LeakingThis") private val closeAction = createCloseAction(this) + protected val buttonPanes: CustomFrameTitleButtons? by lazy { + createButtonsPane() + } + init { windowStateListener = object : WindowAdapter() { override fun windowStateChanged(e: java.awt.event.WindowEvent?) { @@ -104,10 +108,10 @@ internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(fram closeMenuItem.font = JBFont.label().deriveFont(Font.BOLD) } - override fun createButtonsPane(): CustomFrameTitleButtons? { - if (IdeRootPane.hideNativeLinuxTitle) + private fun createButtonsPane(): CustomFrameTitleButtons? { + if (IdeRootPane.hideNativeLinuxTitle) { return ResizableCustomFrameTitleButtons.create(closeAction, restoreAction, iconifyAction, maximizeAction) - + } return null } } \ No newline at end of file From e9d5ff4cf791b565bec8712700d4cef4d66390ce Mon Sep 17 00:00:00 2001 From: Ruslan Cheremin Date: Sat, 1 Jul 2023 18:44:16 +0200 Subject: [PATCH 129/226] [core] IDEA-319737: more diagnostics to VFSHealthChecker + enabled orphan records search (previously apt branch was unreachable due to a bug) + orphans check is disabled by default for regular health-check, but enabled if the check is explicitly invoked via apt Action GitOrigin-RevId: 4475288269cc8f29e7840e016409250a9e840a12 --- .../newvfs/persistent/CheckVFSHealthAction.kt | 2 +- .../vfs/newvfs/persistent/VFSHealthChecker.kt | 93 ++++++++++++++----- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt index 8abb998237f6..0e0ba105d807 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt @@ -31,7 +31,7 @@ internal class CheckVFSHealthAction : AnAction() { ActionsBundle.message("action.CheckVfsSanity.progress"), TaskCancellation.nonCancellable()) { val checker = VFSHealthChecker(FSRecords.implOrFail(), FSRecords.LOG) - checker.checkHealth() + checker.checkHealth(checkForOrphanRecords = true) } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt index 72bcb2e68aa4..18ef4643356f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt @@ -112,7 +112,7 @@ class VFSHealthCheckServiceStarter : ApplicationInitializedListener { } val checker = VFSHealthChecker(fsRecordsImpl, LOG) val checkHealthReport = try { - checker.checkHealth() + checker.checkHealth(CHECK_ORPHAN_RECORDS) } catch (e: AlreadyDisposedException) { return @@ -159,10 +159,12 @@ class VFSHealthCheckServiceStarter : ApplicationInitializedListener { class VFSHealthChecker(private val impl: FSRecordsImpl, private val log: Logger = LOG) { - fun checkHealth(): VFSHealthCheckReport { + constructor() : this(FSRecords.implOrFail(), FSRecords.LOG) + + fun checkHealth(checkForOrphanRecords: Boolean = CHECK_ORPHAN_RECORDS): VFSHealthCheckReport { log.info("Checking VFS started") val startedAtNs = System.nanoTime() - val fileRecordsReport = verifyFileRecords() + val fileRecordsReport = verifyFileRecords(checkForOrphanRecords) val rootsReport = verifyRoots() val namesEnumeratorReport = verifyNamesEnumerator() val contentEnumeratorReport = verifyContentEnumerator() @@ -178,7 +180,7 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, return vfsHealthCheckReport } - private fun verifyFileRecords(): VFSHealthCheckReport.FileRecordsReport { + private fun verifyFileRecords(checkForOrphanRecords: Boolean): VFSHealthCheckReport.FileRecordsReport { val connection = impl.connection() val fileRecords = connection.records val namesEnumerator = connection.names @@ -246,21 +248,34 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, } } //else: it is ok, contentId _could_ be NULL_ID - if (parentId == DataEnumeratorEx.NULL_ID) { + if (parentId == FSRecords.NULL_FILE_ID) { if (!allRoots.contains(fileId)) { nullParents++ log.info("file[#$fileId]{$fileName}: not in ROOTS, but parentId is not set (NULL_ID) -> non-ROOTS must have parents") } } else { - if (CHECK_ORPHAN_RECORDS) { - if (BitUtil.isSet(flags, CHILDREN_CACHED)) { - val childrenOfParent = impl.listIds(parentId) - if (childrenOfParent.indexOf(fileId) < 0) { - inconsistentParentChildRelationships++ //MAYBE RC: dedicated counter? - log.info("file[#$fileId]{$fileName}: record is orphan, .parent.children(first 64: ${ - childrenOfParent.take(64) - }...) doesn't contain it!") + val parentFlags = fileRecords.getFlags(parentId) + val parentIsDirectory = BitUtil.isSet(parentFlags, IS_DIRECTORY) + if (!parentIsDirectory) { + inconsistentParentChildRelationships++ + log.info("file[#$fileId]{$fileName}: parent[#$parentId] is !directory (flags: ${Integer.toBinaryString(parentFlags)}") + } + + if (checkForOrphanRecords) { + if (BitUtil.isSet(parentFlags, CHILDREN_CACHED)) { + try { + //MAYBE RC: use .listIdsUnchecked() method -- to not force VFS rebuild? + val childrenOfParent = impl.listIds(parentId) + if (childrenOfParent.indexOf(fileId) < 0) { + inconsistentParentChildRelationships++ //MAYBE RC: dedicated counter? + log.info("file[#$fileId]{$fileName}: record is orphan, " + + ".parent.children(first 64: ${childrenOfParent.take(64)}...) doesn't contain it!") + } + } + catch (e: Throwable) { + generalErrors++ + log.info("file[#$fileId]{$fileName}.parent[#$parentId]: error accessing children", e) } } } @@ -268,7 +283,14 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, val isDirectory = BitUtil.isSet(flags, IS_DIRECTORY) - val children = impl.listIds(fileId) + val children = try { + impl.listIds(fileId) + } + catch (e: Throwable) { + generalErrors++ + log.info("file[#$fileId]{$fileName}: error accessing children", e) + IntArray(0) + } if (isDirectory) { for (i in children.indices) { childrenChecked++ @@ -276,6 +298,8 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, //re-request maxAllocatedID before loop so racing changes will be accounted for: val maxAllocatedID = fileRecords.maxAllocatedID() if (childId < FSRecords.MIN_REGULAR_FILE_ID || childId > maxAllocatedID) { + //RC: actually this branch is now unreachable -- childId is checked inside .listIds(), and + // CorruptionException is thrown if childId is outside the range. generalErrors++ //MAYBE RC: dedicated counter? log.info("file[#$fileId]{$fileName}: children[$i][#$childId] " + "is outside of allocated IDs range [${FSRecords.MIN_REGULAR_FILE_ID}..$maxAllocatedID]") @@ -298,14 +322,14 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, //TODO RC: try read _all_ attributes, check all them are readable //TODO RC: check attribute storage _has_ such a record (not deleted) //if(attributeRecordId!=AbstractAttributesStorage.NON_EXISTENT_ATTR_RECORD_ID) { - //connection.attributes.forEachAttribute(connection, fileId){ - //} + // connection.attributes.forEachAttribute(connection, fileId){ + // } //} } catch (t: Throwable) { generalErrors++ - log.info("file[#$fileId]: exception while checking", t) + log.info("file[#$fileId]: unhandled exception while checking", t) } } log.info("${fileRecords.recordsCount()} file records checked: ${childrenChecked} children, ${notNullContentIds} contents") @@ -420,6 +444,9 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, val contentEnumeratorReport: ContentEnumeratorReport, val timeTaken: Duration) { + val healthy: Boolean + get() = recordsReport.healthy && rootsReport.healthy && namesEnumeratorReport.healthy && contentEnumeratorReport.healthy + data class FileRecordsReport(var fileRecordsChecked: Int = 0, var fileRecordsDeleted: Int = 0, /* record.nameId = NULL_ID */ @@ -436,7 +463,15 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, /* record.children[].parent != record */ var inconsistentParentChildRelationships: Int = 0, /* exceptions */ - var generalErrors: Int = 0) + var generalErrors: Int = 0) { + val healthy: Boolean + get() = nullNameIds == 0 + && unresolvableNameIds == 0 + && unresolvableContentIds == 0 + && nullParents == 0 + && inconsistentParentChildRelationships == 0 + && generalErrors == 0 + } data class NamesEnumeratorReport(var namesChecked: Int = 0, /* .tryEnumerate(existentNameId) = NULL_ID */ @@ -446,7 +481,13 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, /* existent name -> tryEnumerate() -> .valueOf() -> different name */ var inconsistentNames: Int = 0, /* tryEnumerate/valueOf/etc exceptions */ - var generalErrors: Int = 0) + var generalErrors: Int = 0) { + val healthy: Boolean + get() = namesResolvedToNull == 0 + && idsResolvedToNull == 0 + && inconsistentNames == 0 + && generalErrors == 0 + } data class RootsReport(var rootsCount: Int = 0, /* root.parentId != NULL_ID */ @@ -454,13 +495,21 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, /* root.isDeleted but still present in roots catalog*/ var rootsDeletedButNotRemoved: Int = 0, /* exceptions */ - var generalErrors: Int = 0) + var generalErrors: Int = 0) { + val healthy: Boolean + get() = rootsWithParents == 0 + && rootsDeletedButNotRemoved == 0 + && generalErrors == 0 + } data class ContentEnumeratorReport( var contentRecordsChecked: Int = 0, /* tryEnumerate/valueOf/etc exceptions */ var generalErrors: Int = 0 - ) + ) { + val healthy: Boolean + get() = (generalErrors == 0) + } } } @@ -484,7 +533,7 @@ fun main(args: Array) { } val log = configureLogger() - val checkupReport = VFSHealthChecker(records, log).checkHealth() + val checkupReport = VFSHealthChecker(records, log).checkHealth(checkForOrphanRecords = true) println(checkupReport) exitProcess(0) //too many non-daemon threads From 38d135bc47b2d2adc88031a7cc4145adfb165e46 Mon Sep 17 00:00:00 2001 From: Ruslan Cheremin Date: Sat, 1 Jul 2023 18:52:55 +0200 Subject: [PATCH 130/226] [core] VFS cleanup, docs & minor fixes GitOrigin-RevId: a4bd6e9f65b6eec131f28ff2b88b59c4c4075181 --- .../vfs/newvfs/persistent/FSRecords.java | 3 +- .../vfs/newvfs/persistent/FSRecordsImpl.java | 3 ++ .../persistent/PersistentFSConnection.java | 31 +++++++++---------- .../newvfs/persistent/PersistentFSImpl.java | 18 ++++++----- ...stentFSRecordsLockFreeOverMMappedFile.java | 3 +- 5 files changed, 33 insertions(+), 25 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java index 903bc6921f5a..121a9946a406 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java @@ -395,6 +395,7 @@ public final class FSRecords { return implOrFail().readAttributeRawWithLock(fileId, attribute, reader); } + @ApiStatus.Internal public static void writeAttributeRaw(int fileId, FileAttribute attribute, ByteBufferWriter writer) { @@ -445,7 +446,7 @@ public final class FSRecords { //========== aux: ======================================================== - /** With method create 'VFS corruption marker', which forces VFS to rebuild on the next startup */ + /** Method creates 'VFS corruption marker', which forces VFS to rebuild on the next startup */ public static void invalidateCaches(@NotNull String diagnosticMessage, @NotNull Throwable errorCause) { implOrFail().invalidateCaches(diagnosticMessage, errorCause); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecordsImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecordsImpl.java index 862e63e68318..c4a0fef43611 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecordsImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecordsImpl.java @@ -93,6 +93,9 @@ public final class FSRecordsImpl { */ public static final ErrorHandler ON_ERROR_MARK_CORRUPTED_AND_SCHEDULE_REBUILD = (records, error) -> { records.connection.markAsCorruptedAndScheduleRebuild(error); + if (error instanceof IOException) { + throw new UncheckedIOException((IOException)error); + } ExceptionUtil.rethrow(error); }; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java index 738a8788d143..f3cc0fd93e14 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java @@ -4,7 +4,6 @@ package com.intellij.openapi.vfs.newvfs.persistent; import com.intellij.core.CoreBundle; import com.intellij.notification.NotificationGroup; import com.intellij.notification.NotificationGroupManager; -import com.intellij.notification.NotificationType; import com.intellij.openapi.Forceable; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; @@ -97,7 +96,7 @@ public final class PersistentFSConnection { private volatile boolean myDirty; - private final Closeable flushingTask; + private final @Nullable Closeable flushingTask; /** accessed under {@link #r}/{@link #w} */ private final AtomicInteger corruptionsDetected = new AtomicInteger(); @@ -230,19 +229,16 @@ public final class PersistentFSConnection { } void doForce() throws IOException { - // avoid NPE when close has already taken place - if (myNames != null && flushingTask != null) { - if (myNames instanceof Forceable) { - ((Forceable)myNames).force(); - } - myAttributesStorage.force(); - myContents.force(); - if (myContentHashesEnumerator != null) { - myContentHashesEnumerator.force(); - } - writeConnectionState(); - myRecords.force(); + if (myNames instanceof Forceable) { + ((Forceable)myNames).force(); } + myAttributesStorage.force(); + myContents.force(); + if (myContentHashesEnumerator != null) { + myContentHashesEnumerator.force(); + } + writeConnectionState(); + myRecords.force(); } public boolean isDirty() { @@ -273,8 +269,11 @@ public final class PersistentFSConnection { return myPersistentFSPaths; } - //TODO RC: we use it to mark file record modified there something derived is modified -- i.e. children attribute - // or content. This looks suspicious to me: why we need to update _file_ record version in those cases? + /** + * Method used to mark file record modified if something _derived_ is modified -- i.e. children attribute + * or content. If file record _fields_ are mutated directly -- record marked as modified automatically, no + * need to call this method. + */ public void markRecordAsModified(int fileId) throws IOException { getRecords().markRecordAsModified(fileId); markDirty(); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index a088bbc2aecf..2204c0eafab8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -28,7 +28,6 @@ import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl; import com.intellij.openapi.vfs.newvfs.*; import com.intellij.openapi.vfs.newvfs.events.*; import com.intellij.openapi.vfs.newvfs.impl.*; -import com.intellij.openapi.vfs.newvfs.monitoring.VfsUsageCollector; import com.intellij.openapi.vfs.newvfs.persistent.log.VfsLog; import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.util.*; @@ -246,16 +245,20 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { } // return actual children - private static @NotNull List persistAllChildren(VirtualFile dir, int id) { + private static @NotNull List persistAllChildren(VirtualFile dir, int dirId) { NewVirtualFileSystem fs = getFileSystem(dir); + //FIXME RC: this method is not thread-safe: it creates new file records from children names outside + // of lock, hence it is possible >1 child to be created for the same name, and only + // last children list remains written, while children created during invocations that + // lost the race are remains orphan try { String[] fsNames = VfsUtil.filterNames( fs instanceof LocalFileSystemImpl ? ((LocalFileSystemImpl)fs).listWithCaching(dir) : fs.list(dir) ); Map justCreated = new HashMap<>(); - ListResult saved = FSRecords.update(dir, id, current -> { + ListResult saved = FSRecords.update(dir, dirId, current -> { List currentChildren = current.children; if (fsNames.length == 0 && !currentChildren.isEmpty()) { return current; @@ -277,7 +280,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { FileAttributes attrs = entry.getValue(); String target = attrs.isSymLink() ? fs.resolveSymLink(new FakeVirtualFile(dir, newName)) : null; Pair<@NotNull FileAttributes, String> childData = getChildData(fs, dir, newName, attrs, target); - ChildInfo newChild = justCreated.computeIfAbsent(newName, name -> makeChildRecord(dir, id, name, childData, fs, null)); + ChildInfo newChild = justCreated.computeIfAbsent(newName, name -> makeChildRecord(dir, dirId, name, childData, fs, null)); toAddChildren.add(newChild); } } @@ -285,7 +288,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { for (String newName : toAddNames) { Pair<@NotNull FileAttributes, String> childData = getChildData(fs, dir, newName, null, null); if (childData != null) { - ChildInfo newChild = justCreated.computeIfAbsent(newName, name -> makeChildRecord(dir, id, name, childData, fs, null)); + ChildInfo newChild = justCreated.computeIfAbsent(newName, name -> makeChildRecord(dir, dirId, name, childData, fs, null)); toAddChildren.add(newChild); } } @@ -296,7 +299,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { return current.merge(toAddChildren, caseSensitive); }); - setChildrenCached(id); + setChildrenCached(dirId); return saved.children; } @@ -391,6 +394,8 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { boolean overwriteMissed) { assert id > 0 : id; assert parentId >= 0 : parentId; // 0 means there's no parent + //RC: why we reject the changes in those 2 cases -- what is special with loaded children or + // same-name? if (!name.isEmpty()) { if (Comparing.equal(name, FSRecords.getNameSequence(id), cs)) return -1; // TODO: Handle root attributes change. } @@ -1971,7 +1976,6 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { throw new AssertionError("writeAttributesToRecord(" + childId + ", " + parentId + ", '" + name + "',...) returns -1"); } - assert childId > 0 : childId; if (attributes.isDirectory()) { FSRecords.loadDirectoryData(childId, parentFile, name, fs); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsLockFreeOverMMappedFile.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsLockFreeOverMMappedFile.java index 0d8fac3b0647..077c9d7153ee 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsLockFreeOverMMappedFile.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsLockFreeOverMMappedFile.java @@ -164,6 +164,7 @@ public class PersistentFSRecordsLockFreeOverMMappedFile implements PersistentFSR try (final Page page = storage.pageByOffset(0)) { if (updater.updateHeader(headerAccessor)) { globalModCount.incrementAndGet(); + dirty.compareAndSet(true, false); } } } @@ -195,7 +196,6 @@ public class PersistentFSRecordsLockFreeOverMMappedFile implements PersistentFSR return getIntField(ATTR_REF_OFFSET); } - @Override public int getParent() { return getIntField(PARENT_REF_OFFSET); @@ -984,6 +984,7 @@ public class PersistentFSRecordsLockFreeOverMMappedFile implements PersistentFSR } /** Opens records.dat file given as args[0], prints header fields, and first records (up to 1024) */ + @SuppressWarnings("UseOfSystemOutOrSystemErr") public static void main(String[] args) throws IOException { if (args.length < 1) { System.err.println("Args: "); From 710ff21592c9090ff5959eb905577a2768b2505c Mon Sep 17 00:00:00 2001 From: Ruslan Cheremin Date: Sat, 1 Jul 2023 19:54:49 +0200 Subject: [PATCH 131/226] [core] IDEA-319737: make VFS health-check action available in !internal IDE + In IDE[internal=true] action 'Run VFS HealthCheck' is available through menu Internal Actions/VFS, in IDE[internal=false] action available through 'search everywhere' only GitOrigin-RevId: 452d5758dc045fd7324d62f8095d87dcba742dee --- .../openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt | 2 +- .../openapi/vfs/newvfs/persistent/VFSHealthChecker.kt | 2 +- platform/platform-resources/src/idea/LangActions.xml | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt index 0e0ba105d807..8bc20bfe85c6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/CheckVFSHealthAction.kt @@ -22,7 +22,7 @@ import org.jetbrains.annotations.ApiStatus class CheckVFSHealthService(val coroutineScope: CoroutineScope) -internal class CheckVFSHealthAction : AnAction() { +internal class CheckVFSHealthAction : AnAction(ActionsBundle.message("action.CheckVfsSanity.text")) { override fun actionPerformed(e: AnActionEvent) { service().coroutineScope.launch(Dispatchers.IO) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt index 18ef4643356f..2e5692d9a12c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt @@ -270,7 +270,7 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, if (childrenOfParent.indexOf(fileId) < 0) { inconsistentParentChildRelationships++ //MAYBE RC: dedicated counter? log.info("file[#$fileId]{$fileName}: record is orphan, " + - ".parent.children(first 64: ${childrenOfParent.take(64)}...) doesn't contain it!") + ".parent[#$parentId].children(first 64 of ${childrenOfParent.size}: ${childrenOfParent.take(64)}...) doesn't contain it!") } } catch (e: Throwable) { diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index d409022495c1..a13e0a9c0da4 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -1730,7 +1730,7 @@ - + @@ -1748,5 +1748,10 @@ + + + + + From 69c5bb0d8901c1f290416c4e0b3fbdffcaa04a47 Mon Sep 17 00:00:00 2001 From: Pavel Gromov Date: Fri, 30 Jun 2023 18:31:30 +0200 Subject: [PATCH 132/226] [gitlab] Remove unnecessary inheritance GitOrigin-RevId: 4546e68f465140d4d660ad6e8ce6ebdad6ce4689 --- .../data/GitLabMergeRequestDetails.kt | 22 +++++++++--------- .../data/GitLabMergeRequestFullDetails.kt | 23 +++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDetails.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDetails.kt index d67dd33b43ba..e71a9773811c 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDetails.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDetails.kt @@ -6,18 +6,18 @@ import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO import org.jetbrains.plugins.gitlab.mergerequest.api.dto.GitLabMergeRequestShortRestDTO import java.util.* -open class GitLabMergeRequestDetails( +data class GitLabMergeRequestDetails( override val iid: String, - open val title: @NlsSafe String, - open val createdAt: Date, - open val author: GitLabUserDTO, - open val mergeStatus: GitLabMergeStatus, - open val isMergeable: Boolean, - open val state: GitLabMergeRequestState, - open val draft: Boolean, - open val assignees: List, - open val reviewers: List, - open val webUrl: @NlsSafe String, + val title: @NlsSafe String, + val createdAt: Date, + val author: GitLabUserDTO, + val mergeStatus: GitLabMergeStatus, + val isMergeable: Boolean, + val state: GitLabMergeRequestState, + val draft: Boolean, + val assignees: List, + val reviewers: List, + val webUrl: @NlsSafe String, val labels: List ) : GitLabMergeRequestId { diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestFullDetails.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestFullDetails.kt index e3d3c9870e7e..786297d11b74 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestFullDetails.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestFullDetails.kt @@ -8,16 +8,16 @@ import java.util.* data class GitLabMergeRequestFullDetails( override val iid: String, - override val title: @NlsSafe String, - override val createdAt: Date, - override val author: GitLabUserDTO, - override val mergeStatus: GitLabMergeStatus, - override val isMergeable: Boolean, - override val state: GitLabMergeRequestState, - override val draft: Boolean, - override val assignees: List, - override val reviewers: List, - override val webUrl: @NlsSafe String, + val title: @NlsSafe String, + val createdAt: Date, + val author: GitLabUserDTO, + val mergeStatus: GitLabMergeStatus, + val isMergeable: Boolean, + val state: GitLabMergeRequestState, + val draft: Boolean, + val assignees: List, + val reviewers: List, + val webUrl: @NlsSafe String, val detailedLabels: List, val targetProject: GitLabProjectDTO, val sourceProject: GitLabProjectDTO?, @@ -32,8 +32,7 @@ data class GitLabMergeRequestFullDetails( val userPermissions: GitLabMergeRequestPermissionsDTO, val shouldBeRebased: Boolean, val rebaseInProgress: Boolean -) : GitLabMergeRequestDetails(iid, title, createdAt, author, mergeStatus, isMergeable, state, draft, assignees, reviewers, webUrl, - detailedLabels.map { it.title }) { +) : GitLabMergeRequestId { companion object { fun fromGraphQL(dto: GitLabMergeRequestDTO) = GitLabMergeRequestFullDetails( From 547153dc90250caf4c8233d947c9b52a15566ef9 Mon Sep 17 00:00:00 2001 From: Pavel Gromov Date: Fri, 30 Jun 2023 18:33:25 +0200 Subject: [PATCH 133/226] [gitlab] Use REST DTO in REST entity GitOrigin-RevId: 4254951eb4fa1d4f67d0e97bb58b0e1d1fcfb3dd --- .../api/dto/GitLabMergeRequestShortRestDTO.kt | 8 ++++---- .../gitlab/mergerequest/data/GitLabMergeRequestDetails.kt | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/dto/GitLabMergeRequestShortRestDTO.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/dto/GitLabMergeRequestShortRestDTO.kt index 6dc77753e07a..31686837c412 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/dto/GitLabMergeRequestShortRestDTO.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/dto/GitLabMergeRequestShortRestDTO.kt @@ -3,7 +3,7 @@ package org.jetbrains.plugins.gitlab.mergerequest.api.dto import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.logger -import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO +import org.jetbrains.plugins.gitlab.api.dto.GitLabUserRestDTO import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeRequestId import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeRequestState import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeStatus @@ -18,9 +18,9 @@ data class GitLabMergeRequestShortRestDTO( val state: String, val mergeStatus: String, val mergeable: Boolean, - val author: GitLabUserDTO, - val assignees: List, - val reviewers: List, + val author: GitLabUserRestDTO, + val assignees: List, + val reviewers: List, val labels: List, val createdAt: Date, val draft: Boolean, diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDetails.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDetails.kt index e71a9773811c..cc3691c47b17 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDetails.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestDetails.kt @@ -27,13 +27,13 @@ data class GitLabMergeRequestDetails( dto.iid, dto.title, dto.createdAt, - dto.author, + GitLabUserDTO.fromRestDTO(dto.author), dto.mergeStatusEnum, dto.mergeable, dto.stateEnum, dto.draft, - dto.assignees, - dto.reviewers, + dto.assignees.map(GitLabUserDTO::fromRestDTO), + dto.reviewers.map(GitLabUserDTO::fromRestDTO), dto.webUrl, dto.labels ) From f3b9755dc166414e236b8ec08e57ca39e1750086 Mon Sep 17 00:00:00 2001 From: Pavel Gromov Date: Fri, 30 Jun 2023 18:45:19 +0200 Subject: [PATCH 134/226] [gitlab] Extract review state from reviewer mergeRequestInteraction API entity GitOrigin-RevId: beb534456afffbbaeb534be31b4d9938902568f0 --- .../codereview/details/ReviewDetailsUIUtil.kt | 2 +- .../details/model/CodeReviewFlowViewModel.kt | 4 +- .../graphql/fragment/mergeRequest.graphql | 3 +- .../graphql/fragment/userReviewer.graphql | 7 ++ .../gitlab/api/dto/GitLabReviewerDTO.kt | 37 +++++++++++ .../plugins/gitlab/api/dto/GitLabUserDTO.kt | 48 ++++++++++++-- .../api/dto/GitLabMergeRequestDTO.kt | 7 +- .../mergerequest/data/GitLabMergeRequest.kt | 6 +- .../data/GitLabMergeRequestFullDetails.kt | 4 +- .../GitLabMergeRequestReviewFlowViewModel.kt | 66 ++++++++++--------- 10 files changed, 137 insertions(+), 47 deletions(-) create mode 100644 plugins/gitlab/resources/graphql/fragment/userReviewer.graphql create mode 100644 plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/dto/GitLabReviewerDTO.kt diff --git a/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/details/ReviewDetailsUIUtil.kt b/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/details/ReviewDetailsUIUtil.kt index 7a05cf81de63..f3d061261fb6 100644 --- a/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/details/ReviewDetailsUIUtil.kt +++ b/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/details/ReviewDetailsUIUtil.kt @@ -21,7 +21,7 @@ object ReviewDetailsUIUtil { fun getReviewStateIcon(reviewState: ReviewState): Icon = when (reviewState) { ReviewState.ACCEPTED -> AllIcons.RunConfigurations.TestPassed - ReviewState.WAIT_FOR_UPDATES, + ReviewState.WAIT_FOR_UPDATES -> AllIcons.RunConfigurations.TestError ReviewState.NEED_REVIEW -> AllIcons.RunConfigurations.TestFailed } diff --git a/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/details/model/CodeReviewFlowViewModel.kt b/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/details/model/CodeReviewFlowViewModel.kt index 33c6384ddd81..ab38f3a6dd3c 100644 --- a/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/details/model/CodeReviewFlowViewModel.kt +++ b/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/details/model/CodeReviewFlowViewModel.kt @@ -4,6 +4,6 @@ package com.intellij.collaboration.ui.codereview.details.model import com.intellij.collaboration.ui.codereview.details.data.ReviewState import kotlinx.coroutines.flow.Flow -interface CodeReviewFlowViewModel { - val reviewerReviews: Flow> +interface CodeReviewFlowViewModel { + val reviewerReviews: Flow> } \ No newline at end of file diff --git a/plugins/gitlab/resources/graphql/fragment/mergeRequest.graphql b/plugins/gitlab/resources/graphql/fragment/mergeRequest.graphql index d12dd21b3f2f..8ca8d5e5317f 100644 --- a/plugins/gitlab/resources/graphql/fragment/mergeRequest.graphql +++ b/plugins/gitlab/resources/graphql/fragment/mergeRequest.graphql @@ -25,6 +25,7 @@ fragment mergeRequest on MergeRequest { headSha } + approved conflicts headPipeline { ...pipeline @@ -73,7 +74,7 @@ fragment mergeRequest on MergeRequest { } nodes { - ...user + ...userReviewer } } diff --git a/plugins/gitlab/resources/graphql/fragment/userReviewer.graphql b/plugins/gitlab/resources/graphql/fragment/userReviewer.graphql new file mode 100644 index 000000000000..a536b6f75674 --- /dev/null +++ b/plugins/gitlab/resources/graphql/fragment/userReviewer.graphql @@ -0,0 +1,7 @@ +fragment userReviewer on MergeRequestReviewer { + ...user + mergeRequestInteraction { + approved + reviewed + } +} \ No newline at end of file diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/dto/GitLabReviewerDTO.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/dto/GitLabReviewerDTO.kt new file mode 100644 index 000000000000..80522aa0be61 --- /dev/null +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/dto/GitLabReviewerDTO.kt @@ -0,0 +1,37 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.plugins.gitlab.api.dto + +import com.intellij.collaboration.api.dto.GraphQLFragment +import com.intellij.openapi.util.NlsSafe + +@GraphQLFragment("graphql/fragment/userReviewer.graphql") +class GitLabReviewerDTO( + id: String, + username: @NlsSafe String, + name: @NlsSafe String, + avatarUrl: String?, + webUrl: String, + val mergeRequestInteraction: MergeRequestInteraction? +) : GitLabUserDTO(id, username, name, avatarUrl, webUrl) { + + data class MergeRequestInteraction( + val approved: Boolean, + val reviewed: Boolean + ) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + if (!super.equals(other)) return false + + other as GitLabReviewerDTO + + return mergeRequestInteraction == other.mergeRequestInteraction + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + (mergeRequestInteraction?.hashCode() ?: 0) + return result + } +} \ No newline at end of file diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/dto/GitLabUserDTO.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/dto/GitLabUserDTO.kt index 4e6b74509ecf..6230e008cc10 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/dto/GitLabUserDTO.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/dto/GitLabUserDTO.kt @@ -4,6 +4,7 @@ package org.jetbrains.plugins.gitlab.api.dto import com.intellij.collaboration.api.dto.GraphQLFragment import com.intellij.collaboration.auth.AccountDetails import com.intellij.openapi.util.NlsSafe +import java.net.URL @GraphQLFragment("graphql/fragment/user.graphql") open class GitLabUserDTO( @@ -14,13 +15,46 @@ open class GitLabUserDTO( val webUrl: String ) : AccountDetails { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as GitLabUserDTO + + if (id != other.id) return false + if (username != other.username) return false + if (name != other.name) return false + if (avatarUrl != other.avatarUrl) return false + if (webUrl != other.webUrl) return false + + return true + } + + override fun hashCode(): Int { + var result = id.hashCode() + result = 31 * result + username.hashCode() + result = 31 * result + name.hashCode() + result = 31 * result + (avatarUrl?.hashCode() ?: 0) + result = 31 * result + webUrl.hashCode() + return result + } + companion object { - fun fromRestDTO(dto: GitLabUserRestDTO): GitLabUserDTO = GitLabUserDTO( - id = "gid://gitlab/User/${dto.id}", - username = dto.username, - name = dto.name, - avatarUrl = dto.avatarUrl?.removePrefix("https://gitlab.com"), - webUrl = dto.webUrl - ) + fun fromRestDTO(dto: GitLabUserRestDTO): GitLabUserDTO { + val url = URL(dto.webUrl) + val serverId = url.host.split(".").dropLast(1).joinToString(".") + + val server = dto.avatarUrl?.let { + URL(it) + } + + return GitLabUserDTO( + id = "gid://$serverId/User/${dto.id}", + username = dto.username, + name = dto.name, + avatarUrl = server?.path, + webUrl = dto.webUrl + ) + } } } \ No newline at end of file diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/dto/GitLabMergeRequestDTO.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/dto/GitLabMergeRequestDTO.kt index 0aac4aebbe4a..b43243e6e826 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/dto/GitLabMergeRequestDTO.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/dto/GitLabMergeRequestDTO.kt @@ -21,6 +21,7 @@ class GitLabMergeRequestDTO( val targetBranch: String, val sourceBranch: String, val diffRefs: GitLabDiffRefs, + val approved: Boolean, val conflicts: Boolean, val headPipeline: GitLabPipelineDTO?, val mergeStatusEnum: GitLabMergeStatus, @@ -43,7 +44,7 @@ class GitLabMergeRequestDTO( val assignees: List = assignees.nodes - val reviewers: List = reviewers.nodes + val reviewers: List = reviewers.nodes val commits: List = commits.nodes @@ -55,8 +56,8 @@ class GitLabMergeRequestDTO( class AssigneeConnection(pageInfo: GraphQLCursorPageInfoDTO, nodes: List) : GraphQLConnectionDTO(pageInfo, nodes) - class ReviewerConnection(pageInfo: GraphQLCursorPageInfoDTO, nodes: List) - : GraphQLConnectionDTO(pageInfo, nodes) + class ReviewerConnection(pageInfo: GraphQLCursorPageInfoDTO, nodes: List) + : GraphQLConnectionDTO(pageInfo, nodes) class CommitConnection(pageInfo: GraphQLCursorPageInfoDTO, nodes: List) : GraphQLConnectionDTO(pageInfo, nodes) diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt index 20db2f829a4d..f04f378c11e4 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt @@ -42,13 +42,14 @@ interface GitLabMergeRequest : GitLabMergeRequestDiscussionsContainer { val descriptionHtml: Flow val targetBranch: StateFlow val sourceBranch: StateFlow + val isApproved: Flow val hasConflicts: Flow val isDraft: Flow val reviewRequestState: Flow val isMergeable: Flow val shouldBeRebased: Flow val approvedBy: Flow> - val reviewers: Flow> + val reviewers: Flow> val pipeline: Flow val changes: Flow @@ -122,6 +123,7 @@ internal class LoadedGitLabMergeRequest( override val descriptionHtml: Flow = description.map { if (it.isNotBlank()) GitLabUIUtil.convertToHtml(it) else it } override val targetBranch: StateFlow = mergeRequestDetailsState.mapState(cs) { it.targetBranch } override val sourceBranch: StateFlow = mergeRequestDetailsState.mapState(cs) { it.sourceBranch } + override val isApproved: Flow = mergeRequestDetailsState.map { it.isApproved } override val hasConflicts: Flow = mergeRequestDetailsState.map { it.conflicts } override val isDraft: Flow = mergeRequestDetailsState.map { it.draft } override val reviewRequestState: Flow = @@ -137,7 +139,7 @@ internal class LoadedGitLabMergeRequest( override val isMergeable: Flow = mergeRequestDetailsState.map { it.isMergeable } override val shouldBeRebased: Flow = mergeRequestDetailsState.map { it.shouldBeRebased } override val approvedBy: Flow> = mergeRequestDetailsState.map { it.approvedBy } - override val reviewers: Flow> = mergeRequestDetailsState.map { it.reviewers } + override val reviewers: Flow> = mergeRequestDetailsState.map { it.reviewers } override val pipeline: Flow = mergeRequestDetailsState.map { it.headPipeline } override val changes: Flow = mergeRequestDetailsState .distinctUntilChangedBy(GitLabMergeRequestFullDetails::diffRefs).map { diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestFullDetails.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestFullDetails.kt index 786297d11b74..1a704ee1e222 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestFullDetails.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequestFullDetails.kt @@ -16,7 +16,7 @@ data class GitLabMergeRequestFullDetails( val state: GitLabMergeRequestState, val draft: Boolean, val assignees: List, - val reviewers: List, + val reviewers: List, val webUrl: @NlsSafe String, val detailedLabels: List, val targetProject: GitLabProjectDTO, @@ -25,6 +25,7 @@ data class GitLabMergeRequestFullDetails( val approvedBy: List, val targetBranch: String, val sourceBranch: String, + val isApproved: Boolean, val conflicts: Boolean, val commits: List, val diffRefs: GitLabDiffRefs, @@ -53,6 +54,7 @@ data class GitLabMergeRequestFullDetails( approvedBy = dto.approvedBy, targetBranch = dto.targetBranch, sourceBranch = dto.sourceBranch, + isApproved = dto.approved, conflicts = dto.conflicts, commits = dto.commits, diffRefs = dto.diffRefs, diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/model/GitLabMergeRequestReviewFlowViewModel.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/model/GitLabMergeRequestReviewFlowViewModel.kt index bf9edadf5076..863f670b59d9 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/model/GitLabMergeRequestReviewFlowViewModel.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/model/GitLabMergeRequestReviewFlowViewModel.kt @@ -16,7 +16,7 @@ import com.intellij.openapi.util.text.StringUtil import com.intellij.util.childScope import kotlinx.coroutines.* import kotlinx.coroutines.flow.* -import org.jetbrains.plugins.gitlab.api.data.GitLabAccessLevel +import org.jetbrains.plugins.gitlab.api.dto.GitLabReviewerDTO import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeRequest import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabProject @@ -27,21 +27,21 @@ import org.jetbrains.plugins.gitlab.mergerequest.ui.getSubmittableReview import org.jetbrains.plugins.gitlab.util.GitLabBundle import org.jetbrains.plugins.gitlab.util.SingleCoroutineLauncher -internal interface GitLabMergeRequestReviewFlowViewModel : CodeReviewFlowViewModel { - val isBusy: StateFlow +internal interface GitLabMergeRequestReviewFlowViewModel : CodeReviewFlowViewModel { + val isBusy: Flow val currentUser: GitLabUserDTO val author: GitLabUserDTO - val approvedBy: Flow> - val reviewers: StateFlow> - val role: Flow val reviewRequestState: Flow + val reviewers: StateFlow> + val reviewState: Flow + val role: Flow + val isMergeable: Flow val isApproved: StateFlow - val shouldBeRebased: Flow - val reviewState: Flow + val shouldBeRebased: Flow val userCanApprove: Flow val userCanManage: Flow @@ -93,39 +93,36 @@ internal class GitLabMergeRequestReviewFlowViewModelImpl( private val scope = parentScope.childScope() private val taskLauncher = SingleCoroutineLauncher(scope) - override val isBusy: StateFlow = taskLauncher.busy.stateIn(scope, SharingStarted.Lazily, false) + override val isBusy: Flow = taskLauncher.busy override val author: GitLabUserDTO = mergeRequest.author - override val approvedBy: Flow> = mergeRequest.approvedBy - override val reviewers: StateFlow> = mergeRequest.reviewers.stateIn(scope, SharingStarted.Lazily, emptyList()) + + override val isApproved: StateFlow = mergeRequest.isApproved.stateIn(scope, SharingStarted.Lazily, false) + + override val reviewRequestState: Flow = mergeRequest.reviewRequestState + override val reviewers: StateFlow> = mergeRequest.reviewers.stateIn(scope, SharingStarted.Lazily, emptyList()) + override val reviewerReviews: Flow> = reviewers.map { reviewers -> + reviewers.associateWith { it.mergeRequestInteraction.toReviewState() } + } + override val reviewState: Flow = combine(reviewerReviews, isApproved) { reviewerReviews, isApproved -> + val reviewStates = reviewerReviews.values + when { + isApproved -> ReviewState.ACCEPTED + reviewStates.any { it == ReviewState.WAIT_FOR_UPDATES } -> ReviewState.WAIT_FOR_UPDATES + else -> ReviewState.NEED_REVIEW + } + } override val role: Flow = reviewers.map { reviewers -> when { - author == currentUser -> ReviewRole.AUTHOR - currentUser in reviewers -> ReviewRole.REVIEWER + author.username == currentUser.username -> ReviewRole.AUTHOR + reviewers.any { it.username == currentUser.username } -> ReviewRole.REVIEWER else -> ReviewRole.GUEST } } - override val reviewRequestState: Flow = mergeRequest.reviewRequestState override val isMergeable: Flow = mergeRequest.isMergeable - override val isApproved: StateFlow = approvedBy - .map { it.isNotEmpty() } - .stateIn(scope, SharingStarted.Lazily, false) override val shouldBeRebased: Flow = mergeRequest.shouldBeRebased - override val reviewState: Flow = isApproved.map { isApproved -> - // TODO: add ReviewState.WAIT_FOR_UPDATES state - if (isApproved) ReviewState.ACCEPTED else ReviewState.NEED_REVIEW - } - - override val reviewerReviews: Flow> = combine(reviewers, approvedBy) { reviewers, approvedBy -> - mutableMapOf().apply { - reviewers.forEach { reviewer -> put(reviewer, ReviewState.NEED_REVIEW) } - approvedBy.forEach { reviewer -> put(reviewer, ReviewState.ACCEPTED) } - // TODO: implement ReviewState.WAIT_FOR_UPDATES - } - } - override val userCanApprove: Flow = mergeRequest.userPermissions.map { it.canApprove } override val userCanManage: Flow = mergeRequest.userPermissions.map { it.canMerge } override val userCanMerge: Flow = mergeRequest.userPermissions.map { it.canMerge } @@ -245,4 +242,13 @@ internal class GitLabMergeRequestReviewFlowViewModelImpl( } override suspend fun getPotentialReviewers(): List = projectData.getMembers() + + private fun GitLabReviewerDTO.MergeRequestInteraction?.toReviewState(): ReviewState { + if (this == null) return ReviewState.NEED_REVIEW + return when { + approved -> ReviewState.ACCEPTED + reviewed -> ReviewState.WAIT_FOR_UPDATES + else -> ReviewState.NEED_REVIEW + } + } } \ No newline at end of file From 3b0ebee92364468fd7a30917e7ead93552cea532 Mon Sep 17 00:00:00 2001 From: Pavel Gromov Date: Fri, 30 Jun 2023 18:49:52 +0200 Subject: [PATCH 135/226] [gitlab] Implement re-request review action (IDEA-323942) GitOrigin-RevId: 98f0d60620646b4006ce05d243bb6132837f13ba --- .../mergeRequestReviewerRereview.graphql | 12 +++++++++++ .../plugins/gitlab/api/GitLabGQLQuery.kt | 3 ++- ...GitLabMergeRequestReRequestReviewAction.kt | 20 +++++++++++++++--- .../api/request/GitLabMergeRequestsApi.kt | 17 +++++++++++++++ .../mergerequest/data/GitLabMergeRequest.kt | 14 +++++++++++++ ...geRequestDetailsActionsComponentFactory.kt | 10 +++++++-- .../GitLabMergeRequestReviewFlowViewModel.kt | 21 +++++++++++++------ .../plugins/gitlab/util/gitLabStatistics.kt | 7 +++++-- 8 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 plugins/gitlab/resources/graphql/query/mergeRequestReviewerRereview.graphql diff --git a/plugins/gitlab/resources/graphql/query/mergeRequestReviewerRereview.graphql b/plugins/gitlab/resources/graphql/query/mergeRequestReviewerRereview.graphql new file mode 100644 index 000000000000..0e4cbfb516a6 --- /dev/null +++ b/plugins/gitlab/resources/graphql/query/mergeRequestReviewerRereview.graphql @@ -0,0 +1,12 @@ +mutation ($projectId: ID!, $mergeRequestId: String!, $userId: UserID!) { + mergeRequestReviewerRereview(input: { + projectPath: $projectId, + iid: $mergeRequestId, + userId: $userId + }) { + mergeRequest { + ...mergeRequest + } + errors + } +} \ No newline at end of file diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/GitLabGQLQuery.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/GitLabGQLQuery.kt index 672764c80a9b..ff8a588f313d 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/GitLabGQLQuery.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/api/GitLabGQLQuery.kt @@ -18,5 +18,6 @@ enum class GitLabGQLQuery(val filePath: String) { MERGE_REQUEST_ACCEPT("graphql/query/mergeRequestAccept.graphql"), MERGE_REQUEST_SET_DRAFT("graphql/query/mergeRequestSetDraft.graphql"), MERGE_REQUEST_SET_REVIEWERS("graphql/query/mergeRequestSetReviewers.graphql"), - MERGE_REQUEST_UPDATE("graphql/query/mergeRequestUpdate.graphql") + MERGE_REQUEST_UPDATE("graphql/query/mergeRequestUpdate.graphql"), + MERGE_REQUEST_REVIEWER_REREVIEW("graphql/query/mergeRequestReviewerRereview.graphql") } diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/action/GitLabMergeRequestReRequestReviewAction.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/action/GitLabMergeRequestReRequestReviewAction.kt index bb4051c06483..09b48c81ce41 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/action/GitLabMergeRequestReRequestReviewAction.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/action/GitLabMergeRequestReRequestReviewAction.kt @@ -1,11 +1,25 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.plugins.gitlab.mergerequest.action +import com.intellij.collaboration.async.combineAndCollect import com.intellij.collaboration.messages.CollaborationToolsBundle +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.jetbrains.plugins.gitlab.mergerequest.ui.details.model.GitLabMergeRequestReviewFlowViewModel import java.awt.event.ActionEvent import javax.swing.AbstractAction -// TODO: implement -class GitLabMergeRequestReRequestReviewAction : AbstractAction(CollaborationToolsBundle.message("review.details.action.rerequest")) { - override fun actionPerformed(e: ActionEvent?) {} +internal class GitLabMergeRequestReRequestReviewAction( + scope: CoroutineScope, + private val reviewFlowVm: GitLabMergeRequestReviewFlowViewModel +) : AbstractAction(CollaborationToolsBundle.message("review.details.action.rerequest")) { + init { + scope.launch { + combineAndCollect(reviewFlowVm.isBusy, reviewFlowVm.userCanManage) { isBusy, userCanManageReview -> + isEnabled = !isBusy && userCanManageReview + } + } + } + + override fun actionPerformed(e: ActionEvent?) = reviewFlowVm.reviewerRereview() } \ No newline at end of file diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/request/GitLabMergeRequestsApi.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/request/GitLabMergeRequestsApi.kt index 6b2555a1abc7..59af72155c92 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/request/GitLabMergeRequestsApi.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/api/request/GitLabMergeRequestsApi.kt @@ -8,6 +8,7 @@ import com.intellij.collaboration.util.resolveRelative import com.intellij.collaboration.util.withQuery import org.jetbrains.plugins.gitlab.api.* import org.jetbrains.plugins.gitlab.api.dto.GitLabGraphQLMutationResultDTO +import org.jetbrains.plugins.gitlab.api.dto.GitLabReviewerDTO import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO import org.jetbrains.plugins.gitlab.mergerequest.api.dto.GitLabMergeRequestApprovalRestDTO import org.jetbrains.plugins.gitlab.mergerequest.api.dto.GitLabMergeRequestDTO @@ -161,6 +162,22 @@ suspend fun GitLabApi.GraphQL.mergeRequestSetDraft( } } +suspend fun GitLabApi.GraphQL.mergeRequestReviewerRereview( + project: GitLabProjectCoordinates, + mergeRequestId: GitLabMergeRequestId, + reviewer: GitLabReviewerDTO +): HttpResponse?> { + val parameters = mapOf( + "projectId" to project.projectPath.fullPath(), + "mergeRequestId" to mergeRequestId.iid, + "userId" to reviewer.id + ) + val request = gitLabQuery(project.serverPath, GitLabGQLQuery.MERGE_REQUEST_REVIEWER_REREVIEW, parameters) + return withErrorStats(project.serverPath, GitLabGQLQuery.MERGE_REQUEST_REVIEWER_REREVIEW) { + loadResponse(request, "mergeRequestReviewerRereview") + } +} + private class GitLabMergeRequestResult(mergeRequest: GitLabMergeRequestDTO, errors: List?) : GitLabGraphQLMutationResultDTO(errors) { override val value = mergeRequest diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt index f04f378c11e4..eab81206e0ea 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/data/GitLabMergeRequest.kt @@ -84,6 +84,8 @@ interface GitLabMergeRequest : GitLabMergeRequestDiscussionsContainer { suspend fun setReviewers(reviewers: List) + suspend fun reviewerRereview(reviewers: Collection) + data class CurrentUserPermissions( val canApprove: Boolean, val canMerge: Boolean, @@ -327,6 +329,18 @@ internal class LoadedGitLabMergeRequest( GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.SET_REVIEWERS) } + override suspend fun reviewerRereview(reviewers: Collection) { + withContext(cs.coroutineContext + Dispatchers.IO) { + reviewers.forEach { reviewer -> + val updatedMergeRequest = api.graphQL.mergeRequestReviewerRereview(glProject, mergeRequestDetailsState.value, reviewer) + .getResultOrThrow() + mergeRequestDetailsState.value = GitLabMergeRequestFullDetails.fromGraphQL(updatedMergeRequest) + } + } + discussionsContainer.checkUpdates() + GitLabStatistics.logMrActionExecuted(project, GitLabStatistics.MergeRequestAction.REVIEWER_REREVIEW) + } + private val discussionsContainer = GitLabMergeRequestDiscussionsContainerImpl(parentCs, project, api, projectMapping.repository, this) diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/GitLabMergeRequestDetailsActionsComponentFactory.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/GitLabMergeRequestDetailsActionsComponentFactory.kt index f190b3c629a6..7607149bf199 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/GitLabMergeRequestDetailsActionsComponentFactory.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/GitLabMergeRequestDetailsActionsComponentFactory.kt @@ -25,6 +25,7 @@ import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO import org.jetbrains.plugins.gitlab.mergerequest.action.* import org.jetbrains.plugins.gitlab.mergerequest.ui.GitLabMergeRequestSubmitReviewPopup import org.jetbrains.plugins.gitlab.mergerequest.ui.details.model.GitLabMergeRequestReviewFlowViewModel +import org.jetbrains.plugins.gitlab.mergerequest.ui.details.model.GitLabMergeRequestReviewFlowViewModelImpl.Companion.toReviewState import org.jetbrains.plugins.gitlab.util.GitLabBundle import javax.swing.JButton import javax.swing.JComponent @@ -39,7 +40,7 @@ internal object GitLabMergeRequestDetailsActionsComponentFactory { ): JComponent { val reviewActions = CodeReviewActions( requestReviewAction = GitLabMergeRequestRequestReviewAction(scope, reviewFlowVm, avatarIconsProvider), - reRequestReviewAction = GitLabMergeRequestReRequestReviewAction(), + reRequestReviewAction = GitLabMergeRequestReRequestReviewAction(scope, reviewFlowVm), closeReviewAction = GitLabMergeRequestCloseAction(scope, reviewFlowVm), reopenReviewAction = GitLabMergeRequestReopenAction(scope, reviewFlowVm), setMyselfAsReviewerAction = GitLabMergeRequestSetMyselfAsReviewerAction(scope, reviewFlowVm), @@ -53,7 +54,12 @@ internal object GitLabMergeRequestDetailsActionsComponentFactory { return Wrapper().apply { bindContentIn(scope, reviewFlowVm.role) { role -> val mainPanel = when (role) { - ReviewRole.AUTHOR -> createActionsForAuthor(reviewFlowVm.reviewState, reviewFlowVm.reviewers, reviewActions, moreActionsGroup) + ReviewRole.AUTHOR -> { + val requestedReviewers = reviewFlowVm.reviewers.map { reviewers -> + reviewers.filter { it.mergeRequestInteraction.toReviewState() == ReviewState.NEED_REVIEW } + } + createActionsForAuthor(reviewFlowVm.reviewState, requestedReviewers, reviewActions, moreActionsGroup) + } ReviewRole.REVIEWER -> createActionsForReviewer(reviewFlowVm, reviewActions, moreActionsGroup) ReviewRole.GUEST -> CodeReviewDetailsActionsComponentFactory.createActionsForGuest(reviewActions, moreActionsGroup, ::createMergeActionGroup) diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/model/GitLabMergeRequestReviewFlowViewModel.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/model/GitLabMergeRequestReviewFlowViewModel.kt index 863f670b59d9..0aa59e12ffc6 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/model/GitLabMergeRequestReviewFlowViewModel.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/mergerequest/ui/details/model/GitLabMergeRequestReviewFlowViewModel.kt @@ -77,6 +77,8 @@ internal interface GitLabMergeRequestReviewFlowViewModel : CodeReviewFlowViewMod fun removeReviewer(reviewer: GitLabUserDTO) + fun reviewerRereview() + //TODO: extract reviewers update VM suspend fun getPotentialReviewers(): List } @@ -229,6 +231,11 @@ internal class GitLabMergeRequestReviewFlowViewModelImpl( mergeRequest.setReviewers(newReviewers) // TODO: implement via CollectionDelta } + override fun reviewerRereview() = runAction { + val requestedReviewers = reviewerReviews.first().filterValues { it == ReviewState.WAIT_FOR_UPDATES }.keys + mergeRequest.reviewerRereview(requestedReviewers) + } + private fun runAction(action: suspend () -> Unit) { taskLauncher.launch { try { @@ -243,12 +250,14 @@ internal class GitLabMergeRequestReviewFlowViewModelImpl( override suspend fun getPotentialReviewers(): List = projectData.getMembers() - private fun GitLabReviewerDTO.MergeRequestInteraction?.toReviewState(): ReviewState { - if (this == null) return ReviewState.NEED_REVIEW - return when { - approved -> ReviewState.ACCEPTED - reviewed -> ReviewState.WAIT_FOR_UPDATES - else -> ReviewState.NEED_REVIEW + companion object { + fun GitLabReviewerDTO.MergeRequestInteraction?.toReviewState(): ReviewState { + if (this == null) return ReviewState.NEED_REVIEW + return when { + approved -> ReviewState.ACCEPTED + reviewed -> ReviewState.WAIT_FOR_UPDATES + else -> ReviewState.NEED_REVIEW + } } } } \ No newline at end of file diff --git a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/util/gitLabStatistics.kt b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/util/gitLabStatistics.kt index 637712be53f9..7350cfdfd155 100644 --- a/plugins/gitlab/src/org/jetbrains/plugins/gitlab/util/gitLabStatistics.kt +++ b/plugins/gitlab/src/org/jetbrains/plugins/gitlab/util/gitLabStatistics.kt @@ -35,7 +35,7 @@ internal object GitLabStatistics { //endregion //region Counters - private val COUNTERS_GROUP = EventLogGroup("vcs.gitlab.counters", version = 5) + private val COUNTERS_GROUP = EventLogGroup("vcs.gitlab.counters", version = 6) /** * Server returned 5** error @@ -146,6 +146,7 @@ internal object GitLabStatistics { CLOSE, REOPEN, SET_REVIEWERS, + REVIEWER_REREVIEW, ADD_NOTE, ADD_DIFF_NOTE, ADD_DISCUSSION_NOTE, @@ -196,7 +197,8 @@ enum class GitLabApiRequestName { GQL_MERGE_REQUEST_ACCEPT, GQL_MERGE_REQUEST_SET_DRAFT, GQL_MERGE_REQUEST_SET_REVIEWERS, - GQL_MERGE_REQUEST_UPDATE; + GQL_MERGE_REQUEST_UPDATE, + GQL_MERGE_REQUEST_REVIEWER_REREVIEW; companion object { fun of(gqlQuery: GitLabGQLQuery): GitLabApiRequestName = when (gqlQuery) { @@ -214,6 +216,7 @@ enum class GitLabApiRequestName { GitLabGQLQuery.MERGE_REQUEST_SET_DRAFT -> GQL_MERGE_REQUEST_SET_DRAFT GitLabGQLQuery.MERGE_REQUEST_SET_REVIEWERS -> GQL_MERGE_REQUEST_SET_REVIEWERS GitLabGQLQuery.MERGE_REQUEST_UPDATE -> GQL_MERGE_REQUEST_UPDATE + GitLabGQLQuery.MERGE_REQUEST_REVIEWER_REREVIEW -> GQL_MERGE_REQUEST_REVIEWER_REREVIEW } } } From d18f3373adb06bc7c17d623c24cdaf6b14eeb1a6 Mon Sep 17 00:00:00 2001 From: Bart van Helvert Date: Wed, 28 Jun 2023 12:33:45 +0200 Subject: [PATCH 136/226] [kotlin] Move K2ReferenceMutateService to common refactoring module GitOrigin-RevId: ec38caf8c15467e677e31906719b160f1dd5e1cc --- .../resources/kotlin.refactorings.k2.xml | 2 ++ .../idea/k2/refactoring}/K2ReferenceMutateService.kt | 11 +++++------ .../resources/kotlin.refactorings.rename.k2.xml | 5 ----- 3 files changed, 7 insertions(+), 11 deletions(-) rename plugins/kotlin/refactorings/{rename.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/rename => kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring}/K2ReferenceMutateService.kt (78%) diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.k2/resources/kotlin.refactorings.k2.xml b/plugins/kotlin/refactorings/kotlin.refactorings.k2/resources/kotlin.refactorings.k2.xml index 54d4c0bc28b2..8f641b647b45 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.k2/resources/kotlin.refactorings.k2.xml +++ b/plugins/kotlin/refactorings/kotlin.refactorings.k2/resources/kotlin.refactorings.k2.xml @@ -9,6 +9,8 @@ serviceInterface="org.jetbrains.kotlin.idea.refactoring.KotlinCommonRefactoringSettings"/> + - - - From 7bdc4fbaa9e86111061ae29f53c0894b858d12e5 Mon Sep 17 00:00:00 2001 From: Bart van Helvert Date: Thu, 29 Jun 2023 22:37:23 +0200 Subject: [PATCH 137/226] [uast] Improve bind to element implementation for Kotlin GitOrigin-RevId: 338c15eb128b472cdc853313ef0942e9b3ca09a2 --- .../uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/kotlin/uast/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt b/plugins/kotlin/uast/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt index 80cadcaf3378..db24ee08f6b6 100644 --- a/plugins/kotlin/uast/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt +++ b/plugins/kotlin/uast/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses import org.jetbrains.kotlin.idea.intentions.ImportAllMembersIntention import org.jetbrains.kotlin.idea.refactoring.fqName.fqName import org.jetbrains.kotlin.idea.references.KtSimpleNameReference +import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.resolveToKotlinType import org.jetbrains.kotlin.incremental.components.NoLookupLocation @@ -27,7 +28,6 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* -import org.jetbrains.kotlin.references.fe10.KtFe10SimpleNameReference import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier import org.jetbrains.uast.* import org.jetbrains.uast.generate.UParameterInfo @@ -83,8 +83,7 @@ class KotlinUastCodeGenerationPlugin : UastCodeGenerationPlugin { override fun bindToElement(reference: UReferenceExpression, element: PsiElement): PsiElement? { val sourcePsi = reference.sourcePsi ?: return null if (sourcePsi !is KtSimpleNameExpression) return null - return KtFe10SimpleNameReference(sourcePsi) - .bindToElement(element, KtSimpleNameReference.ShorteningMode.FORCED_SHORTENING) + return sourcePsi.mainReference.bindToElement(element, KtSimpleNameReference.ShorteningMode.FORCED_SHORTENING) } override fun shortenReference(reference: UReferenceExpression): UReferenceExpression? { From b26628649f4748683ca7af4b0262f5580f3bcae4 Mon Sep 17 00:00:00 2001 From: Bart van Helvert Date: Sun, 2 Jul 2023 09:51:54 +0200 Subject: [PATCH 138/226] [kotlin] Support basic `bindToElement` in K2 Allows binding references to new names. #KTIJ-26105 Fixed GitOrigin-RevId: cea88ebc93f1a2bb770c900e3959c3fc82d694fa --- .../refactoring/rename/AbstractRenameTest.kt | 4 +- .../bindToElement/call/FullyQualified.kt | 10 ++ .../call/FullyQualified.kt.after | 10 ++ .../refactoring/bindToElement/call/RootPkg.kt | 8 ++ .../bindToElement/call/RootPkg.kt.after | 8 ++ .../bindToElement/call/TypeArgument.kt | 8 ++ .../bindToElement/call/TypeArgument.kt.after | 8 ++ .../bindToElement/call/UnQualified.kt | 10 ++ .../bindToElement/call/UnQualified.kt.after | 10 ++ .../callableReference/FullyQualified.kt | 14 +++ .../callableReference/FullyQualified.kt.after | 14 +++ .../callableReference/RootPkg.kt | 12 +++ .../callableReference/RootPkg.kt.after | 12 +++ .../callableReference/UnQualified.kt | 14 +++ .../callableReference/UnQualified.kt.after | 14 +++ .../bindToElement/type/FullyQualified.kt | 10 ++ .../type/FullyQualified.kt.after | 10 ++ .../refactoring/bindToElement/type/RootPkg.kt | 8 ++ .../bindToElement/type/RootPkg.kt.after | 8 ++ .../bindToElement/type/UnQualified.kt | 10 ++ .../bindToElement/type/UnQualified.kt.after | 10 ++ .../kotlin.refactorings.k2.iml | 1 + .../refactoring/K2ReferenceMutateService.kt | 67 ++++++++++--- .../kotlin.refactorings.tests.k2.iml | 2 + .../safeDelete/AbstractK2BindToElementTest.kt | 50 ++++++++++ .../K2BindToElementTestGenerated.java | 94 +++++++++++++++++++ .../rename/AbstractFirRenameTest.kt | 36 ++++--- .../GenerateK2RefactoringsTests.kt | 6 ++ 28 files changed, 437 insertions(+), 31 deletions(-) create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt.after create mode 100644 plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/AbstractK2BindToElementTest.kt create mode 100644 plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/K2BindToElementTestGenerated.java diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt index bd09c0965ce9..8aa28daadc52 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt @@ -32,8 +32,9 @@ import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.UsefulTestCase import com.intellij.testFramework.fixtures.CodeInsightTestUtil +import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt import org.jetbrains.kotlin.asJava.finder.KtLightPackage -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.idea.base.plugin.artifacts.TestKotlinArtifacts import org.jetbrains.kotlin.idea.base.util.allScope import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks @@ -363,6 +364,7 @@ abstract class AbstractRenameTest : KotlinLightCodeInsightFixtureTestCase() { return DescriptorToSourceUtils.descriptorToDeclaration(descriptor)!! } + @OptIn(KtAllowAnalysisOnEdt::class) private fun renameWithAutoDetection(renameParamsObject: JsonObject, context: TestContext) { val mainFilePath = renameParamsObject.getString("mainFile") val newName = renameParamsObject.getString("newName") diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt new file mode 100644 index 000000000000..2378cae83efb --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt @@ -0,0 +1,10 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +class A { } + +class B { } + +fun foo() { + val x = org.jetbrains.A() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt.after new file mode 100644 index 000000000000..c938fa3a18db --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt.after @@ -0,0 +1,10 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +class A { } + +class B { } + +fun foo() { + val x = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt new file mode 100644 index 000000000000..db15982c9e02 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt @@ -0,0 +1,8 @@ +// BIND_TO B +class A { } + +class B { } + +fun foo() { + val x = A() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt.after new file mode 100644 index 000000000000..d7f9a64c052e --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt.after @@ -0,0 +1,8 @@ +// BIND_TO B +class A { } + +class B { } + +fun foo() { + val x = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt new file mode 100644 index 000000000000..3d09fc2466e9 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt @@ -0,0 +1,8 @@ +// BIND_TO B +class A { } + +class B { } + +fun foo() { + val x = A() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt.after new file mode 100644 index 000000000000..00192082a0ca --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt.after @@ -0,0 +1,8 @@ +// BIND_TO B +class A { } + +class B { } + +fun foo() { + val x = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt new file mode 100644 index 000000000000..e426c2137e7b --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt @@ -0,0 +1,10 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +class A { } + +class B { } + +fun foo() { + val x = A() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt.after new file mode 100644 index 000000000000..c938fa3a18db --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt.after @@ -0,0 +1,10 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +class A { } + +class B { } + +fun foo() { + val x = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt new file mode 100644 index 000000000000..11b42d47f02f --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt @@ -0,0 +1,14 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +class A { + fun foo() { } +} + +class B { + fun foo() { } +} + +fun foo() { + val x = org.jetbrains.A::foo +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt.after new file mode 100644 index 000000000000..cdee721f78d9 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt.after @@ -0,0 +1,14 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +class A { + fun foo() { } +} + +class B { + fun foo() { } +} + +fun foo() { + val x = B::foo +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt new file mode 100644 index 000000000000..a78ba938081f --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt @@ -0,0 +1,12 @@ +// BIND_TO B +class A { + fun foo() { } +} + +class B { + fun foo() { } +} + +fun foo() { + val x = A::foo +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt.after new file mode 100644 index 000000000000..3b7ee7ae1bec --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt.after @@ -0,0 +1,12 @@ +// BIND_TO B +class A { + fun foo() { } +} + +class B { + fun foo() { } +} + +fun foo() { + val x = B::foo +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt new file mode 100644 index 000000000000..b8af557bb967 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt @@ -0,0 +1,14 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +class A { + fun foo() { } +} + +class B { + fun foo() { } +} + +fun foo() { + val x = A::foo +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt.after new file mode 100644 index 000000000000..cdee721f78d9 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt.after @@ -0,0 +1,14 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +class A { + fun foo() { } +} + +class B { + fun foo() { } +} + +fun foo() { + val x = B::foo +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt new file mode 100644 index 000000000000..adced0a354b2 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt @@ -0,0 +1,10 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +interface A { } + +class B : A { } + +fun foo() { + val x: org.jetbrains.A = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt.after new file mode 100644 index 000000000000..6613edf678f9 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt.after @@ -0,0 +1,10 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +interface A { } + +class B : A { } + +fun foo() { + val x: B = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt new file mode 100644 index 000000000000..ec0c779803ba --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt @@ -0,0 +1,8 @@ +// BIND_TO B +interface A { } + +class B : A { } + +fun foo() { + val x: A = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt.after new file mode 100644 index 000000000000..ac5af471ff0d --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt.after @@ -0,0 +1,8 @@ +// BIND_TO B +interface A { } + +class B : A { } + +fun foo() { + val x: B = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt new file mode 100644 index 000000000000..2110070208dc --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt @@ -0,0 +1,10 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +interface A { } + +class B : A { } + +fun foo() { + val x: A = B() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt.after new file mode 100644 index 000000000000..6613edf678f9 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt.after @@ -0,0 +1,10 @@ +// BIND_TO org.jetbrains.B +package org.jetbrains + +interface A { } + +class B : A { } + +fun foo() { + val x: B = B() +} \ No newline at end of file diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.k2/kotlin.refactorings.k2.iml b/plugins/kotlin/refactorings/kotlin.refactorings.k2/kotlin.refactorings.k2.iml index 7068c93db1ad..c9f28120eb6f 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.k2/kotlin.refactorings.k2.iml +++ b/plugins/kotlin/refactorings/kotlin.refactorings.k2/kotlin.refactorings.k2.iml @@ -22,5 +22,6 @@ + \ No newline at end of file diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/K2ReferenceMutateService.kt b/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/K2ReferenceMutateService.kt index c763c49ecfba..6fcdbc6e67f2 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/K2ReferenceMutateService.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/K2ReferenceMutateService.kt @@ -2,32 +2,77 @@ package org.jetbrains.kotlin.idea.k2.refactoring import com.intellij.psi.PsiElement +import com.intellij.psi.util.parentOfTypes import com.intellij.util.IncorrectOperationException +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.idea.base.analysis.api.utils.invokeShortening +import org.jetbrains.kotlin.idea.base.psi.replaced import org.jetbrains.kotlin.idea.refactoring.intentions.OperatorToFunctionConverter import org.jetbrains.kotlin.idea.refactoring.rename.KtReferenceMutateServiceBase import org.jetbrains.kotlin.idea.references.KtDefaultAnnotationArgumentReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.SyntheticPropertyAccessorReference import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.KtDotQualifiedExpression -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtValueArgument +import org.jetbrains.kotlin.psi.* /** - * At the moment, this implementation of [org.jetbrains.kotlin.idea.references.KtReferenceMutateService] is not able to do any of required - * operations. It is OK and on purpose - this functionality will be added later. + * At the moment, this implementation of [org.jetbrains.kotlin.idea.references.KtReferenceMutateService] is not able to do some of the + * required operations. It is OK and on purpose - this functionality will be added later. */ internal class K2ReferenceMutateService : KtReferenceMutateServiceBase() { override fun bindToFqName( - simpleNameReference: KtSimpleNameReference, - fqName: FqName, - shorteningMode: KtSimpleNameReference.ShorteningMode, - targetElement: PsiElement? + simpleNameReference: KtSimpleNameReference, + fqName: FqName, + shorteningMode: KtSimpleNameReference.ShorteningMode, // not supported in K2, it always does FORCED_SHORTENING + targetElement: PsiElement? ): PsiElement { - operationNotSupportedInK2Error() + if (targetElement !is KtElement) operationNotSupportedInK2Error() // TODO fix reference shortener for non-Kotlin target elements + val expression = simpleNameReference.expression + if (fqName.isRoot) return expression + val anchorElement = expression.parentOfTypes(KtTypeReference::class) ?: expression.topMostQualified() + val newElement = when (anchorElement) { + is KtTypeReference -> anchorElement.replaceWith(fqName) + is KtSimpleNameExpression -> anchorElement.replaceWith(fqName) + is KtDotQualifiedExpression -> anchorElement.replaceWith(fqName) + else -> return expression + } ?: return expression + val newShortenings = analyze(newElement) { collectPossibleReferenceShorteningsInElement(newElement) } + return newShortenings.invokeShortening().firstOrNull() ?: newElement } + private fun KtTypeReference.replaceWith(fqName: FqName): KtTypeReference { + val newReference = KtPsiFactory(project).createType(fqName.asString()) + return replaced(newReference) + } + + private fun KtSimpleNameExpression.replaceWith(fqName: FqName): KtExpression { + val newNameExpression = KtPsiFactory(project).createExpression(fqName.asString()) + return replaced(newNameExpression) + } + + private fun KtDotQualifiedExpression.replaceWith(fqName: FqName): KtExpression? { + val psiFactory = KtPsiFactory(project) + val selectorExpression = selectorExpression ?: return null + val newExpression = when (selectorExpression) { + is KtNameReferenceExpression -> { + psiFactory.createExpression(fqName.asString()) + } + is KtCallElement -> { + val newName = psiFactory.createSimpleName(fqName.shortName().asString()) + selectorExpression.calleeExpression?.replace(newName) + val packageName = fqName.pathSegments().apply { removeLast() }.joinToString(".") { it.asString() } + psiFactory.createExpression("$packageName.${(selectorExpression as KtCallElement).text}") + } + else -> return null + } + return replaced(newExpression) + } + + private fun KtSimpleNameExpression.topMostQualified() = generateSequence(this) { elem -> + val parent = elem.parent + if (parent is KtDotQualifiedExpression) parent else null + }.lastOrNull() ?: this + override fun SyntheticPropertyAccessorReference.renameTo(newElementName: String): KtElement? { operationNotSupportedInK2Error() } diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/kotlin.refactorings.tests.k2.iml b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/kotlin.refactorings.tests.k2.iml index 5bdf093c7c6c..16bdcdd4f37c 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/kotlin.refactorings.tests.k2.iml +++ b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/kotlin.refactorings.tests.k2.iml @@ -12,5 +12,7 @@ + + \ No newline at end of file diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/AbstractK2BindToElementTest.kt b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/AbstractK2BindToElementTest.kt new file mode 100644 index 000000000000..c62435ffbdef --- /dev/null +++ b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/AbstractK2BindToElementTest.kt @@ -0,0 +1,50 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.k2.refactoring.safeDelete + +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.parentOfType +import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt +import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt +import org.jetbrains.kotlin.asJava.unwrapped +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.ProjectDescriptorWithStdlibSources +import org.jetbrains.kotlin.psi.KtSimpleNameExpression + +abstract class AbstractK2BindToElementTest : KotlinLightCodeInsightFixtureTestCase() { + override fun isFirPlugin() = true + + override fun getProjectDescriptor() = ProjectDescriptorWithStdlibSources.getInstanceWithStdlibSources() + + @OptIn(KtAllowAnalysisOnEdt::class) + protected fun doTest(path: String) { + val file = myFixture.configureByFile(path) + val elem = file.findElementAt(myFixture.caretOffset) ?: error("Couldn't find element at caret") + val nameReference = elem.parentOfType(withSelf = true) + ?: error("Element at caret isn't of type 'KtSimpleNameExpression'") + val bindTarget = findElementToBind()?.unwrapped ?: error("Could not find element to bind") + WriteCommandAction.runWriteCommandAction(myFixture.project) { + allowAnalysisOnEdt { + nameReference.mainReference.bindToElement(bindTarget) + } + } + myFixture.checkResultByFile("${myFixture.file.name}.after") + } + + private fun findElementToBind(): PsiElement? { + val classToBind = InTextDirectivesUtils.findStringWithPrefixes(file.text, BIND_TO) + return if (classToBind != null) findClass(classToBind) else null + } + + private fun findClass(fqn: String): PsiClass? = JavaPsiFacade.getInstance(myFixture.project) + .findClass(fqn, GlobalSearchScope.allScope(myFixture.project)) + + private companion object { + const val BIND_TO = "BIND_TO" + } +} \ No newline at end of file diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/K2BindToElementTestGenerated.java b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/K2BindToElementTestGenerated.java new file mode 100644 index 000000000000..8697aca27628 --- /dev/null +++ b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/K2BindToElementTestGenerated.java @@ -0,0 +1,94 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +package org.jetbrains.kotlin.idea.k2.refactoring.safeDelete; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.idea.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.jetbrains.kotlin.idea.base.test.TestRoot; +import org.junit.runner.RunWith; + +/** + * This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}. + * DO NOT MODIFY MANUALLY. + */ +@SuppressWarnings("all") +@TestRoot("refactorings/kotlin.refactorings.tests.k2") +@TestDataPath("$CONTENT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public abstract class K2BindToElementTestGenerated extends AbstractK2BindToElementTest { + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../../idea/tests/testData/refactoring/bindToElement/call") + public static class Call extends AbstractK2BindToElementTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("FullyQualified.kt") + public void testFullyQualified() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/call/FullyQualified.kt"); + } + + @TestMetadata("RootPkg.kt") + public void testRootPkg() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/call/RootPkg.kt"); + } + + @TestMetadata("TypeArgument.kt") + public void testTypeArgument() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/call/TypeArgument.kt"); + } + + @TestMetadata("UnQualified.kt") + public void testUnQualified() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/call/UnQualified.kt"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../../idea/tests/testData/refactoring/bindToElement/callableReference") + public static class CallableReference extends AbstractK2BindToElementTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("FullyQualified.kt") + public void testFullyQualified() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/callableReference/FullyQualified.kt"); + } + + @TestMetadata("RootPkg.kt") + public void testRootPkg() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/callableReference/RootPkg.kt"); + } + + @TestMetadata("UnQualified.kt") + public void testUnQualified() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/callableReference/UnQualified.kt"); + } + } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../../idea/tests/testData/refactoring/bindToElement/type") + public static class Type extends AbstractK2BindToElementTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("FullyQualified.kt") + public void testFullyQualified() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/type/FullyQualified.kt"); + } + + @TestMetadata("RootPkg.kt") + public void testRootPkg() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/type/RootPkg.kt"); + } + + @TestMetadata("UnQualified.kt") + public void testUnQualified() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt"); + } + } +} diff --git a/plugins/kotlin/refactorings/rename.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/rename/AbstractFirRenameTest.kt b/plugins/kotlin/refactorings/rename.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/rename/AbstractFirRenameTest.kt index b69f83969a83..fe4368807e10 100644 --- a/plugins/kotlin/refactorings/rename.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/rename/AbstractFirRenameTest.kt +++ b/plugins/kotlin/refactorings/rename.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/rename/AbstractFirRenameTest.kt @@ -37,41 +37,39 @@ abstract class AbstractFirRenameTest : AbstractRenameTest() { return KotlinWithJdkAndRuntimeLightProjectDescriptor.getInstance() } + @OptIn(KtAllowAnalysisOnEdt::class) override fun doTest(path: String) { val renameObject = loadTestConfiguration(dataFile()) val testIsEnabledInK2 = renameObject.get("enabledInK2")?.asBoolean == true if (!testIsEnabledInK2 && onlyRunEnabledTests) return - val result = runCatching { super.doTest(path) } + val result = allowAnalysisOnEdt { runCatching { super.doTest(path) } } result.fold( onSuccess = { require(testIsEnabledInK2) { "This test passes and should be enabled!" } }, onFailure = { exception -> if (testIsEnabledInK2) throw exception } ) } - @OptIn(KtAllowAnalysisOnEdt::class) - override fun findPsiDeclarationToRename(contextFile: KtFile, target: KotlinTarget): PsiElement = allowAnalysisOnEdt { - analyze(contextFile) { - when (target) { - is KotlinTarget.Classifier -> getClassOrObjectSymbolByClassId(target.classId)?.psi!! - is KotlinTarget.Callable -> { - val callableId = target.callableId + override fun findPsiDeclarationToRename(contextFile: KtFile, target: KotlinTarget): PsiElement = analyze(contextFile) { + when (target) { + is KotlinTarget.Classifier -> getClassOrObjectSymbolByClassId(target.classId)?.psi!! + is KotlinTarget.Callable -> { + val callableId = target.callableId - val scope = callableId.classId - ?.let { classId -> getClassOrObjectSymbolByClassId(classId)!!.getMemberScope() } - ?: getPackageSymbolIfPackageExists(callableId.packageName)!!.getPackageScope() + val scope = callableId.classId + ?.let { classId -> getClassOrObjectSymbolByClassId(classId)!!.getMemberScope() } + ?: getPackageSymbolIfPackageExists(callableId.packageName)!!.getPackageScope() - val callablesOfProperType = scope.getCallableSymbols(callableId.callableName) - .mapNotNull { - when (target.type) { - KotlinTarget.CallableType.FUNCTION -> it as? KtFunctionSymbol - KotlinTarget.CallableType.PROPERTY -> it as? KtPropertySymbol - } + val callablesOfProperType = scope.getCallableSymbols(callableId.callableName) + .mapNotNull { + when (target.type) { + KotlinTarget.CallableType.FUNCTION -> it as? KtFunctionSymbol + KotlinTarget.CallableType.PROPERTY -> it as? KtPropertySymbol } + } - callablesOfProperType.first().psi!! - } + callablesOfProperType.first().psi!! } } } diff --git a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/GenerateK2RefactoringsTests.kt b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/GenerateK2RefactoringsTests.kt index 2e3629336eee..29ed58ba5cd1 100644 --- a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/GenerateK2RefactoringsTests.kt +++ b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/GenerateK2RefactoringsTests.kt @@ -1,6 +1,7 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.fir.testGenerator +import org.jetbrains.kotlin.idea.k2.refactoring.safeDelete.AbstractK2BindToElementTest import org.jetbrains.kotlin.idea.k2.refactoring.safeDelete.AbstractK2SafeDeleteTest import org.jetbrains.kotlin.testGenerator.model.* @@ -29,6 +30,11 @@ internal fun MutableTWorkspace.generateK2RefactoringsTests() { model("refactoring/safeDelete/deleteValueParameter/kotlinValueParameterWithJava", testMethodName = "doValueParameterTestWithJava") model("refactoring/safeDelete/deleteValueParameter/javaParameterWithKotlin", pattern = Patterns.JAVA, testMethodName = "doJavaParameterTest") } + testClass { + model("refactoring/bindToElement/call") + model("refactoring/bindToElement/callableReference") + model("refactoring/bindToElement/type") + } } // TODO enable when move refactoring works From ec02d2967f7e8588f4316705d63cebdab5bc99b9 Mon Sep 17 00:00:00 2001 From: Bart van Helvert Date: Sun, 2 Jul 2023 11:53:59 +0200 Subject: [PATCH 139/226] [kotlin] Fix empty space on right side of dialog when package is very large ^KTIJ-23273 GitOrigin-RevId: 25278bb97fab8287083276428ca9e0fc9befbd56 --- .../idea/k2/refactoring/move/K2MoveDescriptor.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.move.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/move/K2MoveDescriptor.kt b/plugins/kotlin/refactorings/kotlin.refactorings.move.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/move/K2MoveDescriptor.kt index 99098c017ad5..038b024a0e34 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.move.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/move/K2MoveDescriptor.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.move.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/move/K2MoveDescriptor.kt @@ -3,10 +3,7 @@ package org.jetbrains.kotlin.idea.k2.refactoring.move import com.intellij.openapi.util.NlsContexts import com.intellij.refactoring.BaseRefactoringProcessor -import com.intellij.ui.dsl.builder.AlignX -import com.intellij.ui.dsl.builder.AlignY -import com.intellij.ui.dsl.builder.Panel -import com.intellij.ui.dsl.builder.bindSelected +import com.intellij.ui.dsl.builder.* import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.refactoring.KotlinCommonRefactoringSettings import javax.swing.JComponent @@ -46,7 +43,7 @@ sealed class K2MoveDescriptor { fun createComboBox() { row { checkBox(text).bindSelected(setting) - } + }.layout(RowLayout.PARENT_GRID) } } @@ -57,10 +54,10 @@ sealed class K2MoveDescriptor { row { panel { settings.firstOrNull()?.forEach { settings -> settings.createComboBox() } - }.align(AlignX.LEFT).align(AlignY.TOP) + }.align(AlignY.TOP + AlignX.LEFT) panel { settings.lastOrNull()?.forEach { settings -> settings.createComboBox() } - }.align(AlignX.RIGHT).align(AlignY.TOP) + }.align(AlignY.TOP + AlignX.RIGHT) } } From 6d8c50ac0f543ec9aa25629082c3508cfa49132c Mon Sep 17 00:00:00 2001 From: Bart van Helvert Date: Sun, 2 Jul 2023 11:59:37 +0200 Subject: [PATCH 140/226] [kotlin] Fix slow operation when calculating file icons ^KTIJ-23273 GitOrigin-RevId: 1673bc1beb505aa5366a439783eeb315af979d5c --- .../idea/k2/refactoring/move/K2MoveSource.kt | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.move.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/move/K2MoveSource.kt b/plugins/kotlin/refactorings/kotlin.refactorings.move.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/move/K2MoveSource.kt index f1610e38d83e..a7fc2f589d94 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.move.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/move/K2MoveSource.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.move.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/move/K2MoveSource.kt @@ -6,11 +6,15 @@ import com.intellij.platform.backend.presentation.TargetPresentation import com.intellij.refactoring.RefactoringBundle import com.intellij.ui.CollectionListModel import com.intellij.ui.components.JBList -import com.intellij.ui.dsl.builder.* +import com.intellij.ui.dsl.builder.Align +import com.intellij.ui.dsl.builder.BottomGap +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.TopGap import com.intellij.ui.list.createTargetPresentationRenderer import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel import org.jetbrains.kotlin.psi.* +import javax.swing.Icon import javax.swing.JComponent sealed interface K2MoveSource { @@ -25,22 +29,30 @@ sealed interface K2MoveSource { context(Panel) override fun buildPanel(onError: (String?, JComponent) -> Unit) { + val project = elements.firstOrNull()?.project ?: return + + class FileInfo(val icon: Icon?, val file: KtFile) + + val fileInfos = ActionUtil.underModalProgress(project, RefactoringBundle.message("move.title")) { + elements.map { file -> FileInfo(file.getIcon(0), file) } + } + group(RefactoringBundle.message("move.files.group")) { - lateinit var list: JBList + lateinit var list: JBList row { - list = JBList(CollectionListModel(elements)) - list.cellRenderer = createTargetPresentationRenderer { file -> - TargetPresentation.builder(file.name) - .icon(file.getIcon(0)) - .locationText(file.virtualFile.parent.path) + list = JBList(CollectionListModel(fileInfos)) + list.cellRenderer = createTargetPresentationRenderer { fileInfo -> + TargetPresentation.builder(fileInfo.file.name) + .icon(fileInfo.icon) + .locationText(fileInfo.file.virtualFile.parent.path) .presentation() } cell(list).resizableColumn() } onApply { - elements = (list.model as CollectionListModel).items.toSet() + elements = (list.model as CollectionListModel).items.map { it.file }.toSet() } - }.topGap(TopGap.NONE).bottomGap(BottomGap.NONE).layout(RowLayout.PARENT_GRID).resizableRow() + }.topGap(TopGap.NONE).bottomGap(BottomGap.NONE).resizableRow() } } From d71eab2bfb982055b8f9e6903e77a04f94f7657e Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 20:03:08 +0200 Subject: [PATCH 141/226] mac: in DFM mode do not update main toolbar GitOrigin-RevId: bdceb80e6b04cd4be90e871d2a4974a199b3bc6a --- .../header/CustomHeader.kt | 11 ++- .../header/MacToolbarFrameHeader.kt | 84 +++++++++++-------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt index ed0a7c05e02a..92d9ad23510a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt @@ -39,7 +39,7 @@ import kotlin.math.roundToInt private const val HEADER_HEIGHT_DFM = 30 private const val HEADER_HEIGHT_COMPACT = 34 -private const val HEADER_HEIGHT_NORMAL = 40 +internal const val HEADER_HEIGHT_NORMAL = 40 private val windowBorderThicknessInPhysicalPx: Int = run { // Windows 10 (tested on 1809) determines the window border size by the main display scaling, rounded down. This value is @@ -125,7 +125,7 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan override fun updateUI() { super.updateUI() updateWinControlsTheme() - updateSize { computeMainActionGroups(CustomActionsSchema.getInstance()) } + updateSize(mainToolbarActionSupplier = { computeMainActionGroups(CustomActionsSchema.getInstance()) }) } protected fun updateSize(mainToolbarActionSupplier: () -> List>) { @@ -133,15 +133,20 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan return } + updatePreferredSize(isCompactHeader = { (rootPane as? IdeRootPane)?.isCompactHeader(mainToolbarActionSupplier) == true }) + } + + protected fun updatePreferredSize(isCompactHeader: () -> Boolean): Dimension { val size = preferredSize size.height = JBUI.scale( when { - (rootPane as? IdeRootPane)?.isCompactHeader(mainToolbarActionSupplier) == true -> HEADER_HEIGHT_DFM + isCompactHeader() -> HEADER_HEIGHT_DFM UISettings.getInstance().compactMode -> HEADER_HEIGHT_COMPACT else -> HEADER_HEIGHT_NORMAL } ) preferredSize = size + return size } private fun updateWinControlsTheme() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt index a32e0fe30fa3..1f7b9cad965d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt @@ -35,23 +35,23 @@ import javax.swing.JComponent import javax.swing.JFrame private const val GAP_FOR_BUTTONS = 80 -private const val DEFAULT_HEADER_HEIGHT = 40 internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, private val frame: JFrame, private val root: IdeRootPane) : CustomHeader(frame), MainFrameCustomHeader, ToolbarHolder, UISettingsListener { - private var toolbar: MainToolbar + private var toolbar: MainToolbar? private var currentComponent: JComponent private val updateRequests = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) - private var lastHeight = DEFAULT_HEADER_HEIGHT + private var lastHeight = HEADER_HEIGHT_NORMAL init { layout = AdjustableSizeCardLayout() root.addPropertyChangeListener(MacMainFrameDecorator.FULL_SCREEN, PropertyChangeListener { updateBorders() }) - toolbar = createToolBar(coroutineScope.childScope()) + val toolbar = createToolBar(coroutineScope.childScope()) + this.toolbar = toolbar add(toolbar, BorderLayout.CENTER) currentComponent = toolbar @@ -71,24 +71,40 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, } if (customTitleBar != null) { - customTitleBar.height = DEFAULT_HEADER_HEIGHT.toFloat() + customTitleBar.height = HEADER_HEIGHT_NORMAL.toFloat() JBR.getWindowDecorations()!!.setCustomTitleBar(frame, customTitleBar) } coroutineScope.launch(ModalityState.any().asContextElement()) { - initToolbar() - - updateRequests.collect { - initToolbar() + val toolbarActionGroups = computeMainActionGroups() + val isCompactHeader = root.isCompactHeader(mainToolbarActionSupplier = { toolbarActionGroups }) + if (isCompactHeader) { withContext(Dispatchers.EDT) { - toolbar.updateBackground() - updateCustomTitleBar() - revalidate() + updateVisibleComponent(isCompactHeader = true) } } + else { + toolbar.init(toolbarActionGroups, customTitleBar) + } + + updateRequests.collect { + updateState() + } } } + private suspend fun updateState() { + val toolbarActionGroups = computeMainActionGroups() + val mainToolbarActionSupplier = { toolbarActionGroups } + val isCompactHeader = root.isCompactHeader(mainToolbarActionSupplier) + + withContext(Dispatchers.EDT) { + updateVisibleComponent(isCompactHeader) + } + + toolbar?.init(toolbarActionGroups, customTitleBar) + } + private fun createToolBar(coroutineScope: CoroutineScope): MainToolbar { val toolbar = MainToolbar(coroutineScope, frame) toolbar.layoutCallBack = { updateCustomTitleBar() } @@ -116,47 +132,42 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, } } - private suspend fun initToolbar() { - val toolbarActionGroups = computeMainActionGroups() - val mainToolbarActionSupplier = { toolbarActionGroups } - val isCompactHeader = root.isCompactHeader(mainToolbarActionSupplier) - if (!isCompactHeader) { - toolbar.init(toolbarActionGroups, customTitleBar) - } - - withContext(Dispatchers.EDT) { - updateVisibleCard(isCompactHeader) - updateSize(mainToolbarActionSupplier) - } - } - override fun scheduleUpdateToolbar() { updateRequests.tryEmit(Unit) } - private fun updateVisibleCard(isCompactHeader: Boolean) { + private fun updateVisibleComponent(isCompactHeader: Boolean) { if (isCompactHeader) { + if (toolbar == null) { + return + } + remove(currentComponent) + toolbar = null val headerTitle = SimpleCustomDecorationPath(frame) headerTitle.isOpaque = false add(headerTitle, BorderLayout.CENTER) currentComponent = headerTitle updateBorders() - revalidate() - repaint() } else if (componentCount != 0 && currentComponent != toolbar) { remove(currentComponent) val coroutineScope = coroutineScope.childScope() - toolbar = createToolBar(coroutineScope) + val toolbar = createToolBar(coroutineScope) + this.toolbar = toolbar add(toolbar) currentComponent = toolbar - - updateRequests.tryEmit(Unit) - revalidate() - repaint() } + else { + return + } + + val h = updatePreferredSize(isCompactHeader = { isCompactHeader }).height + customTitleBar?.height = h.toFloat() + + revalidate() + repaint() } override fun windowStateChanged() { @@ -176,7 +187,6 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, } override fun updateCustomTitleBar() { - val height = height if (height != 0 && lastHeight != height) { customTitleBar?.let { it.height = height.toFloat() @@ -195,12 +205,12 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, border = JBUI.Borders.emptyLeft(GAP_FOR_BUTTONS) ((if (componentCount == 0) null else getComponent(0)) as? SimpleCustomDecorationPath)?.updateBorders(GAP_FOR_BUTTONS) } - toolbar.border = JBUI.Borders.empty() + toolbar?.border = JBUI.Borders.empty() } override fun updateActive() { super.updateActive() - toolbar.background = getHeaderBackground(isActive) + toolbar?.background = getHeaderBackground(isActive) } override fun uiSettingsChanged(uiSettings: UISettings) { From 06b86667e4a1d2e705888da768a7ce41fa1a12a4 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 20:15:27 +0200 Subject: [PATCH 142/226] mac: do not specify background for MainToolbar - it is a part of mac frame header GitOrigin-RevId: ac23765963cb62a2f6583a9862ab9284a1b3e7df --- .../intellij/openapi/wm/impl/IdeRootPane.kt | 7 +++---- .../header/MacToolbarFrameHeader.kt | 18 +----------------- .../header/toolbar/ToolbarFrameHeader.kt | 6 +----- .../wm/impl/headertoolbar/MainToolbar.kt | 19 +++++++++++-------- 4 files changed, 16 insertions(+), 34 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt index 17882915c503..b35cdf6eada6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt @@ -736,12 +736,11 @@ private val isDecoratedMenu: Boolean private suspend fun createToolbar(coroutineScope: CoroutineScope, frame: JFrame): JComponent { if (ExperimentalUI.isNewUI()) { val toolbar = withContext(Dispatchers.EDT) { - MainToolbar(coroutineScope, frame) + val toolbar = MainToolbar(coroutineScope = coroutineScope, frame = frame, isOpaque = true) + toolbar.border = JBUI.Borders.empty(0, 5) + toolbar } toolbar.init(computeMainActionGroups()) - withContext(Dispatchers.EDT) { - toolbar.border = JBUI.Borders.empty(0, 5) - } return toolbar } else { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt index 1f7b9cad965d..5079ccced302 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt @@ -28,8 +28,6 @@ import kotlinx.coroutines.withContext import java.awt.BorderLayout import java.awt.Color import java.awt.Graphics -import java.awt.event.ComponentAdapter -import java.awt.event.ComponentEvent import java.beans.PropertyChangeListener import javax.swing.JComponent import javax.swing.JFrame @@ -106,16 +104,7 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, } private fun createToolBar(coroutineScope: CoroutineScope): MainToolbar { - val toolbar = MainToolbar(coroutineScope, frame) - toolbar.layoutCallBack = { updateCustomTitleBar() } - toolbar.isOpaque = false - toolbar.addComponentListener(object: ComponentAdapter() { - override fun componentResized(e: ComponentEvent?) { - updateCustomTitleBar() - super.componentResized(e) - } - }) - return toolbar + return MainToolbar(coroutineScope = coroutineScope, frame = frame) } override fun paint(g: Graphics) { @@ -208,11 +197,6 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, toolbar?.border = JBUI.Borders.empty() } - override fun updateActive() { - super.updateActive() - toolbar?.background = getHeaderBackground(isActive) - } - override fun uiSettingsChanged(uiSettings: UISettings) { updateRequests.tryEmit(Unit) } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/toolbar/ToolbarFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/toolbar/ToolbarFrameHeader.kt index b0d05bfca677..20e186da60df 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/toolbar/ToolbarFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/toolbar/ToolbarFrameHeader.kt @@ -187,14 +187,10 @@ internal class ToolbarFrameHeader(private val coroutineScope: CoroutineScope, val toolbar = withContext(Dispatchers.EDT) { toolbar?.removeComponentListener(contentResizeListener) toolbarPlaceholder.removeAll() - - val toolbar = MainToolbar(coroutineScope.childScope(), frame) - toolbar.layoutCallBack = { updateCustomTitleBar() } - toolbar + MainToolbar(coroutineScope = coroutineScope.childScope(), frame = frame, layoutCallBack = { updateCustomTitleBar() }) } toolbar.init(toolbarActionGroups, customTitleBar) withContext(Dispatchers.EDT) { - toolbar.isOpaque = false toolbar.addComponentListener(contentResizeListener) this@ToolbarFrameHeader.toolbar = toolbar toolbarHeaderTitle.updateBorders(0) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbar.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbar.kt index 59ffedd65c7f..091a74b436ed 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbar.kt @@ -76,13 +76,20 @@ private class MenuButtonInToolbarMainToolbarFlavor(coroutineScope: CoroutineScop private object DefaultMainToolbarFlavor : MainToolbarFlavor -internal class MainToolbar(private val coroutineScope: CoroutineScope, frame: JFrame) : JPanel(HorizontalLayout(10)) { - var layoutCallBack: LayoutCallBack? = null +internal class MainToolbar constructor( + private val coroutineScope: CoroutineScope, + frame: JFrame, + isOpaque: Boolean = false, + background: Color? = JBUI.CurrentTheme.CustomFrameDecorations.mainToolbarBackground(true), + val layoutCallBack: LayoutCallBack? = null, +) : JPanel(HorizontalLayout(10)) { private val flavor: MainToolbarFlavor init { - updateBackground() - isOpaque = true + background?.let { + this.background = it + } + this.isOpaque = isOpaque flavor = if (IdeRootPane.isMenuButtonInToolbar) { MenuButtonInToolbarMainToolbarFlavor(headerContent = this, coroutineScope = coroutineScope, frame = frame) } @@ -92,10 +99,6 @@ internal class MainToolbar(private val coroutineScope: CoroutineScope, frame: JF ClientProperty.put(this, IdeBackgroundUtil.NO_BACKGROUND, true) } - fun updateBackground() { - background = JBUI.CurrentTheme.CustomFrameDecorations.mainToolbarBackground(true) - } - override fun getComponentGraphics(g: Graphics): Graphics = super.getComponentGraphics(IdeBackgroundUtil.getOriginalGraphics(g)) suspend fun init(actionGroups: List>, customTitleBar: WindowDecorations.CustomTitleBar? = null) { From 2d95f96ff535d84727c24b75cc2317702069c792 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 20:52:50 +0200 Subject: [PATCH 143/226] MacToolbarFrameHeader - do not extend CustomHeader (any duplicated code can be extracted to helpers, prefer composition to inheritance) GitOrigin-RevId: 102073fd597f388fb42bb302b937aaaaede3e2b0 --- .../header/CustomHeader.kt | 44 ++++--- .../header/MacToolbarFrameHeader.kt | 117 +++++++++++++----- .../ui/src/com/intellij/util/ui/JBUI.java | 8 +- 3 files changed, 115 insertions(+), 54 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt index 92d9ad23510a..dd3370ea20cd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt @@ -24,21 +24,20 @@ import com.intellij.ui.scale.ScaleContext import com.intellij.ui.scale.ScaleContextCache import com.intellij.util.ui.* import com.jetbrains.JBR -import com.jetbrains.WindowDecorations +import com.jetbrains.WindowDecorations.CustomTitleBar import org.jetbrains.annotations.ApiStatus import java.awt.* import java.awt.event.* import java.beans.PropertyChangeListener import javax.accessibility.AccessibleContext -import javax.accessibility.AccessibleRole import javax.swing.* import javax.swing.border.Border import kotlin.math.ceil import kotlin.math.floor import kotlin.math.roundToInt -private const val HEADER_HEIGHT_DFM = 30 -private const val HEADER_HEIGHT_COMPACT = 34 +internal const val HEADER_HEIGHT_DFM = 30 +internal const val HEADER_HEIGHT_COMPACT = 34 internal const val HEADER_HEIGHT_NORMAL = 40 private val windowBorderThicknessInPhysicalPx: Int = run { @@ -48,6 +47,12 @@ private val windowBorderThicknessInPhysicalPx: Int = run { floor(scale).toInt() } +internal fun updateWinControlsTheme(panel: JPanel, customTitleBar: CustomTitleBar) { + customTitleBar.putProperty("controls.dark", ColorUtil.isDark(panel.background)) + customTitleBar.putProperty("controls.foreground.normal", UIManager.getColor("WindowControls.foreground")) + customTitleBar.putProperty("controls.foreground.inactive", UIManager.getColor("WindowControls.inactiveForeground")) +} + internal sealed class CustomHeader(@JvmField internal val window: Window) : JPanel() { companion object { val H: Int @@ -106,7 +111,7 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan private var customFrameTopBorder: CustomFrameTopBorder? = null @ApiStatus.Internal - val customTitleBar: WindowDecorations.CustomTitleBar? + val customTitleBar: CustomTitleBar? protected val productIcon: JComponent by lazy { createProductIcon() @@ -124,7 +129,9 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan override fun updateUI() { super.updateUI() - updateWinControlsTheme() + customTitleBar?.let { + updateWinControlsTheme(panel = this, customTitleBar = it) + } updateSize(mainToolbarActionSupplier = { computeMainActionGroups(CustomActionsSchema.getInstance()) }) } @@ -149,13 +156,6 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan return size } - private fun updateWinControlsTheme() { - val customTitleBar = customTitleBar ?: return - customTitleBar.putProperty("controls.dark", ColorUtil.isDark(background)) - customTitleBar.putProperty("controls.foreground.normal", UIManager.getColor("WindowControls.foreground")) - customTitleBar.putProperty("controls.foreground.inactive", UIManager.getColor("WindowControls.inactiveForeground")) - } - protected open fun getHeaderBackground(active: Boolean = true) = JBUI.CurrentTheme.CustomFrameDecorations.titlePaneBackground(active) protected fun setCustomFrameTopBorder(isTopNeeded: () -> Boolean = { true }, isBottomNeeded: () -> Boolean = { false }) { @@ -214,11 +214,9 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan customTitleBar.height = (height - insets.bottom).toFloat() setCustomTitleBar(customTitleBar) } - - //border = JBUI.Borders.empty(0, customTitleBar.leftInset.toInt(), 0, customTitleBar.rightInset.toInt()) } - private fun setCustomTitleBar(titleBar: WindowDecorations.CustomTitleBar?) { + private fun setCustomTitleBar(titleBar: CustomTitleBar?) { JBR.getWindowDecorations()?.let { if (window is Dialog) { it.setCustomTitleBar(window, titleBar) @@ -239,7 +237,9 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan customFrameTopBorder?.repaintBorder() background = getHeaderBackground(isActive) - updateWinControlsTheme() + customTitleBar?.let { + updateWinControlsTheme(panel = this, customTitleBar = it) + } } protected fun close() { @@ -286,15 +286,13 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan } private inner class AccessibleCustomHeader: AccessibleJPanel() { - override fun getAccessibleRole(): AccessibleRole { - return AccessibilityUtils.GROUPED_ELEMENTS - } + override fun getAccessibleRole() = AccessibilityUtils.GROUPED_ELEMENTS } } -private class CustomFrameTopBorder(@JvmField val isTopNeeded: () -> Boolean = { true }, - @JvmField val isBottomNeeded: () -> Boolean = { false }, - @JvmField val header: CustomHeader) : Border { +internal class CustomFrameTopBorder(@JvmField val isTopNeeded: () -> Boolean = { true }, + @JvmField val isBottomNeeded: () -> Boolean = { false }, + @JvmField val header: CustomHeader) : Border { // The bottom border is a line between a window title/main menu area and the frame content. private val bottomBorderWidthLogicalPx = JBUI.scale(1) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt index 5079ccced302..daa651201c4b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MacToolbarFrameHeader.kt @@ -1,6 +1,7 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations.header +import com.intellij.accessibility.AccessibilityUtils import com.intellij.ide.ProjectWindowCustomizerService import com.intellij.ide.ui.LafManagerListener import com.intellij.ide.ui.UISettings @@ -14,11 +15,13 @@ import com.intellij.openapi.wm.impl.ToolbarHolder import com.intellij.openapi.wm.impl.customFrameDecorations.header.titleLabel.SimpleCustomDecorationPath import com.intellij.openapi.wm.impl.headertoolbar.MainToolbar import com.intellij.openapi.wm.impl.headertoolbar.computeMainActionGroups +import com.intellij.ui.UIBundle import com.intellij.ui.mac.MacFullScreenControlsManager import com.intellij.ui.mac.MacMainFrameDecorator import com.intellij.util.childScope import com.intellij.util.ui.JBUI import com.jetbrains.JBR +import com.jetbrains.WindowDecorations import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.BufferOverflow @@ -26,26 +29,49 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.awt.BorderLayout -import java.awt.Color +import java.awt.Dimension import java.awt.Graphics +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent import java.beans.PropertyChangeListener +import javax.accessibility.AccessibleContext import javax.swing.JComponent import javax.swing.JFrame +import javax.swing.JPanel private const val GAP_FOR_BUTTONS = 80 internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, private val frame: JFrame, private val root: IdeRootPane) - : CustomHeader(frame), MainFrameCustomHeader, ToolbarHolder, UISettingsListener { + : JPanel(AdjustableSizeCardLayout()), MainFrameCustomHeader, ToolbarHolder, UISettingsListener { private var toolbar: MainToolbar? private var currentComponent: JComponent private val updateRequests = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) - private var lastHeight = HEADER_HEIGHT_NORMAL + private val windowListener = object : WindowAdapter() { + override fun windowActivated(ev: WindowEvent) { + updateActive() + } + + override fun windowDeactivated(ev: WindowEvent) { + updateActive() + } + + override fun windowStateChanged(e: WindowEvent) { + updateBorders() + } + } + + private val customTitleBar: WindowDecorations.CustomTitleBar? init { - layout = AdjustableSizeCardLayout() + isOpaque = true + background = JBUI.CurrentTheme.CustomFrameDecorations.mainToolbarBackground(true) + + val windowDecorations = JBR.getWindowDecorations() + customTitleBar = windowDecorations?.createCustomTitleBar() + root.addPropertyChangeListener(MacMainFrameDecorator.FULL_SCREEN, PropertyChangeListener { updateBorders() }) val toolbar = createToolBar(coroutineScope.childScope()) @@ -70,7 +96,7 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, if (customTitleBar != null) { customTitleBar.height = HEADER_HEIGHT_NORMAL.toFloat() - JBR.getWindowDecorations()!!.setCustomTitleBar(frame, customTitleBar) + windowDecorations.setCustomTitleBar(frame, customTitleBar) } coroutineScope.launch(ModalityState.any().asContextElement()) { @@ -103,9 +129,7 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, toolbar?.init(toolbarActionGroups, customTitleBar) } - private fun createToolBar(coroutineScope: CoroutineScope): MainToolbar { - return MainToolbar(coroutineScope = coroutineScope, frame = frame) - } + private fun createToolBar(coroutineScope: CoroutineScope) = MainToolbar(coroutineScope = coroutineScope, frame = frame) override fun paint(g: Graphics) { ProjectWindowCustomizerService.getInstance().paint(window = frame, parent = this, g = g) @@ -115,6 +139,10 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, override fun updateUI() { super.updateUI() + customTitleBar?.let { + updateWinControlsTheme(panel = this, customTitleBar = it) + } + if (parent != null) { scheduleUpdateToolbar() updateBorders() @@ -159,45 +187,76 @@ internal class MacToolbarFrameHeader(private val coroutineScope: CoroutineScope, repaint() } - override fun windowStateChanged() { - super.windowStateChanged() - updateBorders() - } - override fun addNotify() { super.addNotify() + updateActive() + frame.addWindowListener(windowListener) + frame.addWindowStateListener(windowListener) updateBorders() } override fun getComponent(): JComponent = this - override fun getHeaderBackground(active: Boolean): Color { - return JBUI.CurrentTheme.CustomFrameDecorations.mainToolbarBackground(active) - } - - override fun updateCustomTitleBar() { - if (height != 0 && lastHeight != height) { - customTitleBar?.let { - it.height = height.toFloat() - } - } - updateBorders() - } - private fun updateBorders() { val isFullscreen = root.getClientProperty(MacMainFrameDecorator.FULL_SCREEN) != null + val rightGap: Int if (isFullscreen && !MacFullScreenControlsManager.enabled()) { border = JBUI.Borders.empty() - ((if (componentCount == 0) null else getComponent(0)) as? SimpleCustomDecorationPath)?.updateBorders(0) + rightGap = 0 } else { border = JBUI.Borders.emptyLeft(GAP_FOR_BUTTONS) - ((if (componentCount == 0) null else getComponent(0)) as? SimpleCustomDecorationPath)?.updateBorders(GAP_FOR_BUTTONS) + rightGap = GAP_FOR_BUTTONS + } + + val toolbar = toolbar + if (toolbar == null) { + (currentComponent as? SimpleCustomDecorationPath)?.updateBorders(rightGap) + } + else { + toolbar.border = JBUI.Borders.empty() } - toolbar?.border = JBUI.Borders.empty() } override fun uiSettingsChanged(uiSettings: UISettings) { updateRequests.tryEmit(Unit) } + + private fun updatePreferredSize(isCompactHeader: () -> Boolean): Dimension { + val size = preferredSize + size.height = JBUI.scale( + when { + isCompactHeader() -> HEADER_HEIGHT_DFM + UISettings.getInstance().compactMode -> HEADER_HEIGHT_COMPACT + else -> HEADER_HEIGHT_NORMAL + } + ) + preferredSize = size + return size + } + + override fun removeNotify() { + super.removeNotify() + frame.removeWindowListener(windowListener) + frame.removeWindowStateListener(windowListener) + } + + private fun updateActive() { + background = JBUI.CurrentTheme.CustomFrameDecorations.mainToolbarBackground(frame.isActive) + customTitleBar?.let { + updateWinControlsTheme(panel = this, customTitleBar = it) + } + } + + override fun getAccessibleContext(): AccessibleContext { + if (accessibleContext == null) { + accessibleContext = AccessibleCustomHeader() + accessibleContext.accessibleName = UIBundle.message("frame.header.accessible.group.name") + } + return accessibleContext + } + + private inner class AccessibleCustomHeader : AccessibleJPanel() { + override fun getAccessibleRole() = AccessibilityUtils.GROUPED_ELEMENTS + } } \ No newline at end of file diff --git a/platform/util/ui/src/com/intellij/util/ui/JBUI.java b/platform/util/ui/src/com/intellij/util/ui/JBUI.java index f2aa5e3f2c17..0b1830c9f038 100644 --- a/platform/util/ui/src/com/intellij/util/ui/JBUI.java +++ b/platform/util/ui/src/com/intellij/util/ui/JBUI.java @@ -506,8 +506,12 @@ public final class JBUI { public static @NotNull Color mainToolbarBackground(boolean active) { JBColor activeBG = JBColor.namedColor("MainToolbar.background", titlePaneBackground()); - JBColor inactiveBG = JBColor.namedColor("MainToolbar.inactiveBackground", activeBG); - return active ? activeBG : inactiveBG; + if (active) { + return activeBG; + } + else { + return JBColor.namedColor("MainToolbar.inactiveBackground", activeBG); + } } public static @NotNull Color titlePaneInfoForeground() { From 9c70a0f57e4eaee28205db321e2b67306776401a Mon Sep 17 00:00:00 2001 From: Fabrice Tiercelin Date: Sun, 2 Jul 2023 20:12:31 +0200 Subject: [PATCH 144/226] [lombok] IDEA-322251 New clean up: Lombok @Setter may be used GitOrigin-RevId: 72565c74033cf033bf23d866f6518602c7ad120e --- .../LombokGetterMayBeUsedInspection.java | 414 +++++------------- ...mbokGetterOrSetterMayBeUsedInspection.java | 267 +++++++++++ .../LombokSetterMayBeUsedInspection.java | 184 ++++++++ .../src/main/resources/META-INF/plugin.xml | 5 + .../LombokSetterMayBeUsed.html | 45 ++ .../messages/LombokBundle.properties | 7 +- .../LombokSetterMayBeUsedFixTest.java | 31 ++ .../LombokSetterMayBeUsedInspectionTest.java | 43 ++ ...sedWithoutLombokLibraryInspectionTest.java | 31 ++ .../afterEmptyStatement.java | 18 + .../afterParentherizedValue.java | 18 + .../beforeEmptyStatement.java | 18 + .../beforeParentherizedValue.java | 18 + .../FieldsWithSetter.java | 53 +++ .../InstanceAndStaticFields.java | 14 + .../lombokSetterMayBeUsed/NoLibrary.java | 53 +++ .../lombokSetterMayBeUsed/afterAllFields.java | 10 + .../afterAnnotatedField.java | 10 + .../afterBooleanField.java | 10 + .../afterEmptyStatement.java | 9 + .../afterFieldInInnerClass.java | 12 + .../afterFinalField.java | 18 + .../afterFinalParameter.java | 10 + .../afterFullyQualifiedAnnotation.java | 11 + .../afterFullyQualifiedThis.java | 12 + .../afterInstanceField.java | 18 + .../afterMergeJavaDoc.java | 21 + .../afterMoveJavaDoc.java | 19 + .../lombokSetterMayBeUsed/afterParamTags.java | 20 + .../afterParentherizedParameter.java | 10 + .../afterQualifiedThis.java | 11 + .../afterStaticField.java | 10 + .../lombokSetterMayBeUsed/afterThisField.java | 10 + .../afterUppercaseField.java | 18 + .../beforeAllFields.java | 14 + .../beforeAnnotatedField.java | 13 + .../beforeAnnotedMethod.java | 11 + .../beforeAnnoyingQualifier.java | 9 + .../beforeAnotherField.java | 10 + .../beforeAssignment.java | 9 + .../lombokSetterMayBeUsed/beforeBadField.java | 10 + .../beforeBadOperator.java | 9 + .../beforeBooleanField.java | 10 + .../beforeDifferentType.java | 10 + .../beforeEmptyStatement.java | 9 + .../beforeFieldInInnerClass.java | 11 + .../beforeFinalField.java | 18 + .../beforeFinalMethod.java | 10 + .../beforeFinalParameter.java | 10 + .../beforeFullyQualifiedAnnotation.java | 14 + .../beforeFullyQualifiedThis.java | 12 + .../beforeGetterMethod.java | 10 + .../beforeIgnoredParameter.java | 9 + .../beforeInheritedField.java | 13 + .../beforeInstanceField.java | 10 + .../beforeMergeJavaDoc.java | 22 + .../beforeMethodStartingWithDigit.java | 10 + .../beforeMoveJavaDoc.java | 19 + .../beforeNoFieldSet.java | 9 + .../beforeNonPublicGetter.java | 10 + .../beforeNonStaticMethod.java | 10 + .../beforeNotWritableLog.java | 12 + .../beforeParamTags.java | 20 + .../beforeParentherizedParameter.java | 10 + .../beforeQualifiedThis.java | 11 + .../beforeSetLiteral.java | 10 + .../beforeShortMethodName.java | 10 + .../beforeStaticField.java | 10 + .../beforeThisField.java | 10 + .../beforeThrowException.java | 12 + .../beforeTwoParameterMethod.java | 10 + .../beforeTwoStatements.java | 11 + .../beforeUppercaseField.java | 18 + .../beforeVarArgParameter.java | 9 + .../beforeZeroParameterMethod.java | 10 + 75 files changed, 1631 insertions(+), 301 deletions(-) create mode 100644 plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterOrSetterMayBeUsedInspection.java create mode 100644 plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedInspection.java create mode 100644 plugins/lombok/src/main/resources/inspectionDescriptions/LombokSetterMayBeUsed.html create mode 100644 plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedFixTest.java create mode 100644 plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedInspectionTest.java create mode 100644 plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayNotBeUsedWithoutLombokLibraryInspectionTest.java create mode 100644 plugins/lombok/testData/inspection/lombokGetterMayBeUsed/afterEmptyStatement.java create mode 100644 plugins/lombok/testData/inspection/lombokGetterMayBeUsed/afterParentherizedValue.java create mode 100644 plugins/lombok/testData/inspection/lombokGetterMayBeUsed/beforeEmptyStatement.java create mode 100644 plugins/lombok/testData/inspection/lombokGetterMayBeUsed/beforeParentherizedValue.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/FieldsWithSetter.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/InstanceAndStaticFields.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/NoLibrary.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterAllFields.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterAnnotatedField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterBooleanField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterEmptyStatement.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFieldInInnerClass.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFinalField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFinalParameter.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFullyQualifiedAnnotation.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFullyQualifiedThis.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterInstanceField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterMergeJavaDoc.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterMoveJavaDoc.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterParamTags.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterParentherizedParameter.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterQualifiedThis.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterStaticField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterThisField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterUppercaseField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAllFields.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnotatedField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnotedMethod.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnoyingQualifier.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnotherField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAssignment.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBadField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBadOperator.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBooleanField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeDifferentType.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeEmptyStatement.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFieldInInnerClass.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalMethod.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalParameter.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFullyQualifiedAnnotation.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFullyQualifiedThis.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeGetterMethod.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeIgnoredParameter.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeInheritedField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeInstanceField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMergeJavaDoc.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMethodStartingWithDigit.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMoveJavaDoc.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNoFieldSet.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNonPublicGetter.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNonStaticMethod.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNotWritableLog.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeParamTags.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeParentherizedParameter.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeQualifiedThis.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeSetLiteral.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeShortMethodName.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeStaticField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeThisField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeThrowException.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeTwoParameterMethod.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeTwoStatements.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeUppercaseField.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeVarArgParameter.java create mode 100644 plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeZeroParameterMethod.java diff --git a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterMayBeUsedInspection.java b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterMayBeUsedInspection.java index aaa66dbe5ee3..02d2ac274539 100644 --- a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterMayBeUsedInspection.java +++ b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterMayBeUsedInspection.java @@ -1,337 +1,151 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package de.plushnikov.intellij.plugin.inspection; -import com.intellij.codeInspection.*; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.javadoc.PsiDocTag; -import com.intellij.psi.javadoc.PsiDocToken; import com.intellij.psi.util.PsiTreeUtil; -import com.siyeh.ig.psiutils.CommentTracker; +import com.intellij.psi.util.PsiUtil; import de.plushnikov.intellij.plugin.LombokBundle; import de.plushnikov.intellij.plugin.LombokClassNames; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; import static com.intellij.util.ObjectUtils.tryCast; -public class LombokGetterMayBeUsedInspection extends LombokJavaInspectionBase implements CleanupLocalInspectionTool { - - @NotNull +public class LombokGetterMayBeUsedInspection extends LombokGetterOrSetterMayBeUsedInspection { @Override - protected PsiElementVisitor createVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { - return new LombokGetterMayBeUsedVisitor(holder, false); + @NotNull + protected String getTagName() { + return "return"; } - private static class LombokGetterMayBeUsedVisitor extends JavaElementVisitor { - private final @Nullable ProblemsHolder myHolder; - private final boolean myApplyFix; + @Override + @NotNull + protected String getJavaDocMethodMarkup() { + return "GETTER"; + } - private LombokGetterMayBeUsedVisitor(@Nullable ProblemsHolder holder, boolean applyFix) { - this.myHolder = holder; - myApplyFix = applyFix; + @Override + @NotNull + protected @NonNls String getAnnotationName() { + return LombokClassNames.GETTER; + } + + @Override + @NotNull + protected @Nls String getFieldErrorMessage(String fieldName) { + return LombokBundle.message("inspection.lombok.getter.may.be.used.display.field.message", + fieldName); + } + + @Override + @NotNull + protected @Nls String getClassErrorMessage(String className) { + return LombokBundle.message("inspection.lombok.getter.may.be.used.display.class.message", + className); + } + + @Override + protected boolean processMethod( + @NotNull PsiMethod method, + @NotNull List> instanceCandidates, + @NotNull List> staticCandidates + ) { + final PsiType returnType = method.getReturnType(); + if (!method.hasModifierProperty(PsiModifier.PUBLIC) + || method.isConstructor() + || method.hasParameters() + || method.getThrowsTypes().length != 0 + || method.hasModifierProperty(PsiModifier.FINAL) + || method.hasModifierProperty(PsiModifier.ABSTRACT) + || method.hasModifierProperty(PsiModifier.SYNCHRONIZED) + || method.hasModifierProperty(PsiModifier.NATIVE) + || method.hasModifierProperty(PsiModifier.STRICTFP) + || method.getAnnotations().length != 0 + || PsiTypes.voidType().equals(returnType) + || returnType == null + || returnType.getAnnotations().length != 0 + || !method.isWritable()) { + return false; + } + final String methodName = method.getName(); + final boolean isBooleanType = PsiTypes.booleanType().equals(returnType); + if (isBooleanType ? !methodName.startsWith("is") : !methodName.startsWith("get")) { + return false; } - @Override - public void visitJavaFile(@NotNull PsiJavaFile psiJavaFile) { + final String fieldName = StringUtil.getPropertyName(methodName); + if (StringUtil.isEmpty(fieldName)) { + return false; } - @Override - public void visitClass(@NotNull PsiClass psiClass) { - List annotatedFields = new ArrayList<>(); - List> instanceCandidates = new ArrayList<>(); - List> staticCandidates = new ArrayList<>(); - for (PsiMethod method : psiClass.getMethods()) { - processMethod(method, instanceCandidates, staticCandidates); - } - boolean isGetterAtClassLevel = true; - for (PsiField field : psiClass.getFields()) { - PsiAnnotation annotation = field.getAnnotation(LombokClassNames.GETTER); - if (annotation != null) { - if (!annotation.getAttributes().isEmpty()) { - isGetterAtClassLevel = false; - } - else { - annotatedFields.add(field); - } - break; - } - if (!field.hasModifierProperty(PsiModifier.STATIC)) { - boolean found = false; - for (Pair instanceCandidate : instanceCandidates) { - if (field.equals(instanceCandidate.getFirst())) { - found = true; - break; - } - } - isGetterAtClassLevel &= found; - } - } - List> allCandidates = new ArrayList<>(staticCandidates); - if (isGetterAtClassLevel && (!instanceCandidates.isEmpty() || !annotatedFields.isEmpty())) { - warnOrFix(psiClass, instanceCandidates, annotatedFields); - } - else { - allCandidates.addAll(instanceCandidates); - } - for (Pair candidate : allCandidates) { - warnOrFix(candidate.getFirst(), candidate.getSecond()); - } + if (method.getBody() == null) { + return false; } - - public void visitMethodForFix(@NotNull PsiMethod psiMethod) { - List> fieldsAndMethods = new ArrayList<>(); - if (!processMethod(psiMethod, fieldsAndMethods, fieldsAndMethods)) return; - if (!fieldsAndMethods.isEmpty()) { - final Pair psiFieldPsiMethodPair = fieldsAndMethods.get(0); - warnOrFix(psiFieldPsiMethodPair.getFirst(), psiFieldPsiMethodPair.getSecond()); - } + final PsiStatement @NotNull [] methodStatements = Arrays.stream(method.getBody().getStatements()).filter(e -> !(e instanceof PsiEmptyStatement)).toArray(PsiStatement[]::new); + if (methodStatements.length != 1) { + return false; } - - private static boolean processMethod( - @NotNull PsiMethod method, - @NotNull List> instanceCandidates, - @NotNull List> staticCandidates - ) { - final PsiType returnType = method.getReturnType(); - if (!method.hasModifierProperty(PsiModifier.PUBLIC) - || method.isConstructor() - || method.hasParameters() - || method.getThrowsTypes().length != 0 - || method.hasModifierProperty(PsiModifier.FINAL) - || method.hasModifierProperty(PsiModifier.ABSTRACT) - || method.hasModifierProperty(PsiModifier.SYNCHRONIZED) - || method.hasModifierProperty(PsiModifier.NATIVE) - || method.hasModifierProperty(PsiModifier.STRICTFP) - || method.getAnnotations().length != 0 - || PsiTypes.voidType().equals(returnType) - || returnType == null - || returnType.getAnnotations().length != 0 - || !method.isWritable()) { + final PsiReturnStatement returnStatement = tryCast(methodStatements[0], PsiReturnStatement.class); + if (returnStatement == null) { + return false; + } + final PsiReferenceExpression targetRef = tryCast( + PsiUtil.skipParenthesizedExprDown(returnStatement.getReturnValue()), PsiReferenceExpression.class); + if (targetRef == null) { + return false; + } + final @Nullable PsiExpression qualifier = targetRef.getQualifierExpression(); + final @Nullable PsiThisExpression thisExpression = tryCast(qualifier, PsiThisExpression.class); + final PsiClass psiClass = PsiTreeUtil.getParentOfType(method, PsiClass.class); + if (psiClass == null) { + return false; + } + if (qualifier != null) { + if (thisExpression == null) { return false; - } - - final String methodName = method.getName(); - final boolean isBooleanType = PsiTypes.booleanType().equals(returnType); - if (isBooleanType ? !methodName.startsWith("is") : !methodName.startsWith("get")) { - return false; - } - - final String fieldName = StringUtil.getPropertyName(methodName); - if (StringUtil.isEmpty(fieldName)) { - return false; - } - - if (method.getBody() == null) { - return false; - } - final PsiStatement @NotNull [] methodStatements = method.getBody().getStatements(); - if (methodStatements.length != 1) { - return false; - } - final PsiReturnStatement returnStatement = tryCast(methodStatements[0], PsiReturnStatement.class); - if (returnStatement == null) { - return false; - } - final PsiReferenceExpression fieldRef = tryCast(returnStatement.getReturnValue(), PsiReferenceExpression.class); - if (fieldRef == null) { - return false; - } - final @Nullable PsiExpression qualifier = fieldRef.getQualifierExpression(); - final @Nullable PsiThisExpression thisExpression = tryCast(qualifier, PsiThisExpression.class); - final PsiClass psiClass = PsiTreeUtil.getParentOfType(method, PsiClass.class); - if (psiClass == null) { - return false; - } - if (qualifier != null) { - if (thisExpression == null) { + } else if (thisExpression.getQualifier() != null) { + if (!thisExpression.getQualifier().isReferenceTo(psiClass)) { return false; } - else if (thisExpression.getQualifier() != null) { - if (!thisExpression.getQualifier().isReferenceTo(psiClass)) { - return false; - } - } - } - final @Nullable String identifier = fieldRef.getReferenceName(); - if (!fieldName.equals(identifier) && !StringUtil.capitalize(fieldName).equals(identifier)) { - return false; - } - - final boolean isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC); - final PsiField field = psiClass.findFieldByName(identifier, false); - if (field == null - || !field.isWritable() - || isMethodStatic != field.hasModifierProperty(PsiModifier.STATIC) - || !field.getType().equals(returnType)) { - return false; - } - if (isMethodStatic) { - staticCandidates.add(Pair.pair(field, method)); - } - else { - instanceCandidates.add(Pair.pair(field, method)); - } - return true; - } - - private void warnOrFix( - @NotNull PsiClass psiClass, - @NotNull List> fieldsAndMethods, - @NotNull List annotatedFields - ) { - if (myHolder != null) { - final LocalQuickFix fix = new LombokGetterMayBeUsedFix(Objects.requireNonNull(psiClass.getName())); - final PsiIdentifier psiClassNameIdentifier = psiClass.getNameIdentifier(); - myHolder.registerProblem(psiClass, - LombokBundle.message("inspection.lombok.getter.may.be.used.display.class.message", - psiClass.getName()), - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, - psiClassNameIdentifier != null ? psiClassNameIdentifier.getTextRangeInParent() : psiClass.getTextRange(), - fix); - } - else if (myApplyFix) { - LombokGetterMayBeUsedFix.effectivelyDoFix(psiClass, fieldsAndMethods, annotatedFields); } } - - private void warnOrFix(@NotNull PsiField field, @NotNull PsiMethod method) { - if (myHolder != null) { - final LocalQuickFix fix = new LombokGetterMayBeUsedFix(field.getName()); - myHolder.registerProblem(method, - LombokBundle.message("inspection.lombok.getter.may.be.used.display.field.message", - field.getName()), fix); - } - else if (myApplyFix) { - LombokGetterMayBeUsedFix.effectivelyDoFix(field, method); - } + final @Nullable String fieldIdentifier = targetRef.getReferenceName(); + if (!fieldName.equals(fieldIdentifier) && !StringUtil.capitalize(fieldName).equals(fieldIdentifier)) { + return false; } + + final boolean isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC); + final PsiField field = psiClass.findFieldByName(fieldIdentifier, false); + if (field == null + || !field.isWritable() + || isMethodStatic != field.hasModifierProperty(PsiModifier.STATIC) + || !field.getType().equals(returnType)) { + return false; + } + if (isMethodStatic) { + staticCandidates.add(Pair.pair(field, method)); + } else { + instanceCandidates.add(Pair.pair(field, method)); + } + return true; } - private static class LombokGetterMayBeUsedFix implements LocalQuickFix { - private final @NotNull String myText; - - private LombokGetterMayBeUsedFix(@NotNull String text) { - myText = text; - } - - @Nls(capitalization = Nls.Capitalization.Sentence) - @NotNull - @Override - public String getName() { - return LombokBundle.message("inspection.lombok.getter.may.be.used.display.fix.name", myText); - } - - @Nls(capitalization = Nls.Capitalization.Sentence) - @NotNull - @Override - public String getFamilyName() { - return LombokBundle.message("inspection.lombok.getter.may.be.used.display.fix.family.name"); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - final PsiElement element = descriptor.getPsiElement(); - if (element instanceof PsiMethod) { - new LombokGetterMayBeUsedVisitor(null, true).visitMethodForFix((PsiMethod)element); - } - else if (element instanceof PsiClass) { - new LombokGetterMayBeUsedVisitor(null, true).visitClass((PsiClass)element); - } - } - - private static void effectivelyDoFix(@NotNull PsiField field, @NotNull PsiMethod method) { - final PsiModifierList modifierList = field.getModifierList(); - if (modifierList == null) { - return; - } - Project project = field.getProject(); - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final PsiAnnotation annotation = factory.createAnnotationFromText("@" + LombokClassNames.GETTER, field); - JavaCodeStyleManager.getInstance(project).shortenClassReferences(annotation); - modifierList.addAfter(annotation, null); - removeMethodAndMoveJavaDoc(field, method); - } - - public static void effectivelyDoFix(@NotNull PsiClass aClass, @NotNull List> fieldsAndMethods, - @NotNull List annotatedFields) { - Project project = aClass.getProject(); - for (Pair fieldAndMethod : fieldsAndMethods) { - PsiField field = fieldAndMethod.getFirst(); - PsiMethod method = fieldAndMethod.getSecond(); - removeMethodAndMoveJavaDoc(field, method); - } - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final PsiAnnotation newAnnotation = factory.createAnnotationFromText("@" + LombokClassNames.GETTER, aClass); - JavaCodeStyleManager.getInstance(project).shortenClassReferences(newAnnotation); - final PsiModifierList modifierList = aClass.getModifierList(); - if (modifierList == null) { - return; - } - modifierList.addAfter(newAnnotation, null); - for (PsiField annotatedField : annotatedFields) { - PsiAnnotation oldAnnotation = annotatedField.getAnnotation(LombokClassNames.GETTER); - if (oldAnnotation != null) { - new CommentTracker().deleteAndRestoreComments(oldAnnotation); - } - } - } - - private static void removeMethodAndMoveJavaDoc(@NotNull PsiField field, @NotNull PsiMethod method) { - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(field.getProject()); - CommentTracker tracker = new CommentTracker(); - PsiDocComment methodJavaDoc = method.getDocComment(); - if (methodJavaDoc != null) { - tracker.text(methodJavaDoc); - PsiDocComment fieldJavaDoc = field.getDocComment(); - List methodJavaDocTokens = Arrays.stream(methodJavaDoc.getChildren()) - .filter(e -> e instanceof PsiDocToken) - .map(PsiElement::getText) - .filter(text -> !text.matches("\\s*\\*\\s*")) - .toList(); - methodJavaDocTokens = methodJavaDocTokens.subList(1, methodJavaDocTokens.size() - 1); - String javaDocGetterText = String.join("\n* ", methodJavaDocTokens); - PsiDocTag[] returnTags = methodJavaDoc.findTagsByName("return"); - if (fieldJavaDoc == null) { - if (javaDocGetterText.isEmpty()) { - fieldJavaDoc = factory.createDocCommentFromText("/**\n*/"); - } - else { - fieldJavaDoc = factory.createDocCommentFromText("/**\n* -- GETTER --\n* " + javaDocGetterText + "\n*/"); - } - for (PsiDocTag returnTag : returnTags) { - fieldJavaDoc.add(returnTag); - } - field.getParent().addBefore(fieldJavaDoc, field); - } - else { - @NotNull PsiElement @NotNull [] fieldJavaDocChildren = Arrays.stream(fieldJavaDoc.getChildren()) - .filter(e -> e instanceof PsiDocToken) - .toArray(PsiElement[]::new); - @NotNull PsiElement fieldJavaDocChild = fieldJavaDocChildren[fieldJavaDocChildren.length - 2]; - PsiDocComment newMethodJavaDoc = factory.createDocCommentFromText("/**\n* -- GETTER --\n* " + javaDocGetterText + "\n*/"); - PsiElement[] tokens = newMethodJavaDoc.getChildren(); - for (int i = tokens.length - 2; 0 < i; i--) { - fieldJavaDoc.addAfter(tokens[i], fieldJavaDocChild); - } - for (PsiDocTag returnTag : returnTags) { - fieldJavaDoc.add(returnTag); - } - } - methodJavaDoc.delete(); - } - tracker.delete(method); - tracker.insertCommentsBefore(field); - } + @Override + @NotNull + protected @Nls String getFixName(String text) { + return LombokBundle.message("inspection.lombok.getter.may.be.used.display.fix.name", text); } -} + + @Override + @NotNull + protected @Nls String getFixFamilyName() { + return LombokBundle.message("inspection.lombok.getter.may.be.used.display.fix.family.name"); + } +} \ No newline at end of file diff --git a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterOrSetterMayBeUsedInspection.java b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterOrSetterMayBeUsedInspection.java new file mode 100644 index 000000000000..e5735f9643cd --- /dev/null +++ b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterOrSetterMayBeUsedInspection.java @@ -0,0 +1,267 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package de.plushnikov.intellij.plugin.inspection; + +import com.intellij.codeInspection.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.javadoc.PsiDocTag; +import com.intellij.psi.javadoc.PsiDocToken; +import com.siyeh.ig.psiutils.CommentTracker; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJavaInspectionBase implements CleanupLocalInspectionTool { + + @NotNull + @Override + protected PsiElementVisitor createVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { + return new LombokGetterOrSetterMayBeUsedVisitor(holder, null); + } + + private class LombokGetterOrSetterMayBeUsedVisitor extends JavaElementVisitor { + private final @Nullable ProblemsHolder myHolder; + + private final @Nullable LombokGetterOrSetterMayBeUsedInspection.LombokGetterOrSetterMayBeUsedFix myLombokGetterOrSetterMayBeUsedFix; + + private LombokGetterOrSetterMayBeUsedVisitor( + @Nullable ProblemsHolder holder, + @Nullable LombokGetterOrSetterMayBeUsedInspection.LombokGetterOrSetterMayBeUsedFix lombokGetterOrSetterMayBeUsedFix + ) { + this.myHolder = holder; + this.myLombokGetterOrSetterMayBeUsedFix = lombokGetterOrSetterMayBeUsedFix; + } + + @Override + public void visitJavaFile(@NotNull PsiJavaFile psiJavaFile) { + } + + @Override + public void visitClass(@NotNull PsiClass psiClass) { + List annotatedFields = new ArrayList<>(); + List> instanceCandidates = new ArrayList<>(); + List> staticCandidates = new ArrayList<>(); + for (PsiMethod method : psiClass.getMethods()) { + processMethod(method, instanceCandidates, staticCandidates); + } + boolean isLombokAnnotationAtClassLevel = true; + for (PsiField field : psiClass.getFields()) { + PsiAnnotation annotation = field.getAnnotation(getAnnotationName()); + if (annotation != null) { + if (!annotation.getAttributes().isEmpty()) { + isLombokAnnotationAtClassLevel = false; + } else { + annotatedFields.add(field); + } + break; + } + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + boolean found = false; + for (Pair instanceCandidate : instanceCandidates) { + if (field.equals(instanceCandidate.getFirst())) { + found = true; + break; + } + } + isLombokAnnotationAtClassLevel &= found; + } + } + List> allCandidates = new ArrayList<>(staticCandidates); + if (isLombokAnnotationAtClassLevel && (!instanceCandidates.isEmpty() || !annotatedFields.isEmpty()) ) { + warnOrFix(psiClass, instanceCandidates, annotatedFields); + } else { + allCandidates.addAll(instanceCandidates); + } + for (Pair candidate : allCandidates) { + warnOrFix(candidate.getFirst(), candidate.getSecond()); + } + } + + public void visitMethodForFix(@NotNull PsiMethod psiMethod) { + List> fieldsAndMethods = new ArrayList<>(); + if (!processMethod(psiMethod, fieldsAndMethods, fieldsAndMethods)) return; + if (!fieldsAndMethods.isEmpty()) { + final Pair psiFieldPsiMethodPair = fieldsAndMethods.get(0); + warnOrFix(psiFieldPsiMethodPair.getFirst(), psiFieldPsiMethodPair.getSecond()); + } + } + + private void warnOrFix( + @NotNull PsiClass psiClass, + @NotNull List> fieldsAndMethods, + @NotNull List annotatedFields + ) { + if (myHolder != null) { + String className = psiClass.getName(); + final PsiIdentifier psiClassNameIdentifier = psiClass.getNameIdentifier(); + final LocalQuickFix fix = new LombokGetterOrSetterMayBeUsedFix(Objects.requireNonNull(className)); + myHolder.registerProblem(psiClass, + getClassErrorMessage(className), + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + psiClassNameIdentifier != null ? psiClassNameIdentifier.getTextRangeInParent() : psiClass.getTextRange(), + fix); + } else if (myLombokGetterOrSetterMayBeUsedFix != null) { + myLombokGetterOrSetterMayBeUsedFix.effectivelyDoFix(psiClass, fieldsAndMethods, annotatedFields); + } + } + + private void warnOrFix(@NotNull PsiField field, @NotNull PsiMethod method) { + if (myHolder != null) { + String fieldName = field.getName(); + final LocalQuickFix fix = new LombokGetterOrSetterMayBeUsedFix(fieldName); + myHolder.registerProblem(method, + getFieldErrorMessage(fieldName), fix); + } else if (myLombokGetterOrSetterMayBeUsedFix != null) { + myLombokGetterOrSetterMayBeUsedFix.effectivelyDoFix(field, method); + } + } + } + + private class LombokGetterOrSetterMayBeUsedFix implements LocalQuickFix { + private final @NotNull String myText; + private Project project; + + private LombokGetterOrSetterMayBeUsedFix(@NotNull String text) { + myText = text; + } + + @Nls(capitalization = Nls.Capitalization.Sentence) + @NotNull + @Override + public String getName() { + return getFixName(myText); + } + + @Nls(capitalization = Nls.Capitalization.Sentence) + @NotNull + @Override + public String getFamilyName() { + return getFixFamilyName(); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + this.project = project; + final PsiElement element = descriptor.getPsiElement(); + if (element instanceof PsiMethod) { + new LombokGetterOrSetterMayBeUsedVisitor(null, this).visitMethodForFix((PsiMethod)element); + } else if (element instanceof PsiClass) { + new LombokGetterOrSetterMayBeUsedVisitor(null, this).visitClass((PsiClass)element); + } + } + + private void effectivelyDoFix(@NotNull PsiField field, @NotNull PsiMethod method) { + if (!addLombokAnnotation(field)) return; + removeMethodAndMoveJavaDoc(field, method); + } + + public void effectivelyDoFix(@NotNull PsiClass aClass, @NotNull List> fieldsAndMethods, + @NotNull List annotatedFields) { + if (!addLombokAnnotation(aClass)) return; + for (Pair fieldAndMethod : fieldsAndMethods) { + PsiField field = fieldAndMethod.getFirst(); + PsiMethod method = fieldAndMethod.getSecond(); + removeMethodAndMoveJavaDoc(field, method); + } + for (PsiField annotatedField : annotatedFields) { + PsiAnnotation oldAnnotation = annotatedField.getAnnotation(getAnnotationName()); + if (oldAnnotation != null) { + new CommentTracker().deleteAndRestoreComments(oldAnnotation); + } + } + } + + private boolean addLombokAnnotation(@NotNull PsiModifierListOwner fieldOrClass) { + final PsiModifierList modifierList = fieldOrClass.getModifierList(); + if (modifierList == null) { + return false; + } + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + final PsiAnnotation annotation = factory.createAnnotationFromText("@"+getAnnotationName(), fieldOrClass); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(annotation); + modifierList.addAfter(annotation, null); + return true; + } + + private void removeMethodAndMoveJavaDoc(@NotNull PsiField field, @NotNull PsiMethod method) { + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + CommentTracker tracker = new CommentTracker(); + PsiDocComment methodJavaDoc = method.getDocComment(); + if (methodJavaDoc != null) { + tracker.text(methodJavaDoc); + PsiDocComment fieldJavaDoc = field.getDocComment(); + List methodJavaDocTokens = Arrays.stream(methodJavaDoc.getChildren()) + .filter(e -> e instanceof PsiDocToken) + .map(PsiElement::getText) + .filter(text -> !text.matches("\\s*\\*\\s*")) + .toList(); + methodJavaDocTokens = methodJavaDocTokens.subList(1, methodJavaDocTokens.size() - 1); + String javaDocMethodText = String.join("\n* ", methodJavaDocTokens); + PsiDocTag[] methodTags = methodJavaDoc.findTagsByName(getTagName()); + if (fieldJavaDoc == null) { + if (javaDocMethodText.isEmpty()) { + fieldJavaDoc = factory.createDocCommentFromText("/**\n*/"); + } else { + fieldJavaDoc = factory.createDocCommentFromText("/**\n* -- " + getJavaDocMethodMarkup() + " --\n* " + javaDocMethodText + "\n*/"); + } + for (PsiDocTag methodTag : methodTags) { + fieldJavaDoc.add(methodTag); + } + field.getParent().addBefore(fieldJavaDoc, field); + } else { + @NotNull PsiElement @NotNull [] fieldJavaDocChildren = Arrays.stream(fieldJavaDoc.getChildren()) + .filter(e -> e instanceof PsiDocToken) + .toArray(PsiElement[]::new); + @NotNull PsiElement fieldJavaDocChild = fieldJavaDocChildren[fieldJavaDocChildren.length - 2]; + PsiDocComment newMethodJavaDoc = factory.createDocCommentFromText("/**\n* -- " + getJavaDocMethodMarkup() + " --\n* " + javaDocMethodText + "\n*/"); + PsiElement[] tokens = newMethodJavaDoc.getChildren(); + for (int i = tokens.length - 2; 0 < i; i--) { + fieldJavaDoc.addAfter(tokens[i], fieldJavaDocChild); + } + for (PsiDocTag methodTag : methodTags) { + fieldJavaDoc.add(methodTag); + } + } + methodJavaDoc.delete(); + } + tracker.delete(method); + tracker.insertCommentsBefore(field); + } + } + + @NotNull + protected abstract String getTagName(); + + @NotNull + protected abstract String getJavaDocMethodMarkup(); + + @NotNull + protected abstract @NonNls String getAnnotationName(); + + @NotNull + protected abstract @Nls String getFieldErrorMessage(String fieldName); + + @NotNull + protected abstract @Nls String getClassErrorMessage(String className); + + protected abstract boolean processMethod( + @NotNull PsiMethod method, + @NotNull List> instanceCandidates, + @NotNull List> staticCandidates + ); + + @NotNull + protected abstract @Nls String getFixName(String text); + + @NotNull + protected abstract @Nls String getFixFamilyName(); +} diff --git a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedInspection.java b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedInspection.java new file mode 100644 index 000000000000..22d89cd3e647 --- /dev/null +++ b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedInspection.java @@ -0,0 +1,184 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package de.plushnikov.intellij.plugin.inspection; + +import com.intellij.lang.jvm.JvmModifier; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import de.plushnikov.intellij.plugin.LombokBundle; +import de.plushnikov.intellij.plugin.LombokClassNames; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; + +import static com.intellij.util.ObjectUtils.tryCast; + +public class LombokSetterMayBeUsedInspection extends LombokGetterOrSetterMayBeUsedInspection { + @Override + @NotNull + protected String getTagName() { + return "param"; + } + + @Override + @NotNull + protected String getJavaDocMethodMarkup() { + return "SETTER"; + } + + @Override + @NotNull + protected @NonNls String getAnnotationName() { + return LombokClassNames.SETTER; + } + + @Override + @NotNull + protected @Nls String getFieldErrorMessage(String fieldName) { + return LombokBundle.message("inspection.lombok.setter.may.be.used.display.field.message", + fieldName); + } + + @Override + @NotNull + protected @Nls String getClassErrorMessage(String className) { + return LombokBundle.message("inspection.lombok.setter.may.be.used.display.class.message", + className); + } + + @Override + protected boolean processMethod( + @NotNull PsiMethod method, + @NotNull List> instanceCandidates, + @NotNull List> staticCandidates + ) { + if (!method.hasModifierProperty(PsiModifier.PUBLIC) + || method.isConstructor() + || !method.hasParameters() + || method.getParameterList().getParameters().length != 1 + || 0 < method.getThrowsTypes().length + || method.hasModifierProperty(PsiModifier.FINAL) + || method.hasModifierProperty(PsiModifier.ABSTRACT) + || method.hasModifierProperty(PsiModifier.SYNCHRONIZED) + || method.hasModifierProperty(PsiModifier.NATIVE) + || method.hasModifierProperty(PsiModifier.STRICTFP) + || 0 < method.getAnnotations().length + || !PsiTypes.voidType().equals(method.getReturnType()) + || !method.isWritable()) { + return false; + } + final PsiParameter parameter = method.getParameterList().getParameters()[0]; + if ( + parameter.isVarArgs() + || ( + parameter.getModifierList() != null + && 0 < parameter.getModifierList().getChildren().length + && (parameter.getModifierList().getChildren().length != 1 || !parameter.hasModifier(JvmModifier.FINAL)) + ) + || 0 < parameter.getAnnotations().length + ) { + return false; + } + final PsiType parameterType = parameter.getType(); + + final String methodName = method.getName(); + if (!methodName.startsWith("set")) { + return false; + } + + final String fieldName = StringUtil.getPropertyName(methodName); + if (StringUtil.isEmpty(fieldName)) { + return false; + } + + if (method.getBody() == null) { + return false; + } + final PsiStatement @NotNull [] methodStatements = Arrays.stream(method.getBody().getStatements()).filter(e -> !(e instanceof PsiEmptyStatement)).toArray(PsiStatement[]::new); + if (methodStatements.length != 1) { + return false; + } + final PsiExpressionStatement assignmentStatement = tryCast(methodStatements[0], PsiExpressionStatement.class); + if (assignmentStatement == null) { + return false; + } + final PsiAssignmentExpression assignment = tryCast(assignmentStatement.getExpression(), PsiAssignmentExpression.class); + if (assignment == null || assignment.getOperationTokenType() != JavaTokenType.EQ) { + return false; + } + final PsiReferenceExpression sourceRef = tryCast(PsiUtil.skipParenthesizedExprDown(assignment.getRExpression()), PsiReferenceExpression.class); + if (sourceRef == null || sourceRef.getQualifierExpression() != null) { + return false; + } + final @Nullable String paramIdentifier = sourceRef.getReferenceName(); + if (paramIdentifier == null) { + return false; + } + if (!paramIdentifier.equals(parameter.getName())) { + return false; + } + final PsiReferenceExpression targetRef = tryCast(assignment.getLExpression(), PsiReferenceExpression.class); + if (targetRef == null) { + return false; + } + final @Nullable PsiExpression qualifier = targetRef.getQualifierExpression(); + final @Nullable PsiThisExpression thisExpression = tryCast(qualifier, PsiThisExpression.class); + final PsiClass psiClass = PsiTreeUtil.getParentOfType(method, PsiClass.class); + if (psiClass == null) { + return false; + } + if (qualifier != null) { + if (thisExpression == null) { + return false; + } else if (thisExpression.getQualifier() != null) { + if (!thisExpression.getQualifier().isReferenceTo(psiClass)) { + return false; + } + } + } + final @Nullable String fieldIdentifier = targetRef.getReferenceName(); + if (fieldIdentifier == null) { + return false; + } + if (!fieldName.equals(fieldIdentifier) && !StringUtil.capitalize(fieldName).equals(fieldIdentifier)) { + return false; + } + if (qualifier == null + && paramIdentifier.equals(fieldIdentifier)) { + return false; + } + + final boolean isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC); + final PsiField field = psiClass.findFieldByName(fieldIdentifier, false); + if (field == null + || !field.isWritable() + || isMethodStatic != field.hasModifierProperty(PsiModifier.STATIC) + || !field.getType().equals(parameterType)) { + return false; + } + if (isMethodStatic) { + staticCandidates.add(Pair.pair(field, method)); + } else { + instanceCandidates.add(Pair.pair(field, method)); + } + return true; + } + + @Override + @NotNull + protected @Nls String getFixName(String text) { + return LombokBundle.message("inspection.lombok.setter.may.be.used.display.fix.name", text); + } + + @Override + @NotNull + protected @Nls String getFixFamilyName() { + return LombokBundle.message("inspection.lombok.setter.may.be.used.display.fix.family.name"); + } +} diff --git a/plugins/lombok/src/main/resources/META-INF/plugin.xml b/plugins/lombok/src/main/resources/META-INF/plugin.xml index 873c72ca7fc6..77f798226c86 100644 --- a/plugins/lombok/src/main/resources/META-INF/plugin.xml +++ b/plugins/lombok/src/main/resources/META-INF/plugin.xml @@ -185,6 +185,11 @@ groupBundle="messages.InspectionsBundle" groupKey="group.names.verbose.or.redundant.code.constructs" implementationClass="de.plushnikov.intellij.plugin.inspection.LombokGetterMayBeUsedInspection" cleanupTool="true"/> + + + +Reports standard setter method that can be replaced by the lombok @Setter annotation. +

Example:

+

+  import java.util.Date;
+
+  public class MyClass {
+    /**
+     * The process date.
+     */
+    private Date processDate;
+
+    /**
+     * Sets the date.
+     *
+     * @param The date
+     */
+    public void setProcessDate(Date param) {
+      processDate = param;
+    }
+  }
+
+

After the quick-fix/cleanup is applied:

+

+  import lombok.Setter;
+  import java.util.Date;
+
+  @Setter
+  public class MyClass {
+    /**
+     * The process date.
+     * -- SETTER --
+     * Sets the date.
+     *
+     * @param The date
+     */
+    private Date processDate;
+  }
+
+

It only reports when the lombok library is configured. To unlombok, see the lombok site.

+ +

New in 2023.2

+ + \ No newline at end of file diff --git a/plugins/lombok/src/main/resources/messages/LombokBundle.properties b/plugins/lombok/src/main/resources/messages/LombokBundle.properties index 6f5f0c6a0fe5..7382beca0c9d 100644 --- a/plugins/lombok/src/main/resources/messages/LombokBundle.properties +++ b/plugins/lombok/src/main/resources/messages/LombokBundle.properties @@ -186,4 +186,9 @@ inspection.lombok.getter.may.be.used.display.name=Lombok @Getter may be used inspection.lombok.getter.may.be.used.display.class.message=Class ''{0}'' may use Lombok @Getter inspection.lombok.getter.may.be.used.display.field.message=Field ''{0}'' may have Lombok @Getter inspection.lombok.getter.may.be.used.display.fix.family.name=Replace explicit getter method with Lombok @Getter -inspection.lombok.getter.may.be.used.display.fix.name=Use lombok @Getter for ''{0}'' \ No newline at end of file +inspection.lombok.getter.may.be.used.display.fix.name=Use lombok @Getter for ''{0}'' +inspection.lombok.setter.may.be.used.display.name=Lombok @Setter may be used +inspection.lombok.setter.may.be.used.display.class.message=Class ''{0}'' may use Lombok @Setter +inspection.lombok.setter.may.be.used.display.field.message=Field ''{0}'' may have Lombok @Setter +inspection.lombok.setter.may.be.used.display.fix.family.name=Replace explicit setter method with Lombok @Setter +inspection.lombok.setter.may.be.used.display.fix.name=Use lombok @Setter for ''{0}'' \ No newline at end of file diff --git a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedFixTest.java b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedFixTest.java new file mode 100644 index 000000000000..255f594b6658 --- /dev/null +++ b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedFixTest.java @@ -0,0 +1,31 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package de.plushnikov.intellij.plugin.inspection; + +import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase; +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.openapi.application.PathManager; +import com.intellij.testFramework.LightProjectDescriptor; +import de.plushnikov.intellij.plugin.LombokTestUtil; +import org.jetbrains.annotations.NotNull; + +public class LombokSetterMayBeUsedFixTest extends LightQuickFixParameterizedTestCase { + @Override + protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() { + return new LocalInspectionTool[]{new LombokSetterMayBeUsedInspection()}; + } + + @Override + protected @NotNull String getTestDataPath() { + return PathManager.getCommunityHomePath() + "/plugins/lombok/testData"; + } + + @Override + protected String getBasePath() { + return "/inspection/lombokSetterMayBeUsed"; + } + + @Override + protected @NotNull LightProjectDescriptor getProjectDescriptor() { + return LombokTestUtil.LOMBOK_NEW_DESCRIPTOR; + } +} diff --git a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedInspectionTest.java b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedInspectionTest.java new file mode 100644 index 000000000000..9c14647ca7a7 --- /dev/null +++ b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayBeUsedInspectionTest.java @@ -0,0 +1,43 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package de.plushnikov.intellij.plugin.inspection; + +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.openapi.application.PathManager; +import com.intellij.testFramework.LightProjectDescriptor; +import de.plushnikov.intellij.plugin.LombokTestUtil; +import org.jetbrains.annotations.NotNull; + +public class LombokSetterMayBeUsedInspectionTest extends LightDaemonAnalyzerTestCase { + @Override + protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() { + return new LocalInspectionTool[]{new LombokSetterMayBeUsedInspection()}; + } + + @Override + protected @NotNull LightProjectDescriptor getProjectDescriptor() { + return LombokTestUtil.LOMBOK_NEW_DESCRIPTOR; + } + + @Override + protected @NotNull String getTestDataPath() { + return PathManager.getCommunityHomePath() + "/plugins/lombok/testData"; + } + + @NotNull + private String getFilePath() { + return "/inspection/lombokSetterMayBeUsed/" + getTestName(false) + ".java"; + } + + private void doTest() { + doTest(getFilePath(), true, false); + } + + public void testFieldsWithSetter() { + doTest(); + } + + public void testInstanceAndStaticFields() { + doTest(); + } +} diff --git a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayNotBeUsedWithoutLombokLibraryInspectionTest.java b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayNotBeUsedWithoutLombokLibraryInspectionTest.java new file mode 100644 index 000000000000..827cc7552b66 --- /dev/null +++ b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/inspection/LombokSetterMayNotBeUsedWithoutLombokLibraryInspectionTest.java @@ -0,0 +1,31 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package de.plushnikov.intellij.plugin.inspection; + +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.openapi.application.PathManager; +import org.jetbrains.annotations.NotNull; + +public class LombokSetterMayNotBeUsedWithoutLombokLibraryInspectionTest extends LightDaemonAnalyzerTestCase { + @Override + protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() { + return new LocalInspectionTool[]{new LombokSetterMayBeUsedInspection()}; + } + + @Override + protected @NotNull String getTestDataPath() { + return PathManager.getCommunityHomePath() + "/plugins/lombok/testData"; + } + @NotNull + private String getFilePath() { + return "/inspection/lombokSetterMayBeUsed/" + getTestName(false) + ".java"; + } + + private void doTest() { + doTest(getFilePath(), true, false); + } + + public void testNoLibrary() { + doTest(); + } +} diff --git a/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/afterEmptyStatement.java b/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/afterEmptyStatement.java new file mode 100644 index 000000000000..d6fd30594d87 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/afterEmptyStatement.java @@ -0,0 +1,18 @@ +// "Use lombok @Getter for 'field'" "true" + +import lombok.Getter; + +public class Foo { + private int fieldWithoutGetter; + /** + * The field. + * -- GETTER -- + * Returns The field. + * + * @return The field + + */ + @Getter + private int field; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/afterParentherizedValue.java b/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/afterParentherizedValue.java new file mode 100644 index 000000000000..e1c9085dc7d3 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/afterParentherizedValue.java @@ -0,0 +1,18 @@ +// "Use lombok @Getter for 'finalField'" "true" + +import lombok.Getter; + +public class Foo { + private int fieldWithoutGetter; + /** + * The final field. + * -- GETTER -- + * Returns The final field. + * + * @return The final field + + */ + @Getter + private final int finalField; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/beforeEmptyStatement.java b/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/beforeEmptyStatement.java new file mode 100644 index 000000000000..0fae03ef696c --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/beforeEmptyStatement.java @@ -0,0 +1,18 @@ +// "Use lombok @Getter for 'field'" "true" + +public class Foo { + private int fieldWithoutGetter; + /** + * The field. + */ + private int field; + + /** + * Returns The field. + * + * @return The field + */ + public int getField() { + return field;; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/beforeParentherizedValue.java b/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/beforeParentherizedValue.java new file mode 100644 index 000000000000..80aa43312944 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokGetterMayBeUsed/beforeParentherizedValue.java @@ -0,0 +1,18 @@ +// "Use lombok @Getter for 'finalField'" "true" + +public class Foo { + private int fieldWithoutGetter; + /** + * The final field. + */ + private final int finalField; + + /** + * Returns The final field. + * + * @return The final field + */ + public int getFinalField() { + return (finalField); + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/FieldsWithSetter.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/FieldsWithSetter.java new file mode 100644 index 000000000000..9ca8bd159a29 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/FieldsWithSetter.java @@ -0,0 +1,53 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +public class FieldsWithSetter { + private int bar; + + public void setBar(int param) { + bar = param; + } + public class InstanceField { + private int bar; + private boolean Baz; + private int fooBar; + private int fieldWithoutSetter; + + public void setBar(int param) { + bar = param; + } + + public void setBaz(boolean param) { + this.Baz = param; + } + + public void setFooBar(int param) { + InstanceField.this.fooBar = param; + } + } + public class AllInstanceFields { + private int bar; + private boolean Baz; + private int fooBar; + private static int staticFieldWithoutSetter; + + public void setBar(int param) { + bar = param; + } + + public void setBaz(boolean param) { + this.Baz = param; + } + + public void setFooBar(int param) { + AllInstanceFields.this.fooBar = param; + } + } + public class StaticField { + private static int bar; + private int fieldWithoutSetter; + + public static void setBar(int param) { + bar = param; + } + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/InstanceAndStaticFields.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/InstanceAndStaticFields.java new file mode 100644 index 000000000000..10f4ca7e706f --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/InstanceAndStaticFields.java @@ -0,0 +1,14 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +public class InstanceAndStaticFields { + private static int staticField; + private int instanceField; + + public static void setStaticField(int param) { + staticField = param; + } + + public void setInstanceField(int param) { + instanceField = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/NoLibrary.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/NoLibrary.java new file mode 100644 index 000000000000..5b706dec5d76 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/NoLibrary.java @@ -0,0 +1,53 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +public class NoLibrary { + private int bar; + + public void setBar(int param) { + bar = param; + } + public class InstanceField { + private int bar; + private boolean PrimitiveBooleanValue; + private int fooBar; + private int fieldWithoutSetter; + + public void setBar(int param) { + bar = param; + } + + public void setPrimitiveBooleanValue(boolean param) { + PrimitiveBooleanValue = param; + } + + public void setFooBar(int param) { + InstanceField.this.fooBar = param; + } + } + public class AllInstanceFields { + private int bar; + private boolean Baz; + private int fooBar; + private static int staticFieldWithoutSetter; + + public void setBar(int param) { + bar = param; + } + + public void setBaz(boolean param) { + Baz = param; + } + + public void setFooBar(int param) { + AllInstanceFields.this.fooBar = param; + } + } + public class StaticField { + private static int number; + private int fieldWithoutSetter; + + public static void setNumber(int param) { + number = param; + } + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterAllFields.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterAllFields.java new file mode 100644 index 000000000000..1e6470a91acd --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterAllFields.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'Foo'" "true" + +import lombok.Setter; + +@Setter +public class Foo { + private int bar; + private boolean baz; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterAnnotatedField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterAnnotatedField.java new file mode 100644 index 000000000000..065f15113967 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterAnnotatedField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'ClassWithAnnotatedField'" "true" + +import lombok.Setter; + +@Setter +public class ClassWithAnnotatedField { + private int canditateField; + private int annotatedField; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterBooleanField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterBooleanField.java new file mode 100644 index 000000000000..9369297f66fb --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterBooleanField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'valid'" "true" + +import lombok.Setter; + +public class ClassWithBoolean { + private int fieldWithoutSetter; + @Setter + private boolean valid; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterEmptyStatement.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterEmptyStatement.java new file mode 100644 index 000000000000..ad0a1da16dd9 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterEmptyStatement.java @@ -0,0 +1,9 @@ +// "Use lombok @Setter for 'Foo'" "true" + +import lombok.Setter; + +@Setter +public class Foo { + Long bar; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFieldInInnerClass.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFieldInInnerClass.java new file mode 100644 index 000000000000..d0443c018d79 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFieldInInnerClass.java @@ -0,0 +1,12 @@ +// "Use lombok @Setter for 'InnerClass'" "true" + +import lombok.Setter; + +public class Foo { + @Setter + public class InnerClass { + // Keep this comment + private int bar; + + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFinalField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFinalField.java new file mode 100644 index 000000000000..df831fd2da4a --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFinalField.java @@ -0,0 +1,18 @@ +// "Use lombok @Setter for 'finalField'" "true" + +import lombok.Setter; + +public class Foo { + private int fieldWithoutSetter; + /** + * The final field. + * -- SETTER -- + * Sets The final field. + * + * @param The final field + + */ + @Setter + private final int finalField; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFinalParameter.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFinalParameter.java new file mode 100644 index 000000000000..a44a72105eac --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFinalParameter.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +import lombok.Setter; + +public class Foo { + @Setter + Long bar; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFullyQualifiedAnnotation.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFullyQualifiedAnnotation.java new file mode 100644 index 000000000000..3ebd4394894f --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFullyQualifiedAnnotation.java @@ -0,0 +1,11 @@ +// "Use lombok @Setter for 'candidateField'" "true" + +public class Setter { + @lombok.Setter + private int candidateField; + private int fieldWithoutSetter; + + public int completelyIrrevelantMethod() { + return 0; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFullyQualifiedThis.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFullyQualifiedThis.java new file mode 100644 index 000000000000..ab7672db0fee --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterFullyQualifiedThis.java @@ -0,0 +1,12 @@ +// "Use lombok @Setter for 'bar'" "true" + +package project; + +import lombok.Setter; + +public class OneFullyQualifiedClass { + @Setter + private int bar; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterInstanceField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterInstanceField.java new file mode 100644 index 000000000000..67dc044786a4 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterInstanceField.java @@ -0,0 +1,18 @@ +// "Use lombok @Setter for 'bar'" "true" + +import lombok.Setter; + +public class CommentedClass { + /*1*/ + /*2*/ + /*3*/ + /*4*/ + /*5*/ + /*6*/ + /*7*/ + /*8*/ + @Setter + private int bar; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterMergeJavaDoc.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterMergeJavaDoc.java new file mode 100644 index 000000000000..cb9dc15a648f --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterMergeJavaDoc.java @@ -0,0 +1,21 @@ +// "Use lombok @Setter for 'processDate'" "true" + +import lombok.Setter; + +import java.util.Date; + +public class MergeJavaDoc { + /** + * The process date. + * -- SETTER -- + * Sets The date. + * It's an instance field. + * + * @param The date + + */ + @Setter + private Date processDate; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterMoveJavaDoc.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterMoveJavaDoc.java new file mode 100644 index 000000000000..d3848c30e4a8 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterMoveJavaDoc.java @@ -0,0 +1,19 @@ +// "Use lombok @Setter for 'creationDate'" "true" + +import lombok.Setter; + +import java.util.Date; + +public class MoveJavaDoc { + /** + * -- SETTER -- + * Sets The date. + * It's an instance field. + * + * @param The date + */ + @Setter + private Date creationDate; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterParamTags.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterParamTags.java new file mode 100644 index 000000000000..43d2b938766e --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterParamTags.java @@ -0,0 +1,20 @@ +// "Use lombok @Setter for 'releaseDate'" "true" + +import lombok.Setter; + +import java.util.Date; + +public class Foo { + /** + * -- SETTER -- + * Sets The date. + * It's an instance field. + * + * @param The date + * @param The value + */ + @Setter + private Date releaseDate; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterParentherizedParameter.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterParentherizedParameter.java new file mode 100644 index 000000000000..a44a72105eac --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterParentherizedParameter.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +import lombok.Setter; + +public class Foo { + @Setter + Long bar; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterQualifiedThis.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterQualifiedThis.java new file mode 100644 index 000000000000..ed80607ac9f8 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterQualifiedThis.java @@ -0,0 +1,11 @@ +// "Use lombok @Setter for 'bar'" "true" + +import lombok.Setter; + +public class QualifiedClass { + //Keep this comment + @Setter + private int bar; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterStaticField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterStaticField.java new file mode 100644 index 000000000000..1302b3ad7b83 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterStaticField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +import lombok.Setter; + +public class Foo { + @Setter + private static char bar; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterThisField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterThisField.java new file mode 100644 index 000000000000..a44a72105eac --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterThisField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +import lombok.Setter; + +public class Foo { + @Setter + Long bar; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterUppercaseField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterUppercaseField.java new file mode 100644 index 000000000000..7070d141287e --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/afterUppercaseField.java @@ -0,0 +1,18 @@ +// "Use lombok @Setter for 'Bar'" "true" + +import lombok.Setter; + +import java.util.Date; + +public class Foo { + /** + * -- SETTER -- + * Sets The date. + * + * @param The date + */ + @Setter + private Date Bar; + private int fieldWithoutSetter; + +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAllFields.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAllFields.java new file mode 100644 index 000000000000..c22d08f7b179 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAllFields.java @@ -0,0 +1,14 @@ +// "Use lombok @Setter for 'Foo'" "true" + +public class Foo { + private int bar; + private boolean baz; + + public void setBar(int param) { + bar = param; + } + + public void setBaz(boolean param) { + baz = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnotatedField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnotatedField.java new file mode 100644 index 000000000000..967718495d1c --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnotatedField.java @@ -0,0 +1,13 @@ +// "Use lombok @Setter for 'ClassWithAnnotatedField'" "true" + +import lombok.Setter; + +public class ClassWithAnnotatedField { + private int canditateField; + @Setter + private int annotatedField; + + public void setCanditateField(int param) { + canditateField = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnotedMethod.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnotedMethod.java new file mode 100644 index 000000000000..bd812b6c6461 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnotedMethod.java @@ -0,0 +1,11 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + @Deprecated + public void setBar(int param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnoyingQualifier.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnoyingQualifier.java new file mode 100644 index 000000000000..c309bbdb9d8d --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnnoyingQualifier.java @@ -0,0 +1,9 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + Long bar; + + public void setBar(Long bar) { + this.bar = this.bar; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnotherField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnotherField.java new file mode 100644 index 000000000000..096b552082fe --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAnotherField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int anotherField; + private int fieldWithoutSetter; + + public void setBar(int param) { + anotherField = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAssignment.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAssignment.java new file mode 100644 index 000000000000..60f2c4987f1e --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeAssignment.java @@ -0,0 +1,9 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public void setBar(int param) { + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBadField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBadField.java new file mode 100644 index 000000000000..d60f8d3409fe --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBadField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public void setBar(int param) { + new Foo().bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBadOperator.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBadOperator.java new file mode 100644 index 000000000000..b288d0d399a4 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBadOperator.java @@ -0,0 +1,9 @@ +// "Use lombok @Setter for 'Foo'" "false" + +public class Foo { + private int count; + + public void setCount(int increment) { + count += increment; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBooleanField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBooleanField.java new file mode 100644 index 000000000000..622769c369e7 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeBooleanField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'valid'" "true" + +public class ClassWithBoolean { + private int fieldWithoutSetter; + private boolean valid; + + public void setValid(boolean param) { + valid = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeDifferentType.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeDifferentType.java new file mode 100644 index 000000000000..8fd364937f3f --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeDifferentType.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private char bar; + private int fieldWithoutSetter; + + public void setBar(int param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeEmptyStatement.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeEmptyStatement.java new file mode 100644 index 000000000000..dca40199e320 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeEmptyStatement.java @@ -0,0 +1,9 @@ +// "Use lombok @Setter for 'Foo'" "true" + +public class Foo { + Long bar; + + public void setBar(Long param) { + this.bar = param;; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFieldInInnerClass.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFieldInInnerClass.java new file mode 100644 index 000000000000..297be0f81003 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFieldInInnerClass.java @@ -0,0 +1,11 @@ +// "Use lombok @Setter for 'InnerClass'" "true" + +public class Foo { + public class InnerClass { + private int bar; + + public void setBar(int param) { + bar = param; // Keep this comment + } + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalField.java new file mode 100644 index 000000000000..866865483742 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalField.java @@ -0,0 +1,18 @@ +// "Use lombok @Setter for 'finalField'" "true" + +public class Foo { + private int fieldWithoutSetter; + /** + * The final field. + */ + private final int finalField; + + /** + * Sets The final field. + * + * @param The final field + */ + public void setFinalField(int param) { + finalField = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalMethod.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalMethod.java new file mode 100644 index 000000000000..97f441398b65 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalMethod.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public final void setBar(int param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalParameter.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalParameter.java new file mode 100644 index 000000000000..bdbd9c3670ac --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFinalParameter.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +public class Foo { + Long bar; + private int fieldWithoutSetter; + + public void setBar(final Long param) { + this.bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFullyQualifiedAnnotation.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFullyQualifiedAnnotation.java new file mode 100644 index 000000000000..3a23c7ebcd37 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFullyQualifiedAnnotation.java @@ -0,0 +1,14 @@ +// "Use lombok @Setter for 'candidateField'" "true" + +public class Setter { + private int candidateField; + private int fieldWithoutSetter; + + public void setCandidateField(int param) { + candidateField = param; + } + + public int completelyIrrevelantMethod() { + return 0; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFullyQualifiedThis.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFullyQualifiedThis.java new file mode 100644 index 000000000000..a0fef7a29908 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeFullyQualifiedThis.java @@ -0,0 +1,12 @@ +// "Use lombok @Setter for 'bar'" "true" + +package project; + +public class OneFullyQualifiedClass { + private int bar; + private int fieldWithoutSetter; + + public void setBar(int param) { + project.OneFullyQualifiedClass.this.bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeGetterMethod.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeGetterMethod.java new file mode 100644 index 000000000000..e5559a1170dd --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeGetterMethod.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public int getBar() { + return bar; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeIgnoredParameter.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeIgnoredParameter.java new file mode 100644 index 000000000000..b1e1fc28cfe3 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeIgnoredParameter.java @@ -0,0 +1,9 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + + public void setBar(int param) { + bar = bar; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeInheritedField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeInheritedField.java new file mode 100644 index 000000000000..232ab0157c40 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeInheritedField.java @@ -0,0 +1,13 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo extends MotherClass { + + public class MotherClass { + private int bar; + private int fieldWithoutSetter; + } + + public void setBar(int param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeInstanceField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeInstanceField.java new file mode 100644 index 000000000000..a67a2e04290a --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeInstanceField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +public class CommentedClass { + private int bar; + private int fieldWithoutSetter; + + /*1*/public /*2*/void /*3*/setBar(int param) /*4*/{ + /*5*/bar/*6*/ = /*7*/param; + /*8*/} +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMergeJavaDoc.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMergeJavaDoc.java new file mode 100644 index 000000000000..5c7e17c870c4 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMergeJavaDoc.java @@ -0,0 +1,22 @@ +// "Use lombok @Setter for 'processDate'" "true" + +import java.util.Date; + +public class MergeJavaDoc { + /** + * The process date. + */ + private Date processDate; + private int fieldWithoutSetter; + + /** + * Sets The date. + * + * It's an instance field. + * + * @param The date + */ + public void setProcessDate(Date param) { + processDate = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMethodStartingWithDigit.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMethodStartingWithDigit.java new file mode 100644 index 000000000000..0af9d2b3ffb6 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMethodStartingWithDigit.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public void set1Bar(int param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMoveJavaDoc.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMoveJavaDoc.java new file mode 100644 index 000000000000..9749c0b3914a --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeMoveJavaDoc.java @@ -0,0 +1,19 @@ +// "Use lombok @Setter for 'creationDate'" "true" + +import java.util.Date; + +public class MoveJavaDoc { + private Date creationDate; + private int fieldWithoutSetter; + + /** + * Sets The date. + * + * It's an instance field. + * + * @param The date + */ + public void setCreationDate(Date param) { + creationDate = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNoFieldSet.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNoFieldSet.java new file mode 100644 index 000000000000..237c48f01a24 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNoFieldSet.java @@ -0,0 +1,9 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + Long bar; + + public void setBar(Long bar) { + bar = bar; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNonPublicGetter.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNonPublicGetter.java new file mode 100644 index 000000000000..b5fd9dba0670 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNonPublicGetter.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + void setBar(int param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNonStaticMethod.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNonStaticMethod.java new file mode 100644 index 000000000000..5f7cbc7ea840 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNonStaticMethod.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private static int bar; + private int fieldWithoutSetter; + + public void setBar(int param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNotWritableLog.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNotWritableLog.java new file mode 100644 index 000000000000..b018eb8a2865 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeNotWritableLog.java @@ -0,0 +1,12 @@ +// "Use lombok @Setter for 'log'" "false" + +import lombok.extern.java.Log; +import java.util.logging.Logger; + +@Log +public class Foo { + private int fieldWithoutSetter; + public void setLog(Logger param) { + log = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeParamTags.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeParamTags.java new file mode 100644 index 000000000000..9f006df9b629 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeParamTags.java @@ -0,0 +1,20 @@ +// "Use lombok @Setter for 'releaseDate'" "true" + +import java.util.Date; + +public class Foo { + private Date releaseDate; + private int fieldWithoutSetter; + + /** + * Sets The date. + * + * It's an instance field. + * + * @param The date + * @param The value + */ + public void setReleaseDate(Date param) { + releaseDate = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeParentherizedParameter.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeParentherizedParameter.java new file mode 100644 index 000000000000..60ea1e71071b --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeParentherizedParameter.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +public class Foo { + Long bar; + private int fieldWithoutSetter; + + public void setBar(Long param) { + this.bar = (param); + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeQualifiedThis.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeQualifiedThis.java new file mode 100644 index 000000000000..0b222bd472e3 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeQualifiedThis.java @@ -0,0 +1,11 @@ +// "Use lombok @Setter for 'bar'" "true" + +public class QualifiedClass { + private int bar; + private int fieldWithoutSetter; + + public void setBar(int param) { + //Keep this comment + QualifiedClass.this.bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeSetLiteral.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeSetLiteral.java new file mode 100644 index 000000000000..b201d7a4d1b5 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeSetLiteral.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public void setBar(int param) { + bar = 0; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeShortMethodName.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeShortMethodName.java new file mode 100644 index 000000000000..c46374dcf5ac --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeShortMethodName.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public void set(int param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeStaticField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeStaticField.java new file mode 100644 index 000000000000..da64c27b49f0 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeStaticField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +public class Foo { + private static char bar; + private int fieldWithoutSetter; + + public static void setBar(char param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeThisField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeThisField.java new file mode 100644 index 000000000000..c76da09e5340 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeThisField.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "true" + +public class Foo { + Long bar; + private int fieldWithoutSetter; + + public void setBar(Long param) { + this.bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeThrowException.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeThrowException.java new file mode 100644 index 000000000000..704cee846c2f --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeThrowException.java @@ -0,0 +1,12 @@ +// "Use lombok @Setter for 'bar'" "false" + +import javax.validation.constraints.NotNull; + +public class Foo { + private Integer bar; + private int fieldWithoutSetter; + + public void setBar(@NotNull Integer param) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeTwoParameterMethod.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeTwoParameterMethod.java new file mode 100644 index 000000000000..0adb9c8ef030 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeTwoParameterMethod.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public void setBar(int param, int dummy) { + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeTwoStatements.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeTwoStatements.java new file mode 100644 index 000000000000..83f734946913 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeTwoStatements.java @@ -0,0 +1,11 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public void setBar(int param) { + bar++; + bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeUppercaseField.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeUppercaseField.java new file mode 100644 index 000000000000..cbe80e56222b --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeUppercaseField.java @@ -0,0 +1,18 @@ +// "Use lombok @Setter for 'Bar'" "true" + +import java.util.Date; + +public class Foo { + private Date Bar; + private int fieldWithoutSetter; + + /** + * Sets The date. + * + * @param The date + */ + + public void setBar(Date param) { + Bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeVarArgParameter.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeVarArgParameter.java new file mode 100644 index 000000000000..0b596ea32192 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeVarArgParameter.java @@ -0,0 +1,9 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + Object bar; + + public void setBar(Object param...) { + this.bar = param; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeZeroParameterMethod.java b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeZeroParameterMethod.java new file mode 100644 index 000000000000..8b4cdb798663 --- /dev/null +++ b/plugins/lombok/testData/inspection/lombokSetterMayBeUsed/beforeZeroParameterMethod.java @@ -0,0 +1,10 @@ +// "Use lombok @Setter for 'bar'" "false" + +public class Foo { + private int bar; + private int fieldWithoutSetter; + + public void setBar() { + bar = bar; + } +} \ No newline at end of file From 0f73b3d3d4cfd42faf4114f4af233bcfd93d30de Mon Sep 17 00:00:00 2001 From: Michail Plushnikov Date: Sun, 2 Jul 2023 20:33:02 +0200 Subject: [PATCH 145/226] [lombok] IDEA-322276 Replace all field-annotations by one class-annotation GitOrigin-RevId: 53da3fce87d68c26f248a9a61e59be9fc68885d9 --- ...mbokGetterOrSetterMayBeUsedInspection.java | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterOrSetterMayBeUsedInspection.java b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterOrSetterMayBeUsedInspection.java index e5735f9643cd..c825372f6e9a 100644 --- a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterOrSetterMayBeUsedInspection.java +++ b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/inspection/LombokGetterOrSetterMayBeUsedInspection.java @@ -59,12 +59,12 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava if (annotation != null) { if (!annotation.getAttributes().isEmpty()) { isLombokAnnotationAtClassLevel = false; - } else { + } + else { annotatedFields.add(field); } - break; } - if (!field.hasModifierProperty(PsiModifier.STATIC)) { + else if (!field.hasModifierProperty(PsiModifier.STATIC)) { boolean found = false; for (Pair instanceCandidate : instanceCandidates) { if (field.equals(instanceCandidate.getFirst())) { @@ -72,13 +72,18 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava break; } } - isLombokAnnotationAtClassLevel &= found; + isLombokAnnotationAtClassLevel = found; + } + + if (!isLombokAnnotationAtClassLevel) { + break; } } List> allCandidates = new ArrayList<>(staticCandidates); - if (isLombokAnnotationAtClassLevel && (!instanceCandidates.isEmpty() || !annotatedFields.isEmpty()) ) { + if (isLombokAnnotationAtClassLevel && (!instanceCandidates.isEmpty() || !annotatedFields.isEmpty())) { warnOrFix(psiClass, instanceCandidates, annotatedFields); - } else { + } + else { allCandidates.addAll(instanceCandidates); } for (Pair candidate : allCandidates) { @@ -109,7 +114,8 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava ProblemHighlightType.GENERIC_ERROR_OR_WARNING, psiClassNameIdentifier != null ? psiClassNameIdentifier.getTextRangeInParent() : psiClass.getTextRange(), fix); - } else if (myLombokGetterOrSetterMayBeUsedFix != null) { + } + else if (myLombokGetterOrSetterMayBeUsedFix != null) { myLombokGetterOrSetterMayBeUsedFix.effectivelyDoFix(psiClass, fieldsAndMethods, annotatedFields); } } @@ -120,7 +126,8 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava final LocalQuickFix fix = new LombokGetterOrSetterMayBeUsedFix(fieldName); myHolder.registerProblem(method, getFieldErrorMessage(fieldName), fix); - } else if (myLombokGetterOrSetterMayBeUsedFix != null) { + } + else if (myLombokGetterOrSetterMayBeUsedFix != null) { myLombokGetterOrSetterMayBeUsedFix.effectivelyDoFix(field, method); } } @@ -154,7 +161,8 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava final PsiElement element = descriptor.getPsiElement(); if (element instanceof PsiMethod) { new LombokGetterOrSetterMayBeUsedVisitor(null, this).visitMethodForFix((PsiMethod)element); - } else if (element instanceof PsiClass) { + } + else if (element instanceof PsiClass) { new LombokGetterOrSetterMayBeUsedVisitor(null, this).visitClass((PsiClass)element); } } @@ -186,7 +194,7 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava return false; } final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final PsiAnnotation annotation = factory.createAnnotationFromText("@"+getAnnotationName(), fieldOrClass); + final PsiAnnotation annotation = factory.createAnnotationFromText("@" + getAnnotationName(), fieldOrClass); JavaCodeStyleManager.getInstance(project).shortenClassReferences(annotation); modifierList.addAfter(annotation, null); return true; @@ -210,19 +218,23 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava if (fieldJavaDoc == null) { if (javaDocMethodText.isEmpty()) { fieldJavaDoc = factory.createDocCommentFromText("/**\n*/"); - } else { - fieldJavaDoc = factory.createDocCommentFromText("/**\n* -- " + getJavaDocMethodMarkup() + " --\n* " + javaDocMethodText + "\n*/"); + } + else { + fieldJavaDoc = + factory.createDocCommentFromText("/**\n* -- " + getJavaDocMethodMarkup() + " --\n* " + javaDocMethodText + "\n*/"); } for (PsiDocTag methodTag : methodTags) { fieldJavaDoc.add(methodTag); } field.getParent().addBefore(fieldJavaDoc, field); - } else { + } + else { @NotNull PsiElement @NotNull [] fieldJavaDocChildren = Arrays.stream(fieldJavaDoc.getChildren()) .filter(e -> e instanceof PsiDocToken) .toArray(PsiElement[]::new); @NotNull PsiElement fieldJavaDocChild = fieldJavaDocChildren[fieldJavaDocChildren.length - 2]; - PsiDocComment newMethodJavaDoc = factory.createDocCommentFromText("/**\n* -- " + getJavaDocMethodMarkup() + " --\n* " + javaDocMethodText + "\n*/"); + PsiDocComment newMethodJavaDoc = + factory.createDocCommentFromText("/**\n* -- " + getJavaDocMethodMarkup() + " --\n* " + javaDocMethodText + "\n*/"); PsiElement[] tokens = newMethodJavaDoc.getChildren(); for (int i = tokens.length - 2; 0 < i; i--) { fieldJavaDoc.addAfter(tokens[i], fieldJavaDocChild); From eacd977798424244b47dfdc098c28f22f4d772a3 Mon Sep 17 00:00:00 2001 From: Ruslan Cheremin Date: Sun, 2 Jul 2023 20:59:32 +0200 Subject: [PATCH 146/226] [core] junit5 extensions for VFS check/cleanup GitOrigin-RevId: 9b693e2a715c69a5ae77d9684e15f61458da4bb7 --- .../persistent/PersistentFSConnection.java | 4 +- .../src/impl/CheckVFSHealthExtension.kt | 69 +++++++++++++++++++ .../junit5/src/impl/CleanVFSExtension.kt | 62 +++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 platform/testFramework/junit5/src/impl/CheckVFSHealthExtension.kt create mode 100644 platform/testFramework/junit5/src/impl/CleanVFSExtension.kt diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java index f3cc0fd93e14..c1c56f4405f8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java @@ -358,10 +358,10 @@ public final class PersistentFSConnection { if (errorCause == null) { //Without 'errorCause' it is not an error, but, likely, an explicit 'invalidateCache' call: // no need to print stacktrace then, also no need for a WARN - LOG.info("VFS is corrupted; Creating VFS corruption marker: " + message); + LOG.info("VFS rebuild is requested: creating VFS rebuild marker. Message: " + message); } else { - LOG.warn("VFS is corrupted; Creating VFS corruption marker", corruptedException); + LOG.warn("VFS is corrupted: creating VFS rebuild marker.", corruptedException); } try { diff --git a/platform/testFramework/junit5/src/impl/CheckVFSHealthExtension.kt b/platform/testFramework/junit5/src/impl/CheckVFSHealthExtension.kt new file mode 100644 index 000000000000..01994e90668a --- /dev/null +++ b/platform/testFramework/junit5/src/impl/CheckVFSHealthExtension.kt @@ -0,0 +1,69 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.testFramework.junit5.impl + +import com.intellij.openapi.vfs.newvfs.persistent.VFSHealthChecker +import org.jetbrains.annotations.TestOnly +import org.junit.jupiter.api.extension.AfterAllCallback +import org.junit.jupiter.api.extension.AfterEachCallback +import org.junit.jupiter.api.extension.BeforeAllCallback +import org.junit.jupiter.api.extension.BeforeEachCallback +import org.junit.jupiter.api.extension.ExtensionContext + +/** + * Checks VFS to be consistent before/after all/each tests have passed. + */ +@TestOnly +class CheckVFSHealthExtension +private constructor(private val checkBeforeEach: Boolean = false, + private val checkAfterEach: Boolean = false, + private val checkBeforeAll: Boolean = false, + private val checkAfterAll: Boolean = false) : BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback { + + init { + if (!checkBeforeAll && !checkBeforeEach && !checkAfterAll && !checkAfterEach) { + throw IllegalArgumentException( + "All check[Before|After][All|Each] flags are false -- nothing to do. At least one of flags must be true") + } + } + + override fun beforeAll(context: ExtensionContext?) = if (checkBeforeAll) checkVFS(context!!) else Unit + + override fun afterAll(context: ExtensionContext?) = if (checkAfterAll) checkVFS(context!!) else Unit + + override fun beforeEach(context: ExtensionContext?) = if (checkBeforeEach) checkVFS(context!!) else Unit + + override fun afterEach(context: ExtensionContext?) = if (checkAfterEach) checkVFS(context!!) else Unit + + @Suppress("TestOnlyProblems") + companion object { + @JvmStatic + fun beforeAll() = CheckVFSHealthExtension(checkBeforeAll = true) + + @JvmStatic + fun afterAll() = CheckVFSHealthExtension(checkAfterAll = true) + + @JvmStatic + fun beforeAndAfterAll() = CheckVFSHealthExtension(checkBeforeAll = true, checkAfterAll = true) + + + @JvmStatic + fun beforeEach() = CheckVFSHealthExtension(checkBeforeEach = true) + + @JvmStatic + fun afterEach() = CheckVFSHealthExtension(checkAfterEach = true) + + @JvmStatic + fun beforeAndAfterEach() = CheckVFSHealthExtension(checkBeforeEach = true, checkAfterEach = true) + } + + + @Throws(Exception::class) + private fun checkVFS(context: ExtensionContext) { + val checker = VFSHealthChecker() + val report = checker.checkHealth(checkForOrphanRecords = true) + context.publishReportEntry("vfs-report", report.toString()) + if (!report.healthy) { + throw AssertionError("VFS is corrupted: $report") + } + } +} diff --git a/platform/testFramework/junit5/src/impl/CleanVFSExtension.kt b/platform/testFramework/junit5/src/impl/CleanVFSExtension.kt new file mode 100644 index 000000000000..a573e575327f --- /dev/null +++ b/platform/testFramework/junit5/src/impl/CleanVFSExtension.kt @@ -0,0 +1,62 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.testFramework.junit5.impl + +import com.intellij.openapi.vfs.newvfs.persistent.FSRecords +import org.jetbrains.annotations.TestOnly +import org.junit.jupiter.api.extension.* + +/** + * Cleans VFS before/after all/each tests have passed. + */ +@TestOnly +class CleanVFSExtension +private constructor(private val cleanBeforeEach: Boolean = false, + private val cleanAfterEach: Boolean = false, + private val cleanBeforeAll: Boolean = false, + private val cleanAfterAll: Boolean = false) : BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback { + + init { + if (!cleanBeforeAll && !cleanBeforeEach && !cleanAfterAll && !cleanAfterEach) { + throw IllegalArgumentException( + "All clean[Before|After][All|Each] flags are false -- nothing to do. At least one of flags must be true") + } + } + + override fun beforeAll(context: ExtensionContext?) = if (cleanBeforeAll) cleanVFS(context!!) else Unit + + override fun afterAll(context: ExtensionContext?) = if (cleanAfterAll) cleanVFS(context!!) else Unit + + override fun beforeEach(context: ExtensionContext?) = if (cleanBeforeEach) cleanVFS(context!!) else Unit + + override fun afterEach(context: ExtensionContext?) = if (cleanAfterEach) cleanVFS(context!!) else Unit + + @Suppress("TestOnlyProblems") + companion object { + @JvmStatic + fun beforeAll() = CleanVFSExtension(cleanBeforeAll = true) + + @JvmStatic + fun afterAll() = CleanVFSExtension(cleanAfterAll = true) + + @JvmStatic + fun beforeAndAfterAll() = CleanVFSExtension(cleanBeforeAll = true, cleanAfterAll = true) + + + @JvmStatic + fun beforeEach() = CleanVFSExtension(cleanBeforeEach = true) + + @JvmStatic + fun afterEach() = CleanVFSExtension(cleanAfterEach = true) + + @JvmStatic + fun beforeAndAfterEach() = CleanVFSExtension(cleanBeforeEach = true, cleanAfterEach = true) + } + + + @Throws(Exception::class) + private fun cleanVFS(context: ExtensionContext) { + context.publishReportEntry("Request VFS rebuild (for better tests isolation)") + + FSRecords.invalidateCaches("Rebuild VFS (for better tests isolation)") + } +} From 2997aec0337473eea8b0c1464565cc37599dff2d Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 20:55:00 +0200 Subject: [PATCH 147/226] cleanup GitOrigin-RevId: 7cd0afa427bb0d78572848a0a5aec6cb7b394edf --- .../ide/ProjectWindowCustomizerService.kt | 18 +++++++++++------- .../ChangeMainToolbarColorAction.kt | 14 ++++++++------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt b/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt index bf4d5675294a..46f86702d312 100644 --- a/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt +++ b/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt @@ -62,7 +62,7 @@ private class ProjectWindowCustomizerIconCache(private val project: Project) { } } -enum class MainToolbarCustomizationType { +internal enum class MainToolbarCustomizationType { JUST_ICON, LINEAR_GRAD_WITH_ICON, CIRCULAR_GRADIENT_WITH_ICON, @@ -84,7 +84,7 @@ class ProjectWindowCustomizerService : Disposable { fun getInstance(): ProjectWindowCustomizerService = service() } - private data class ProjectColors(val gradient: Color, val background: Color) + private data class ProjectColors(@JvmField val gradient: Color, @JvmField val background: Color) private var wasGradientPainted = false private var ourSettingsValue = UISettings.getInstance().differentiateProjects @@ -139,13 +139,15 @@ class ProjectWindowCustomizerService : Disposable { } } - fun getPaintingType() = when (Registry.get("ide.colorful.toolbar.gradient.type").selectedOption) { + internal fun getPaintingType(): MainToolbarCustomizationType { + return when (Registry.get("ide.colorful.toolbar.gradient.type").selectedOption) { "Just Icon" -> MainToolbarCustomizationType.JUST_ICON "Linear Gradient and Icon" -> MainToolbarCustomizationType.LINEAR_GRAD_WITH_ICON "Circular Gradient and Icon" -> MainToolbarCustomizationType.CIRCULAR_GRADIENT_WITH_ICON "Dropdown Background and Icon" -> MainToolbarCustomizationType.DROPDOWN_WITH_ICON "Just Dropdown" -> MainToolbarCustomizationType.JUST_DROPDOWN else -> MainToolbarCustomizationType.LINEAR_GRAD_WITH_ICON + } } internal fun update(newValue: Boolean) { @@ -219,13 +221,13 @@ class ProjectWindowCustomizerService : Disposable { * @return true if method painted something */ fun paint(project: Project, parent: JComponent, g: Graphics2D): Boolean { - g.color = parent.background - g.fillRect(0, 0, parent.width, parent.height) - if (!isActive() || !getPaintingType().isGradient()) { return false } + g.color = parent.background + g.fillRect(0, 0, parent.width, parent.height) + g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY) val color = getGradientProjectColor(project) @@ -245,7 +247,9 @@ class ProjectWindowCustomizerService : Disposable { } fun getToolbarBackground(project: Project?):Color? { - if (project == null) return null + if (project == null) { + return null + } return getBackgroundProjectColor(project) } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/customization/ChangeMainToolbarColorAction.kt b/platform/platform-impl/src/com/intellij/ide/ui/customization/ChangeMainToolbarColorAction.kt index 5256db033c4b..64a857fa678a 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/customization/ChangeMainToolbarColorAction.kt +++ b/platform/platform-impl/src/com/intellij/ide/ui/customization/ChangeMainToolbarColorAction.kt @@ -14,19 +14,21 @@ import java.awt.Point /** * @author Konstantin Bulenkov */ -class ChangeMainToolbarColorAction : DumbAwareAction() { +private class ChangeMainToolbarColorAction : DumbAwareAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project!! val ideFrame = IdeFocusManager.getInstance(project).lastFocusedFrame - var relativePoint:RelativePoint? = null + var relativePoint: RelativePoint? = null if (ideFrame != null) { relativePoint = RelativePoint(ideFrame.component, Point(200, 30)) } - ColorChooserService.instance.showPopup(project, - ProjectWindowCustomizerService.getInstance().getToolbarBackground(project), - { color, _ -> ProjectWindowCustomizerService.getInstance().setToolbarColor(color, project) }, - relativePoint) + ColorChooserService.instance.showPopup(project = project, + currentColor = ProjectWindowCustomizerService.getInstance().getToolbarBackground(project), + listener = { color, _ -> + ProjectWindowCustomizerService.getInstance().setToolbarColor(color, project) + }, + location = relativePoint) } override fun getActionUpdateThread(): ActionUpdateThread { From 8f0f84dd5b1cdf12c50a587a2a26496135942cc8 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 21:11:01 +0200 Subject: [PATCH 148/226] ProjectWindowCustomizerService used in paint - cache it GitOrigin-RevId: 4cdb99e0f1d7414b761a08f3ff71dcdfe177b525 --- .../ide/ProjectWindowCustomizerService.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt b/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt index 46f86702d312..97e5ae4fbeb7 100644 --- a/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt +++ b/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt @@ -7,6 +7,7 @@ import com.intellij.ide.ui.UISettings import com.intellij.ide.ui.UISettingsListener import com.intellij.ide.util.PropertiesComponent import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.project.Project @@ -21,6 +22,7 @@ import com.intellij.ui.GotItTooltip import com.intellij.ui.JBColor import com.intellij.util.PlatformUtils import com.intellij.util.concurrency.SynchronizedClearableLazy +import com.intellij.util.concurrency.annotations.RequiresBlockingContext import com.intellij.util.ui.ColorPalette import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.job @@ -81,7 +83,21 @@ private const val TOOLBAR_BACKGROUND_KEY = "PROJECT_TOOLBAR_COLOR" @Service class ProjectWindowCustomizerService : Disposable { companion object { - fun getInstance(): ProjectWindowCustomizerService = service() + private var instance: ProjectWindowCustomizerService? = null + + init { + ApplicationManager.registerCleaner { instance = null } + } + + @RequiresBlockingContext + fun getInstance(): ProjectWindowCustomizerService { + var result = instance + if (result == null) { + result = service() + instance = result + } + return result + } } private data class ProjectColors(@JvmField val gradient: Color, @JvmField val background: Color) From 44d4da21d028c49704551730b87284c0a631c2b0 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 2 Jul 2023 22:07:07 +0200 Subject: [PATCH 149/226] support getServiceAsync for light services GitOrigin-RevId: a0b22fed40a5d927273a882eaaf64fb44622d0f3 --- .../serviceContainer/ComponentManagerImpl.kt | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt b/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt index 2c2943222172..61b9ad5794b6 100644 --- a/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt +++ b/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt @@ -634,7 +634,11 @@ abstract class ComponentManagerImpl( } final override suspend fun getServiceAsync(keyClass: Class): T { - return getServiceAsyncIfDefined(keyClass) ?: throw RuntimeException("service is not defined for $keyClass") + val result = getServiceAsyncIfDefined(keyClass) + if (result == null && isLightServiceSupported && isLightService(keyClass)) { + return getOrCreateLightServiceAdapater(keyClass).getInstanceAsync(componentManager = this, keyClass = keyClass) + } + return result ?: throw RuntimeException("service is not defined for $keyClass") } suspend fun getServiceAsyncIfDefined(keyClass: Class): T? { @@ -677,7 +681,13 @@ abstract class ComponentManagerImpl( } if (isLightServiceSupported && isLightService(serviceClass)) { - return if (createIfNeeded) getOrCreateLightService(serviceClass) else null + if (createIfNeeded) { + return getOrCreateLightServiceAdapater(serviceClass) + .getInstance(componentManager = this, keyClass = serviceClass, createIfNeeded = true)!! + } + else { + return null + } } checkCanceledIfNotInClassInit() @@ -712,7 +722,7 @@ abstract class ComponentManagerImpl( return result } - private fun getOrCreateLightService(serviceClass: Class): T { + private fun getOrCreateLightServiceAdapater(serviceClass: Class): BaseComponentAdapter { val adapter = componentKeyToAdapter.computeIfAbsent(serviceClass.name) { val classLoader = serviceClass.classLoader LightServiceComponentAdapter( @@ -721,7 +731,7 @@ abstract class ComponentManagerImpl( componentManager = this, ) } as BaseComponentAdapter - return adapter.getInstance(componentManager = this, keyClass = serviceClass, createIfNeeded = true)!! + return adapter } @Synchronized From 691485290ab43fcaabc9bc7c17c6abc7f5ef8948 Mon Sep 17 00:00:00 2001 From: Bart van Helvert Date: Sun, 2 Jul 2023 22:15:39 +0200 Subject: [PATCH 150/226] [kotlin] Remove redundant annotation #KTIJ-26105 GitOrigin-RevId: 9519342db64703600cf6ef89831f4f50eb854b96 --- .../kotlin/idea/refactoring/rename/AbstractRenameTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt index 8aa28daadc52..1c81fb332aa3 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt @@ -32,7 +32,6 @@ import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.UsefulTestCase import com.intellij.testFramework.fixtures.CodeInsightTestUtil -import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt import org.jetbrains.kotlin.asJava.finder.KtLightPackage import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.idea.base.plugin.artifacts.TestKotlinArtifacts @@ -364,7 +363,6 @@ abstract class AbstractRenameTest : KotlinLightCodeInsightFixtureTestCase() { return DescriptorToSourceUtils.descriptorToDeclaration(descriptor)!! } - @OptIn(KtAllowAnalysisOnEdt::class) private fun renameWithAutoDetection(renameParamsObject: JsonObject, context: TestContext) { val mainFilePath = renameParamsObject.getString("mainFile") val newName = renameParamsObject.getString("newName") From c8162203b23d49ef9b3e71d76d9a3a5b7071abc9 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 00:00:42 +0200 Subject: [PATCH 151/226] paint project colorful toolbar as soon as possible GitOrigin-RevId: aca5e89da314c7d6692492ee1988b7c65aceb079 --- .../com/intellij/ide/ProjectWindowCustomizerService.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt b/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt index 97e5ae4fbeb7..f3234d4d4bfb 100644 --- a/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt +++ b/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt @@ -80,6 +80,10 @@ internal enum class MainToolbarCustomizationType { private const val TOOLBAR_BACKGROUND_KEY = "PROJECT_TOOLBAR_COLOR" +private fun isForceColorfulToolbar() = Registry.`is`("ide.colorful.toolbar.force", true) + +private fun conditionToEnable() = isForceColorfulToolbar() || ProjectManagerEx.getOpenProjects().size > 1 + @Service class ProjectWindowCustomizerService : Disposable { companion object { @@ -102,7 +106,8 @@ class ProjectWindowCustomizerService : Disposable { private data class ProjectColors(@JvmField val gradient: Color, @JvmField val background: Color) - private var wasGradientPainted = false + private var wasGradientPainted = isForceColorfulToolbar() + private var ourSettingsValue = UISettings.getInstance().differentiateProjects private val colorCache = mutableMapOf() private val listeners = mutableListOf<(Boolean) -> Unit>() @@ -194,8 +199,6 @@ class ProjectWindowCustomizerService : Disposable { } } - private fun conditionToEnable() = ProjectManagerEx.getOpenProjects().size > 1 || Registry.`is`("ide.colorful.toolbar.force") - fun addListener(coroutineScope: CoroutineScope, fireFirstTime: Boolean, listener: (Boolean) -> Unit) { if (fireFirstTime) { listener(isActive()) From 6ab4e94b06f752c30a3d06486d771e8754ad423d Mon Sep 17 00:00:00 2001 From: Alexey Kryuchkov Date: Mon, 3 Jul 2023 00:34:02 +0400 Subject: [PATCH 152/226] Code review 107358 resolve issues GitOrigin-RevId: d86947841925d0fc238cec1f3f735519e66c32e5 --- .../java/performancePlugin/CreateJavaFileCommand.kt | 5 +++-- .../commands/CreateKotlinFileCommand.kt | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/java/performancePlugin/src/com/intellij/java/performancePlugin/CreateJavaFileCommand.kt b/java/performancePlugin/src/com/intellij/java/performancePlugin/CreateJavaFileCommand.kt index 19eacc569e37..5b1d537ccbb2 100644 --- a/java/performancePlugin/src/com/intellij/java/performancePlugin/CreateJavaFileCommand.kt +++ b/java/performancePlugin/src/com/intellij/java/performancePlugin/CreateJavaFileCommand.kt @@ -5,6 +5,7 @@ import com.intellij.core.JavaPsiBundle.message import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.guessProjectDir import com.intellij.openapi.ui.playback.PlaybackContext +import com.intellij.openapi.vfs.findDirectory import com.intellij.platform.diagnostic.telemetry.helpers.useWithScope import com.intellij.psi.JavaDirectoryService import com.intellij.psi.impl.file.PsiJavaDirectoryFactory @@ -38,8 +39,8 @@ class CreateJavaFileCommand(text: String, line: Int) : PerformanceCommandCorouti val directory = PsiJavaDirectoryFactory .getInstance(context.project) .createDirectory( - (context.project.guessProjectDir() ?: throw RuntimeException("'guessProjectDir' dir returned 'null'")) - .findFileByRelativePath(filePath) ?: throw RuntimeException("Can't find file $filePath") + (context.project.guessProjectDir() ?: throw RuntimeException("Root of the project was not found")) + .findDirectory(filePath) ?: throw RuntimeException("Can't find file $filePath") ) val templateName = POSSIBLE_FILE_TYPES[fileType.lowercase()] diff --git a/plugins/kotlin/kotlin.performanceExtendedPlugin/src/com/intellij/performance/performancePlugin/commands/CreateKotlinFileCommand.kt b/plugins/kotlin/kotlin.performanceExtendedPlugin/src/com/intellij/performance/performancePlugin/commands/CreateKotlinFileCommand.kt index 8bd46b15bab6..90993cfc7a2d 100644 --- a/plugins/kotlin/kotlin.performanceExtendedPlugin/src/com/intellij/performance/performancePlugin/commands/CreateKotlinFileCommand.kt +++ b/plugins/kotlin/kotlin.performanceExtendedPlugin/src/com/intellij/performance/performancePlugin/commands/CreateKotlinFileCommand.kt @@ -7,7 +7,7 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.guessProjectDir import com.intellij.openapi.ui.playback.PlaybackContext -import com.intellij.openapi.vfs.findFileOrDirectory +import com.intellij.openapi.vfs.findDirectory import com.intellij.platform.diagnostic.telemetry.helpers.useWithScope import com.intellij.psi.impl.PsiManagerImpl import com.intellij.psi.impl.file.PsiDirectoryImpl @@ -43,8 +43,8 @@ class CreateKotlinFileCommand(text: String, line: Int) : PerformanceCommandCorou val (fileName, filePath, fileType) = extractCommandArgument(PREFIX).replace("\\s","").split(",") val directory = PsiDirectoryImpl( PsiManagerImpl(context.project), - (context.project.guessProjectDir() ?: throw RuntimeException("'guessProjectDir' dir returned 'null'")) - .findFileOrDirectory(filePath) ?: throw RuntimeException("Can't find file $filePath") + (context.project.guessProjectDir() ?: throw RuntimeException("Root of the project was not found ")) + .findDirectory(filePath) ?: throw RuntimeException("Can't find file $filePath") ) val templateName = POSSIBLE_FILE_TYPES[fileType.lowercase()] @@ -58,7 +58,9 @@ class CreateKotlinFileCommand(text: String, line: Int) : PerformanceCommandCorou PerformanceTestSpan.TRACER.spanBuilder(NAME).useWithScope { val createdFile = CreateFileFromTemplateAction .createFileFromTemplate(fileName, template, directory, null, true) - createdFile?.let { LOG.info("Created kotlin file\n${createdFile.text}") } + createdFile?.let { + LOG.info("Created kotlin file\n${createdFile.text}") + } } })) From 736eb45070ff50aaf847f467647770e1d7dc3181 Mon Sep 17 00:00:00 2001 From: Dima Golovkov Date: Thu, 29 Jun 2023 16:17:35 +0300 Subject: [PATCH 153/226] Add changedFile, changedFiles, diagramDiff, server icons for intUI GitOrigin-RevId: 9695dae935459baab6007e9397a9b4b9f31fd27f --- platform/icons/src/PlatformIconMappings.json | 11 ++++++++++- platform/icons/src/expui/actions/diagramDiff.svg | 5 +++++ .../icons/src/expui/actions/diagramDiff_dark.svg | 5 +++++ platform/icons/src/expui/fileTypes/changedFile.svg | 7 +++++++ .../icons/src/expui/fileTypes/changedFile_dark.svg | 7 +++++++ .../icons/src/expui/fileTypes/changedFiles.svg | 6 ++++++ .../src/expui/fileTypes/changedFiles_dark.svg | 6 ++++++ platform/icons/src/expui/webReferences/server.svg | 14 ++++++++++++++ .../icons/src/expui/webReferences/server_dark.svg | 14 ++++++++++++++ .../util/ui/src/com/intellij/icons/ExpUiIcons.java | 7 +++++++ 10 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 platform/icons/src/expui/actions/diagramDiff.svg create mode 100644 platform/icons/src/expui/actions/diagramDiff_dark.svg create mode 100644 platform/icons/src/expui/fileTypes/changedFile.svg create mode 100644 platform/icons/src/expui/fileTypes/changedFile_dark.svg create mode 100644 platform/icons/src/expui/fileTypes/changedFiles.svg create mode 100644 platform/icons/src/expui/fileTypes/changedFiles_dark.svg create mode 100644 platform/icons/src/expui/webReferences/server.svg create mode 100644 platform/icons/src/expui/webReferences/server_dark.svg diff --git a/platform/icons/src/PlatformIconMappings.json b/platform/icons/src/PlatformIconMappings.json index f3f483e5a927..6d818a7c4f69 100644 --- a/platform/icons/src/PlatformIconMappings.json +++ b/platform/icons/src/PlatformIconMappings.json @@ -3,6 +3,7 @@ "actions": { "buildAutoReloadChanges.svg": "actions/buildAutoReloadChanges.svg", "deploy.svg": "nodes/deploy.svg", + "diagramDiff.svg": "actions/diagramDiff.svg", "diffWithClipboard.svg": "actions/diffWithClipboard.svg", "filterdups.svg": "toolbar/filterdups.svg", "generated.svg": "actions/generatedFolder.svg", @@ -160,6 +161,8 @@ "nodes/ppJar.svg" ], "aspectJ.svg": "fileTypes/aspectj.svg", + "changedFile.svg": "scope/changedFiles.svg", + "changedFiles.svg": "scope/changedFilesAll.svg", "config.svg": "fileTypes/config.svg", "css.svg": "fileTypes/css.svg", "cucumber.svg": "org/jetbrains/plugins/cucumber/icons/cucumber.svg", @@ -658,7 +661,10 @@ "viewBreakpoints.svg": "debugger/viewBreakpoints.svg" }, "runConfigurations": { - "application.svg": "runConfigurations/application.svg", + "application.svg": [ + "runConfigurations/application.svg", + "runConfigurations/applet.svg" + ], "applicationRemote.svg": "runConfigurations/remote.svg", "compound.svg": "runConfigurations/compound.svg", "invalidConfigurationLayer.svg": "runConfigurations/invalidConfigurationLayer.svg", @@ -748,6 +754,9 @@ "update.svg": "actions/checkOut.svg", "vcs.svg": "vcs/branchNode.svg" }, + "webReferences": { + "server.svg": "webreferences/server.svg" + }, "welcome": { "createNewProjectTab.svg": "welcome/createNewProjectTab.svg", "fromVCSTab.svg": "welcome/fromVCSTab.svg", diff --git a/platform/icons/src/expui/actions/diagramDiff.svg b/platform/icons/src/expui/actions/diagramDiff.svg new file mode 100644 index 000000000000..abf0dffa4b0f --- /dev/null +++ b/platform/icons/src/expui/actions/diagramDiff.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/actions/diagramDiff_dark.svg b/platform/icons/src/expui/actions/diagramDiff_dark.svg new file mode 100644 index 000000000000..714838287621 --- /dev/null +++ b/platform/icons/src/expui/actions/diagramDiff_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/fileTypes/changedFile.svg b/platform/icons/src/expui/fileTypes/changedFile.svg new file mode 100644 index 000000000000..4578be9c93c1 --- /dev/null +++ b/platform/icons/src/expui/fileTypes/changedFile.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platform/icons/src/expui/fileTypes/changedFile_dark.svg b/platform/icons/src/expui/fileTypes/changedFile_dark.svg new file mode 100644 index 000000000000..5e8be56c5bed --- /dev/null +++ b/platform/icons/src/expui/fileTypes/changedFile_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platform/icons/src/expui/fileTypes/changedFiles.svg b/platform/icons/src/expui/fileTypes/changedFiles.svg new file mode 100644 index 000000000000..976e2120d6b2 --- /dev/null +++ b/platform/icons/src/expui/fileTypes/changedFiles.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/platform/icons/src/expui/fileTypes/changedFiles_dark.svg b/platform/icons/src/expui/fileTypes/changedFiles_dark.svg new file mode 100644 index 000000000000..2325f946fd1e --- /dev/null +++ b/platform/icons/src/expui/fileTypes/changedFiles_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/platform/icons/src/expui/webReferences/server.svg b/platform/icons/src/expui/webReferences/server.svg new file mode 100644 index 000000000000..7da67bb33993 --- /dev/null +++ b/platform/icons/src/expui/webReferences/server.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/platform/icons/src/expui/webReferences/server_dark.svg b/platform/icons/src/expui/webReferences/server_dark.svg new file mode 100644 index 000000000000..b07f67d94cdb --- /dev/null +++ b/platform/icons/src/expui/webReferences/server_dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java index 9c4a21d0345f..07ad598df65b 100644 --- a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java +++ b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java @@ -19,6 +19,7 @@ public final class ExpUiIcons { /** 16x16 */ public static final @NotNull Icon BuildAutoReloadChanges = load("expui/actions/buildAutoReloadChanges.svg", -769137589, 2); /** 16x16 */ public static final @NotNull Icon ClearCash = load("expui/actions/clearCash.svg", -651670985, 2); /** 16x16 */ public static final @NotNull Icon Deploy = load("expui/actions/deploy.svg", -42046735, 2); + /** 16x16 */ public static final @NotNull Icon DiagramDiff = load("expui/actions/diagramDiff.svg", 2129574955, 2); /** 16x16 */ public static final @NotNull Icon DiffWithClipboard = load("expui/actions/diffWithClipboard.svg", -1141011475, 2); /** 16x16 */ public static final @NotNull Icon Filterdups = load("expui/actions/filterdups.svg", -1675572656, 2); /** 16x16 */ public static final @NotNull Icon Generated = load("expui/actions/generated.svg", -1905788368, 2); @@ -181,6 +182,8 @@ public final class ExpUiIcons { /** 16x16 */ public static final @NotNull Icon AnyType = load("expui/fileTypes/anyType.svg", 1371529814, 2); /** 16x16 */ public static final @NotNull Icon Archive = load("expui/fileTypes/archive.svg", -782079458, 2); /** 16x16 */ public static final @NotNull Icon AspectJ = load("expui/fileTypes/aspectJ.svg", 2084203057, 2); + /** 16x16 */ public static final @NotNull Icon ChangedFile = load("expui/fileTypes/changedFile.svg", -1545199036, 2); + /** 16x16 */ public static final @NotNull Icon ChangedFiles = load("expui/fileTypes/changedFiles.svg", -1547714866, 2); /** 16x16 */ public static final @NotNull Icon Config = load("expui/fileTypes/config.svg", 1239979240, 2); /** 16x16 */ public static final @NotNull Icon Css = load("expui/fileTypes/css.svg", 1158571392, 0); /** 16x16 */ public static final @NotNull Icon Csv = load("expui/fileTypes/csv.svg", -2009889099, 2); @@ -700,6 +703,10 @@ public final class ExpUiIcons { /** 16x16 */ public static final @NotNull Icon Vcs = load("expui/vcs/vcs.svg", 468795750, 2); } + public static final class WebReferences { + /** 16x16 */ public static final @NotNull Icon Server = load("expui/webReferences/server.svg", 1021314784, 2); + } + public static final class Welcome { /** 20x20 */ public static final @NotNull Icon CreateNewProjectTab = load("expui/welcome/createNewProjectTab.svg", 78176762, 2); /** 20x20 */ public static final @NotNull Icon FromVCSTab = load("expui/welcome/fromVCSTab.svg", 587255847, 2); From caddba58742540a7fa822a47b3558cc81bc1e84b Mon Sep 17 00:00:00 2001 From: Dima Golovkov Date: Thu, 29 Jun 2023 17:16:18 +0300 Subject: [PATCH 154/226] Add icons for Reformat Code and Minimap actions GitOrigin-RevId: 9c98ef74cabe7fd9a5472cb247818918edca3015 --- platform/icons/src/PlatformIconMappings.json | 2 ++ platform/icons/src/actions/reformatCode.svg | 5 +++++ platform/icons/src/actions/reformatCode_dark.svg | 5 +++++ platform/icons/src/expui/actions/minimap.svg | 7 +++++++ platform/icons/src/expui/actions/minimap_dark.svg | 7 +++++++ platform/icons/src/expui/actions/reformatCode.svg | 8 ++++++++ platform/icons/src/expui/actions/reformatCode_dark.svg | 8 ++++++++ platform/platform-resources/src/idea/LangActions.xml | 2 +- platform/util/ui/src/com/intellij/icons/AllIcons.java | 1 + platform/util/ui/src/com/intellij/icons/ExpUiIcons.java | 2 ++ 10 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 platform/icons/src/actions/reformatCode.svg create mode 100644 platform/icons/src/actions/reformatCode_dark.svg create mode 100644 platform/icons/src/expui/actions/minimap.svg create mode 100644 platform/icons/src/expui/actions/minimap_dark.svg create mode 100644 platform/icons/src/expui/actions/reformatCode.svg create mode 100644 platform/icons/src/expui/actions/reformatCode_dark.svg diff --git a/platform/icons/src/PlatformIconMappings.json b/platform/icons/src/PlatformIconMappings.json index 6d818a7c4f69..5d5c71e3f5bb 100644 --- a/platform/icons/src/PlatformIconMappings.json +++ b/platform/icons/src/PlatformIconMappings.json @@ -14,6 +14,7 @@ "inSelection.svg": "actions/inSelection.svg", "install.svg": "actions/install.svg", "lightning.svg": "actions/lightning.svg", + "minimap.svg": "actions/minimap.svg", "moveToBottomLeft.svg": "actions/moveToBottomLeft.svg", "moveToBottomRight.svg": "actions/moveToBottomRight.svg", "moveToButton.svg": "actions/move-to-button.svg", @@ -29,6 +30,7 @@ "profileCPU.svg": "actions/profileCPU.svg", "projectDirectory.svg": "actions/projectDirectory.svg", "runAll.svg": "actions/runAll.svg", + "reformatCode.svg": "actions/reformatCode.svg", "showReadAccess.svg": "actions/showReadAccess.svg", "showWriteAccess.svg": "actions/showWriteAccess.svg", "swapPanels.svg": "actions/swapPanels.svg", diff --git a/platform/icons/src/actions/reformatCode.svg b/platform/icons/src/actions/reformatCode.svg new file mode 100644 index 000000000000..2a184cb1bbf7 --- /dev/null +++ b/platform/icons/src/actions/reformatCode.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/actions/reformatCode_dark.svg b/platform/icons/src/actions/reformatCode_dark.svg new file mode 100644 index 000000000000..5b649bcb5fbc --- /dev/null +++ b/platform/icons/src/actions/reformatCode_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/actions/minimap.svg b/platform/icons/src/expui/actions/minimap.svg new file mode 100644 index 000000000000..f24d3b7afe4e --- /dev/null +++ b/platform/icons/src/expui/actions/minimap.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platform/icons/src/expui/actions/minimap_dark.svg b/platform/icons/src/expui/actions/minimap_dark.svg new file mode 100644 index 000000000000..3fc7dc1b710d --- /dev/null +++ b/platform/icons/src/expui/actions/minimap_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platform/icons/src/expui/actions/reformatCode.svg b/platform/icons/src/expui/actions/reformatCode.svg new file mode 100644 index 000000000000..ef85a66bdf04 --- /dev/null +++ b/platform/icons/src/expui/actions/reformatCode.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/platform/icons/src/expui/actions/reformatCode_dark.svg b/platform/icons/src/expui/actions/reformatCode_dark.svg new file mode 100644 index 000000000000..20872d3a2cb9 --- /dev/null +++ b/platform/icons/src/expui/actions/reformatCode_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index a13e0a9c0da4..01460ee9ec9a 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -604,7 +604,7 @@
- + diff --git a/platform/util/ui/src/com/intellij/icons/AllIcons.java b/platform/util/ui/src/com/intellij/icons/AllIcons.java index 940543c940f6..4711b9b2d0d1 100644 --- a/platform/util/ui/src/com/intellij/icons/AllIcons.java +++ b/platform/util/ui/src/com/intellij/icons/AllIcons.java @@ -162,6 +162,7 @@ public class AllIcons { /** 16x16 */ public static final @NotNull Icon RealIntentionBulb = load("actions/realIntentionBulb.svg", 516517225, 2); /** 16x16 */ public static final @NotNull Icon Redo = load("actions/redo.svg", 1384796752, 2); /** 16x16 */ public static final @NotNull Icon RefactoringBulb = load("actions/refactoringBulb.svg", -1341396806, 2); + /** 16x16 */ public static final @NotNull Icon ReformatCode = load("actions/reformatCode.svg", 1503774223, 2); /** 16x16 */ public static final @NotNull Icon Refresh = load("actions/refresh.svg", 954789704, 2); /** 16x16 */ public static final @NotNull Icon Regex = load("actions/regex.svg", -669040651, 0); /** 16x16 */ public static final @NotNull Icon RegexHovered = load("actions/regexHovered.svg", -17694115, 0); diff --git a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java index 07ad598df65b..f7948fc38af9 100644 --- a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java +++ b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java @@ -30,6 +30,7 @@ public final class ExpUiIcons { /** 16x16 */ public static final @NotNull Icon InSelection = load("expui/actions/inSelection.svg", -672670687, 2); /** 16x16 */ public static final @NotNull Icon Install = load("expui/actions/install.svg", 1754913287, 2); /** 16x16 */ public static final @NotNull Icon Lightning = load("expui/actions/lightning.svg", -270648659, 2); + /** 16x16 */ public static final @NotNull Icon Minimap = load("expui/actions/minimap.svg", -1838091231, 2); /** 16x16 */ public static final @NotNull Icon MoveToBottomLeft = load("expui/actions/moveToBottomLeft.svg", -1880102300, 2); /** 16x16 */ public static final @NotNull Icon MoveToBottomRight = load("expui/actions/moveToBottomRight.svg", 742208591, 2); /** 16x16 */ public static final @NotNull Icon MoveToButton = load("expui/actions/moveToButton.svg", -483907299, 2); @@ -44,6 +45,7 @@ public final class ExpUiIcons { /** 16x16 */ public static final @NotNull Icon PlayLast = load("expui/actions/playLast.svg", -236076917, 2); /** 16x16 */ public static final @NotNull Icon ProfileCPU = load("expui/actions/profileCPU.svg", -143458575, 2); /** 16x16 */ public static final @NotNull Icon ProjectDirectory = load("expui/actions/projectDirectory.svg", 1333538549, 2); + /** 16x16 */ public static final @NotNull Icon ReformatCode = load("expui/actions/reformatCode.svg", 1018232520, 2); /** 16x16 */ public static final @NotNull Icon RunAll = load("expui/actions/runAll.svg", 892135407, 2); /** 16x16 */ public static final @NotNull Icon ShowImportStatements = load("expui/actions/showImportStatements.svg", 935761482, 2); /** 16x16 */ public static final @NotNull Icon ShowReadAccess = load("expui/actions/showReadAccess.svg", 432207500, 2); From fa877198164e80bb27f59d90b3e00c7a5c613476 Mon Sep 17 00:00:00 2001 From: Dima Golovkov Date: Fri, 30 Jun 2023 22:25:10 +0300 Subject: [PATCH 155/226] Add icons for IntUI - split.svg - subtypes.svg - supertypes.svg - uiForm.svg - fix mapping for keymapEditor.svg, keymapMainMenu.svg, keymapTools.svg, keymapAnt.svg, keymapOther.svg GitOrigin-RevId: 4f5a0f11b05269acbaba77fb1c48097224e326ca --- platform/icons/src/PlatformIconMappings.json | 20 +++++++++++++++++-- platform/icons/src/expui/actions/split.svg | 7 +++++++ .../icons/src/expui/actions/split_dark.svg | 7 +++++++ platform/icons/src/expui/fileTypes/uiForm.svg | 4 ++++ .../icons/src/expui/fileTypes/uiForm_dark.svg | 11 ++++++++++ .../icons/src/expui/hierarchy/subtypes.svg | 5 +++++ .../src/expui/hierarchy/subtypes_dark.svg | 5 +++++ .../icons/src/expui/hierarchy/supertypes.svg | 5 +++++ .../src/expui/hierarchy/supertypes_dark.svg | 5 +++++ .../ui/src/com/intellij/icons/ExpUiIcons.java | 7 +++++++ 10 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 platform/icons/src/expui/actions/split.svg create mode 100644 platform/icons/src/expui/actions/split_dark.svg create mode 100644 platform/icons/src/expui/fileTypes/uiForm.svg create mode 100644 platform/icons/src/expui/fileTypes/uiForm_dark.svg create mode 100644 platform/icons/src/expui/hierarchy/subtypes.svg create mode 100644 platform/icons/src/expui/hierarchy/subtypes_dark.svg create mode 100644 platform/icons/src/expui/hierarchy/supertypes.svg create mode 100644 platform/icons/src/expui/hierarchy/supertypes_dark.svg diff --git a/platform/icons/src/PlatformIconMappings.json b/platform/icons/src/PlatformIconMappings.json index 5d5c71e3f5bb..b769e349fc0b 100644 --- a/platform/icons/src/PlatformIconMappings.json +++ b/platform/icons/src/PlatformIconMappings.json @@ -33,6 +33,7 @@ "reformatCode.svg": "actions/reformatCode.svg", "showReadAccess.svg": "actions/showReadAccess.svg", "showWriteAccess.svg": "actions/showWriteAccess.svg", + "split.svg": "modules/split.svg", "swapPanels.svg": "actions/swapPanels.svg", "synchronizeScrolling.svg": "actions/synchronizeScrolling.svg", "showImportStatements.svg": "actions/showImportStatements.svg", @@ -176,7 +177,10 @@ "ideaModule.svg": "nodes/ideaModule.svg", "idl.svg": "fileTypes/idl.svg", "ignored.svg": "vcs/ignore_file.svg", - "java.svg": "fileTypes/java.svg", + "java.svg": [ + "fileTypes/java.svg", + "fileTypes/javaOutsideSource.svg" + ], "javaScript.svg": "fileTypes/javaScript.svg", "jest.svg": "icons/fileTypes/jestSnapshot.svg", "jfr.svg": "fileTypes/jfr.svg", @@ -207,6 +211,7 @@ "fileTypes/custom.svg", "fileTypes/text.svg" ], + "uiForm.svg": "fileTypes/uiForm.svg", "image.svg": "fileTypes/image.svg", "unknown.svg": "fileTypes/unknown.svg", "vueJs.svg": "icons/vue.svg", @@ -402,6 +407,10 @@ "suggestedRefactoringDisabled.svg": "gutter/suggestedRefactoringBulbDisabled.svg", "writeAccess.svg": "gutter/writeAccess.svg" }, + "hierarchy": { + "subtypes.svg": "hierarchy/subtypes.svg", + "supertypes.svg": "hierarchy/supertypes.svg" + }, "ide": { "configFile.svg": "ide/configFile.svg", "externalLink.svg": "ide/external_link_arrow.svg", @@ -513,7 +522,14 @@ "excludeRoot.svg": "modules/excludeRoot.svg", "excludedGenerated.svg": "modules/excludedGeneratedRoot.svg", "field.svg": "nodes/field.svg", - "folder.svg": "nodes/folder.svg", + "folder.svg": [ + "nodes/folder.svg", + "nodes/keymapAnt.svg", + "nodes/keymapEditor.svg", + "nodes/keymapMainMenu.svg", + "nodes/keymapOther.svg", + "nodes/keymapTools.svg" + ], "function.svg": "nodes/function.svg", "generated.svg": "modules/generatedFolder.svg", "generatedSource.svg": "modules/generatedSourceRoot.svg", diff --git a/platform/icons/src/expui/actions/split.svg b/platform/icons/src/expui/actions/split.svg new file mode 100644 index 000000000000..c972abfb842a --- /dev/null +++ b/platform/icons/src/expui/actions/split.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platform/icons/src/expui/actions/split_dark.svg b/platform/icons/src/expui/actions/split_dark.svg new file mode 100644 index 000000000000..2c9d204f7c53 --- /dev/null +++ b/platform/icons/src/expui/actions/split_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platform/icons/src/expui/fileTypes/uiForm.svg b/platform/icons/src/expui/fileTypes/uiForm.svg new file mode 100644 index 000000000000..23a796e89481 --- /dev/null +++ b/platform/icons/src/expui/fileTypes/uiForm.svg @@ -0,0 +1,4 @@ + + + + diff --git a/platform/icons/src/expui/fileTypes/uiForm_dark.svg b/platform/icons/src/expui/fileTypes/uiForm_dark.svg new file mode 100644 index 000000000000..caf70e0861ab --- /dev/null +++ b/platform/icons/src/expui/fileTypes/uiForm_dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/platform/icons/src/expui/hierarchy/subtypes.svg b/platform/icons/src/expui/hierarchy/subtypes.svg new file mode 100644 index 000000000000..df40830ddabd --- /dev/null +++ b/platform/icons/src/expui/hierarchy/subtypes.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/hierarchy/subtypes_dark.svg b/platform/icons/src/expui/hierarchy/subtypes_dark.svg new file mode 100644 index 000000000000..c416967d15f0 --- /dev/null +++ b/platform/icons/src/expui/hierarchy/subtypes_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/hierarchy/supertypes.svg b/platform/icons/src/expui/hierarchy/supertypes.svg new file mode 100644 index 000000000000..60ceaf9eefb8 --- /dev/null +++ b/platform/icons/src/expui/hierarchy/supertypes.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/hierarchy/supertypes_dark.svg b/platform/icons/src/expui/hierarchy/supertypes_dark.svg new file mode 100644 index 000000000000..31832fe1d6c0 --- /dev/null +++ b/platform/icons/src/expui/hierarchy/supertypes_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java index f7948fc38af9..3664a61c881a 100644 --- a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java +++ b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java @@ -50,6 +50,7 @@ public final class ExpUiIcons { /** 16x16 */ public static final @NotNull Icon ShowImportStatements = load("expui/actions/showImportStatements.svg", 935761482, 2); /** 16x16 */ public static final @NotNull Icon ShowReadAccess = load("expui/actions/showReadAccess.svg", 432207500, 2); /** 16x16 */ public static final @NotNull Icon ShowWriteAccess = load("expui/actions/showWriteAccess.svg", 799113071, 2); + /** 16x16 */ public static final @NotNull Icon Split = load("expui/actions/split.svg", 1102270400, 2); /** 16x16 */ public static final @NotNull Icon SwapPanels = load("expui/actions/swapPanels.svg", 2147313806, 2); /** 16x16 */ public static final @NotNull Icon SynchronizeScrolling = load("expui/actions/synchronizeScrolling.svg", -731160875, 2); /** 16x16 */ public static final @NotNull Icon ToggleVisibility = load("expui/actions/toggleVisibility.svg", 2137980334, 2); @@ -229,6 +230,7 @@ public final class ExpUiIcons { /** 16x16 */ public static final @NotNull Icon SourceMap = load("expui/fileTypes/sourceMap.svg", -798309148, 2); /** 16x16 */ public static final @NotNull Icon Sql = load("expui/fileTypes/sql.svg", -1496861857, 2); /** 16x16 */ public static final @NotNull Icon Text = load("expui/fileTypes/text.svg", 1946633559, 2); + /** 16x16 */ public static final @NotNull Icon UiForm = load("expui/fileTypes/uiForm.svg", -397412144, 2); /** 16x16 */ public static final @NotNull Icon Unknown = load("expui/fileTypes/unknown.svg", -2043297803, 2); /** 16x16 */ public static final @NotNull Icon VueJs = load("expui/fileTypes/vueJs.svg", -1118824585, 0); /** 16x16 */ public static final @NotNull Icon Wsdl = load("expui/fileTypes/wsdl.svg", 53700367, 2); @@ -381,6 +383,11 @@ public final class ExpUiIcons { /** 14x14 */ public static final @NotNull Icon WriteAccess = load("expui/gutter/writeAccess.svg", -998663344, 2); } + public static final class Hierarchy { + /** 16x16 */ public static final @NotNull Icon Subtypes = load("expui/hierarchy/subtypes.svg", -570232233, 2); + /** 16x16 */ public static final @NotNull Icon Supertypes = load("expui/hierarchy/supertypes.svg", 1662070576, 2); + } + public static final class Ide { /** 16x16 */ public static final @NotNull Icon ConfigFile = load("expui/ide/configFile.svg", 1264425469, 2); /** 16x16 */ public static final @NotNull Icon ExternalLink = load("expui/ide/externalLink.svg", -932621117, 2); From a071f88dbb39b6d03237eea6ab7e6e45a668f0ae Mon Sep 17 00:00:00 2001 From: Dima Golovkov Date: Sun, 2 Jul 2023 18:06:11 +0300 Subject: [PATCH 156/226] Update move icons icon for IntUI GitOrigin-RevId: ee30bbcc4c07a0be079c6fa5992fa2371f417a76 --- .../icons/src/expui/actions/moveToBottomLeft.svg | 2 +- .../src/expui/actions/moveToBottomLeft_dark.svg | 2 +- .../icons/src/expui/actions/moveToBottomRight.svg | 2 +- .../src/expui/actions/moveToBottomRight_dark.svg | 2 +- .../icons/src/expui/actions/moveToLeftBottom.svg | 2 +- .../src/expui/actions/moveToLeftBottom_dark.svg | 2 +- platform/icons/src/expui/actions/moveToLeftTop.svg | 2 +- .../icons/src/expui/actions/moveToLeftTop_dark.svg | 2 +- .../icons/src/expui/actions/moveToRightBottom.svg | 2 +- .../src/expui/actions/moveToRightBottom_dark.svg | 2 +- platform/icons/src/expui/actions/moveToRightTop.svg | 2 +- .../icons/src/expui/actions/moveToRightTop_dark.svg | 2 +- .../util/ui/src/com/intellij/icons/ExpUiIcons.java | 12 ++++++------ 13 files changed, 18 insertions(+), 18 deletions(-) diff --git a/platform/icons/src/expui/actions/moveToBottomLeft.svg b/platform/icons/src/expui/actions/moveToBottomLeft.svg index 71995c0cd8a1..889d0cea2e55 100644 --- a/platform/icons/src/expui/actions/moveToBottomLeft.svg +++ b/platform/icons/src/expui/actions/moveToBottomLeft.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToBottomLeft_dark.svg b/platform/icons/src/expui/actions/moveToBottomLeft_dark.svg index 55ba3445b977..d59acfa8e345 100644 --- a/platform/icons/src/expui/actions/moveToBottomLeft_dark.svg +++ b/platform/icons/src/expui/actions/moveToBottomLeft_dark.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToBottomRight.svg b/platform/icons/src/expui/actions/moveToBottomRight.svg index b083a5428d1c..6b2124087bb0 100644 --- a/platform/icons/src/expui/actions/moveToBottomRight.svg +++ b/platform/icons/src/expui/actions/moveToBottomRight.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToBottomRight_dark.svg b/platform/icons/src/expui/actions/moveToBottomRight_dark.svg index d3195f19de7e..84a3ad19af0b 100644 --- a/platform/icons/src/expui/actions/moveToBottomRight_dark.svg +++ b/platform/icons/src/expui/actions/moveToBottomRight_dark.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToLeftBottom.svg b/platform/icons/src/expui/actions/moveToLeftBottom.svg index a09ab6037203..f41217d87139 100644 --- a/platform/icons/src/expui/actions/moveToLeftBottom.svg +++ b/platform/icons/src/expui/actions/moveToLeftBottom.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToLeftBottom_dark.svg b/platform/icons/src/expui/actions/moveToLeftBottom_dark.svg index 38a9308a9886..96000e7dd292 100644 --- a/platform/icons/src/expui/actions/moveToLeftBottom_dark.svg +++ b/platform/icons/src/expui/actions/moveToLeftBottom_dark.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToLeftTop.svg b/platform/icons/src/expui/actions/moveToLeftTop.svg index def3718e2c9b..e6ae3bf1ff90 100644 --- a/platform/icons/src/expui/actions/moveToLeftTop.svg +++ b/platform/icons/src/expui/actions/moveToLeftTop.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToLeftTop_dark.svg b/platform/icons/src/expui/actions/moveToLeftTop_dark.svg index eaaf69c566e3..f2ed50f0b55e 100644 --- a/platform/icons/src/expui/actions/moveToLeftTop_dark.svg +++ b/platform/icons/src/expui/actions/moveToLeftTop_dark.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToRightBottom.svg b/platform/icons/src/expui/actions/moveToRightBottom.svg index b011d9e4a6ee..292b4e348219 100644 --- a/platform/icons/src/expui/actions/moveToRightBottom.svg +++ b/platform/icons/src/expui/actions/moveToRightBottom.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToRightBottom_dark.svg b/platform/icons/src/expui/actions/moveToRightBottom_dark.svg index bb2f3bf499c3..4ab6eed6609d 100644 --- a/platform/icons/src/expui/actions/moveToRightBottom_dark.svg +++ b/platform/icons/src/expui/actions/moveToRightBottom_dark.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToRightTop.svg b/platform/icons/src/expui/actions/moveToRightTop.svg index 84fa31fa983d..e775b5e325b8 100644 --- a/platform/icons/src/expui/actions/moveToRightTop.svg +++ b/platform/icons/src/expui/actions/moveToRightTop.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/icons/src/expui/actions/moveToRightTop_dark.svg b/platform/icons/src/expui/actions/moveToRightTop_dark.svg index 01f8611b0ed8..32541012759e 100644 --- a/platform/icons/src/expui/actions/moveToRightTop_dark.svg +++ b/platform/icons/src/expui/actions/moveToRightTop_dark.svg @@ -1,4 +1,4 @@ - + diff --git a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java index 3664a61c881a..5eb9838cd48a 100644 --- a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java +++ b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java @@ -31,13 +31,13 @@ public final class ExpUiIcons { /** 16x16 */ public static final @NotNull Icon Install = load("expui/actions/install.svg", 1754913287, 2); /** 16x16 */ public static final @NotNull Icon Lightning = load("expui/actions/lightning.svg", -270648659, 2); /** 16x16 */ public static final @NotNull Icon Minimap = load("expui/actions/minimap.svg", -1838091231, 2); - /** 16x16 */ public static final @NotNull Icon MoveToBottomLeft = load("expui/actions/moveToBottomLeft.svg", -1880102300, 2); - /** 16x16 */ public static final @NotNull Icon MoveToBottomRight = load("expui/actions/moveToBottomRight.svg", 742208591, 2); + /** 16x16 */ public static final @NotNull Icon MoveToBottomLeft = load("expui/actions/moveToBottomLeft.svg", -1473386956, 2); + /** 16x16 */ public static final @NotNull Icon MoveToBottomRight = load("expui/actions/moveToBottomRight.svg", 1803793130, 2); /** 16x16 */ public static final @NotNull Icon MoveToButton = load("expui/actions/moveToButton.svg", -483907299, 2); - /** 16x16 */ public static final @NotNull Icon MoveToLeftBottom = load("expui/actions/moveToLeftBottom.svg", -1805039462, 2); - /** 16x16 */ public static final @NotNull Icon MoveToLeftTop = load("expui/actions/moveToLeftTop.svg", 1510043922, 2); - /** 16x16 */ public static final @NotNull Icon MoveToRightBottom = load("expui/actions/moveToRightBottom.svg", -622483511, 2); - /** 16x16 */ public static final @NotNull Icon MoveToRightTop = load("expui/actions/moveToRightTop.svg", 532814306, 2); + /** 16x16 */ public static final @NotNull Icon MoveToLeftBottom = load("expui/actions/moveToLeftBottom.svg", -1236920830, 2); + /** 16x16 */ public static final @NotNull Icon MoveToLeftTop = load("expui/actions/moveToLeftTop.svg", 881154656, 2); + /** 16x16 */ public static final @NotNull Icon MoveToRightBottom = load("expui/actions/moveToRightBottom.svg", 1351639515, 2); + /** 16x16 */ public static final @NotNull Icon MoveToRightTop = load("expui/actions/moveToRightTop.svg", -67380800, 2); /** 16x16 */ public static final @NotNull Icon NewFolder = load("expui/actions/newFolder.svg", 1487335447, 2); /** 16x16 */ public static final @NotNull Icon PlayBack = load("expui/actions/playBack.svg", 1165836244, 2); /** 16x16 */ public static final @NotNull Icon PlayFirst = load("expui/actions/playFirst.svg", -1838173000, 2); From e97dcf0e6395b038887b6db4bade92cf26726ec8 Mon Sep 17 00:00:00 2001 From: Dima Golovkov Date: Sun, 2 Jul 2023 19:21:03 +0300 Subject: [PATCH 157/226] Update icons with external modifier for IntUI GitOrigin-RevId: 829ae9ad40460cf097431fac13be7ed1f87286a6 --- platform/icons/src/expui/run/attachToProcess.svg | 8 ++++---- platform/icons/src/expui/run/attachToProcess_dark.svg | 8 ++++---- .../src/expui/runConfigurations/applicationRemote.svg | 6 +++--- .../expui/runConfigurations/applicationRemote_dark.svg | 6 +++--- platform/util/ui/src/com/intellij/icons/ExpUiIcons.java | 4 ++-- plugins/gradle/resources/icons/expui/gradleNavigate.svg | 6 +++--- .../gradle/resources/icons/expui/gradleNavigate_dark.svg | 6 +++--- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/platform/icons/src/expui/run/attachToProcess.svg b/platform/icons/src/expui/run/attachToProcess.svg index 8ccc5ceaa0c9..a68a716309d4 100644 --- a/platform/icons/src/expui/run/attachToProcess.svg +++ b/platform/icons/src/expui/run/attachToProcess.svg @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/platform/icons/src/expui/run/attachToProcess_dark.svg b/platform/icons/src/expui/run/attachToProcess_dark.svg index a7a6ec938cf5..d498d92f8314 100644 --- a/platform/icons/src/expui/run/attachToProcess_dark.svg +++ b/platform/icons/src/expui/run/attachToProcess_dark.svg @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/platform/icons/src/expui/runConfigurations/applicationRemote.svg b/platform/icons/src/expui/runConfigurations/applicationRemote.svg index 0c48d4be7514..deb5d22422a0 100644 --- a/platform/icons/src/expui/runConfigurations/applicationRemote.svg +++ b/platform/icons/src/expui/runConfigurations/applicationRemote.svg @@ -1,8 +1,8 @@ - - + + - + diff --git a/platform/icons/src/expui/runConfigurations/applicationRemote_dark.svg b/platform/icons/src/expui/runConfigurations/applicationRemote_dark.svg index bcbf16adcb5a..43a5e7e456ad 100644 --- a/platform/icons/src/expui/runConfigurations/applicationRemote_dark.svg +++ b/platform/icons/src/expui/runConfigurations/applicationRemote_dark.svg @@ -1,11 +1,11 @@ - - + + - + diff --git a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java index 5eb9838cd48a..f69bcf3afd73 100644 --- a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java +++ b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java @@ -543,7 +543,7 @@ public final class ExpUiIcons { } public static final class Run { - /** 16x16 */ public static final @NotNull Icon AttachToProcess = load("expui/run/attachToProcess.svg", -1557990976, 2); + /** 16x16 */ public static final @NotNull Icon AttachToProcess = load("expui/run/attachToProcess.svg", 1612859511, 2); /** 16x16 */ public static final @NotNull Icon Debug = load("expui/run/debug.svg", 1409937178, 10); /** 16x16 */ public static final @NotNull Icon DumpThreads = load("expui/run/dumpThreads.svg", -887924950, 2); /** 16x16 */ public static final @NotNull Icon EvaluateExpression = load("expui/run/evaluateExpression.svg", -1931888328, 2); @@ -593,7 +593,7 @@ public final class ExpUiIcons { public static final class RunConfigurations { /** 16x16 */ public static final @NotNull Icon Application = load("expui/runConfigurations/application.svg", 326858300, 2); - /** 16x16 */ public static final @NotNull Icon ApplicationRemote = load("expui/runConfigurations/applicationRemote.svg", 1461896360, 2); + /** 16x16 */ public static final @NotNull Icon ApplicationRemote = load("expui/runConfigurations/applicationRemote.svg", -111652439, 2); /** 16x16 */ public static final @NotNull Icon Compound = load("expui/runConfigurations/compound.svg", 1035092097, 2); /** 16x16 */ public static final @NotNull Icon InvalidConfigurationLayer = load("expui/runConfigurations/invalidConfigurationLayer.svg", 3963890, 2); /** 16x16 */ public static final @NotNull Icon Junit = load("expui/runConfigurations/junit.svg", 884878395, 2); diff --git a/plugins/gradle/resources/icons/expui/gradleNavigate.svg b/plugins/gradle/resources/icons/expui/gradleNavigate.svg index dc01ce6d5b83..16687cc32a58 100644 --- a/plugins/gradle/resources/icons/expui/gradleNavigate.svg +++ b/plugins/gradle/resources/icons/expui/gradleNavigate.svg @@ -1,6 +1,6 @@ - - - + + + diff --git a/plugins/gradle/resources/icons/expui/gradleNavigate_dark.svg b/plugins/gradle/resources/icons/expui/gradleNavigate_dark.svg index 300e42e1444f..2f9b28aea6d3 100644 --- a/plugins/gradle/resources/icons/expui/gradleNavigate_dark.svg +++ b/plugins/gradle/resources/icons/expui/gradleNavigate_dark.svg @@ -1,6 +1,6 @@ - - - + + + From 12e2e68b76860477be19d0899494ca71807439c1 Mon Sep 17 00:00:00 2001 From: Dima Golovkov Date: Mon, 3 Jul 2023 02:01:34 +0300 Subject: [PATCH 158/226] Add toolWindowJsonPath icons for IntUI GitOrigin-RevId: 5aaa3833bf8c097d73afb5c2a8e13ec8611f5904 --- platform/icons/src/PlatformIconMappings.json | 1 + platform/icons/src/expui/toolwindow/toolWindowJsonPath.svg | 5 +++++ .../icons/src/expui/toolwindow/toolWindowJsonPath@20x20.svg | 5 +++++ .../src/expui/toolwindow/toolWindowJsonPath@20x20_dark.svg | 5 +++++ .../icons/src/expui/toolwindow/toolWindowJsonPath_dark.svg | 5 +++++ platform/util/ui/src/com/intellij/icons/ExpUiIcons.java | 2 ++ 6 files changed, 23 insertions(+) create mode 100644 platform/icons/src/expui/toolwindow/toolWindowJsonPath.svg create mode 100644 platform/icons/src/expui/toolwindow/toolWindowJsonPath@20x20.svg create mode 100644 platform/icons/src/expui/toolwindow/toolWindowJsonPath@20x20_dark.svg create mode 100644 platform/icons/src/expui/toolwindow/toolWindowJsonPath_dark.svg diff --git a/platform/icons/src/PlatformIconMappings.json b/platform/icons/src/PlatformIconMappings.json index b769e349fc0b..cd8c7dd1e5fc 100644 --- a/platform/icons/src/PlatformIconMappings.json +++ b/platform/icons/src/PlatformIconMappings.json @@ -736,6 +736,7 @@ "settingSync.svg": "toolwindows/settingSync.svg", "structure.svg": "toolwindows/toolWindowStructure.svg", "todo.svg": "toolwindows/toolWindowTodo.svg", + "toolWindowJsonPath.svg": "toolwindows/toolWindowJsonPath.svg", "toolWindowVariableView.svg": "toolwindows/toolWindowVariableView.svg", "vcs.svg": "toolwindows/toolWindowChanges.svg", "web.svg": [ diff --git a/platform/icons/src/expui/toolwindow/toolWindowJsonPath.svg b/platform/icons/src/expui/toolwindow/toolWindowJsonPath.svg new file mode 100644 index 000000000000..4a962976b22f --- /dev/null +++ b/platform/icons/src/expui/toolwindow/toolWindowJsonPath.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/toolwindow/toolWindowJsonPath@20x20.svg b/platform/icons/src/expui/toolwindow/toolWindowJsonPath@20x20.svg new file mode 100644 index 000000000000..e93a489a8328 --- /dev/null +++ b/platform/icons/src/expui/toolwindow/toolWindowJsonPath@20x20.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/toolwindow/toolWindowJsonPath@20x20_dark.svg b/platform/icons/src/expui/toolwindow/toolWindowJsonPath@20x20_dark.svg new file mode 100644 index 000000000000..253de11170dc --- /dev/null +++ b/platform/icons/src/expui/toolwindow/toolWindowJsonPath@20x20_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/icons/src/expui/toolwindow/toolWindowJsonPath_dark.svg b/platform/icons/src/expui/toolwindow/toolWindowJsonPath_dark.svg new file mode 100644 index 000000000000..522bb8a380ba --- /dev/null +++ b/platform/icons/src/expui/toolwindow/toolWindowJsonPath_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java index f69bcf3afd73..e216f2842071 100644 --- a/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java +++ b/platform/util/ui/src/com/intellij/icons/ExpUiIcons.java @@ -676,6 +676,8 @@ public final class ExpUiIcons { /** 20x20 */ public static final @NotNull Icon Todo_20x20 = load("expui/toolwindow/todo@20x20.svg", -811890978, 2); /** 16x16 */ public static final @NotNull Icon ToolWindowInternal = load("expui/toolwindow/toolWindowInternal.svg", -1900747368, 2); /** 20x20 */ public static final @NotNull Icon ToolWindowInternal_20x20 = load("expui/toolwindow/toolWindowInternal@20x20.svg", -434982620, 2); + /** 16x16 */ public static final @NotNull Icon ToolWindowJsonPath = load("expui/toolwindow/toolWindowJsonPath.svg", 1764965987, 2); + /** 20x20 */ public static final @NotNull Icon ToolWindowJsonPath_20x20 = load("expui/toolwindow/toolWindowJsonPath@20x20.svg", -308711555, 2); /** 16x16 */ public static final @NotNull Icon ToolWindowVariableView = load("expui/toolwindow/toolWindowVariableView.svg", -944459308, 2); /** 20x20 */ public static final @NotNull Icon ToolWindowVariableView_20x20 = load("expui/toolwindow/toolWindowVariableView@20x20.svg", 1193386499, 2); /** 16x16 */ public static final @NotNull Icon Vcs = load("expui/toolwindow/vcs.svg", 468795750, 2); From 8f50d9437d50dad31067e14101edc5af25fb5159 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 00:20:25 +0200 Subject: [PATCH 159/226] replace UIUtil.decorateWindowHeader with ComponentUtil.decorateWindowHeader GitOrigin-RevId: af66f666c90bd84d54a846a787d5a7b5768fda3f --- .../com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java | 2 +- .../src/com/intellij/openapi/wm/impl/FloatingDecorator.java | 3 +-- .../openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt | 4 ++-- .../platform-impl/src/com/intellij/util/IJSwingUtilities.java | 4 ++-- platform/util/ui/src/com/intellij/util/ui/UIUtil.java | 4 ---- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java index e7a030862fed..d1e031b84d08 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java @@ -392,7 +392,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer { AnCancelAction anCancelAction = new AnCancelAction(); JRootPane rootPane = getRootPane(); - UIUtil.decorateWindowHeader(rootPane); + ComponentUtil.decorateWindowHeader(rootPane); Window window = getWindow(); if (window instanceof JDialog && !((JDialog)window).isUndecorated() && rootPane != null && LoadingState.COMPONENTS_LOADED.isOccurred()) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java index 22bca3b81a09..b56f5b9744f8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java @@ -18,7 +18,6 @@ import com.intellij.ui.*; import com.intellij.ui.paint.LinePainter2D; import com.intellij.util.Alarm; import com.intellij.util.MathUtil; -import com.intellij.util.ui.UIUtil; import kotlin.Unit; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -116,7 +115,7 @@ public final class FloatingDecorator extends JDialog implements FloatingDecorato @Override public void show(){ - UIUtil.decorateWindowHeader(rootPane); + ComponentUtil.decorateWindowHeader(rootPane); ToolbarService.Companion.getInstance().setTransparentTitleBar(this, rootPane, runnable -> { Disposer.register(myDisposable, () -> runnable.run()); return Unit.INSTANCE; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt index 8d3bc911c512..1fd948e307a1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt @@ -160,7 +160,7 @@ open class FlatWelcomeFrame @JvmOverloads constructor( setupCloseAction() MnemonicHelper.init(this) Disposer.register(app, this) - UIUtil.decorateWindowHeader(getRootPane()) + ComponentUtil.decorateWindowHeader(getRootPane()) ToolbarService.getInstance().setTransparentTitleBar( window = this, rootPane = getRootPane(), @@ -212,7 +212,7 @@ open class FlatWelcomeFrame @JvmOverloads constructor( size.width, size.height ) - UIUtil.decorateWindowHeader(getRootPane()) + ComponentUtil.decorateWindowHeader(getRootPane()) title = "" title = welcomeFrameTitle updateAppWindowIcon(this) diff --git a/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java b/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java index adebb7090f13..2025dc02c97c 100644 --- a/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java +++ b/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.util; import com.intellij.openapi.options.advanced.AdvancedSettings; @@ -87,7 +87,7 @@ public final class IJSwingUtilities { if (c instanceof RootPaneContainer) { JRootPane rootPane = ((RootPaneContainer)c).getRootPane(); if (rootPane != null) { - UIUtil.decorateWindowHeader(rootPane); + ComponentUtil.decorateWindowHeader(rootPane); } } diff --git a/platform/util/ui/src/com/intellij/util/ui/UIUtil.java b/platform/util/ui/src/com/intellij/util/ui/UIUtil.java index 6c4894dda122..e604d472d328 100644 --- a/platform/util/ui/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/ui/src/com/intellij/util/ui/UIUtil.java @@ -97,10 +97,6 @@ public final class UIUtil { return Logger.getInstance(UIUtil.class); } - public static void decorateWindowHeader(JRootPane pane) { - ComponentUtil.decorateWindowHeader(pane); - } - public static int getTransparentTitleBarHeight(JRootPane rootPane) { Object property = rootPane.getClientProperty("Window.transparentTitleBarHeight"); if (property instanceof Integer) { From db08620ca9cb50849265f5824fcc74657979220d Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 00:34:48 +0200 Subject: [PATCH 160/226] Rename .java to .kt GitOrigin-RevId: def90ea97a2d4ec38a1bb3f80d762a76a3ee4590 --- .../ui/{ToolbarServiceImpl.java => ToolbarServiceImpl.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename platform/platform-impl/src/com/intellij/ui/{ToolbarServiceImpl.java => ToolbarServiceImpl.kt} (100%) diff --git a/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.java b/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt similarity index 100% rename from platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.java rename to platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt From db45cebeb043ec5de3d7317262c540158c9d3354 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 00:34:49 +0200 Subject: [PATCH 161/226] refactor ToolbarServiceImpl from Java to Kotlin GitOrigin-RevId: 5b6d94b0b3a13b4074860da7fbd6d68d0153dcff --- .../src/com/intellij/ui/ToolbarServiceImpl.kt | 228 ++++++++---------- 1 file changed, 94 insertions(+), 134 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt b/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt index 7596d3def95f..b4b40865b8dd 100644 --- a/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt +++ b/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt @@ -1,159 +1,119 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.ui; +package com.intellij.ui -import com.intellij.openapi.util.SystemInfoRt; -import com.intellij.ui.paint.LinePainter2D; -import com.intellij.util.ui.JBInsets; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; -import kotlin.Unit; -import kotlin.jvm.functions.Function0; -import kotlin.jvm.functions.Function1; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.intellij.openapi.util.SystemInfoRt +import com.intellij.ui.paint.LinePainter2D +import com.intellij.util.ui.JBInsets +import com.intellij.util.ui.JBUI +import com.intellij.util.ui.UIUtil +import java.awt.* +import java.beans.PropertyChangeListener +import javax.swing.JRootPane +import javax.swing.RootPaneContainer +import javax.swing.UIManager +import javax.swing.border.AbstractBorder +import javax.swing.border.Border -import javax.swing.*; -import javax.swing.border.AbstractBorder; -import javax.swing.border.Border; -import java.awt.*; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.beans.PropertyChangeListener; - -public class ToolbarServiceImpl implements ToolbarService { - @Override - public void setCustomTitleBar(@NotNull Window window, @NotNull JRootPane rootPane, @NotNull Function1 onDispose) { - if (SystemInfoRt.isMac) { - if (ExperimentalUI.isNewUI()) { - setCustomTitleForToolbar(window, rootPane, onDispose); - } - else { - setTransparentTitleBar(window, rootPane, onDispose); - } +open class ToolbarServiceImpl : ToolbarService { + override fun setCustomTitleBar(window: Window, rootPane: JRootPane, onDispose: (Runnable) -> Unit) { + if (!SystemInfoRt.isMac) { + return + } + else if (ExperimentalUI.isNewUI()) { + setCustomTitleForToolbar(window = window, rootPane = rootPane, onDispose = onDispose) + } + else { + setTransparentTitleBar(window = window, rootPane = rootPane, onDispose = onDispose) } } - @Override - public void setTransparentTitleBar(@NotNull Window window, - @NotNull JRootPane rootPane, - @Nullable Function0 handlerProvider, - @NotNull Function1 onDispose) { + override fun setTransparentTitleBar(window: Window, + rootPane: JRootPane, + handlerProvider: (() -> FullScreenSupport)?, + onDispose: (Runnable) -> Unit) { + @Suppress("NAME_SHADOWING") + var onDispose = onDispose if (!SystemInfoRt.isMac) { - return; + return } - FullScreenSupport handler = handlerProvider == null ? null : handlerProvider.invoke(); - if (handler != null) { - handler.addListener(window); - } - JBInsets topWindowInset = JBUI.insetsTop(UIUtil.getTransparentTitleBarHeight(rootPane)); - AbstractBorder customBorder = new AbstractBorder() { - @Override - public Insets getBorderInsets(Component c) { - if (handler != null && handler.isFullScreen()) { - return JBInsets.emptyInsets(); - } - return topWindowInset; + val handler = handlerProvider?.invoke() + handler?.addListener(window) + + val topWindowInset = JBUI.insetsTop(UIUtil.getTransparentTitleBarHeight(rootPane)) + val customBorder: AbstractBorder = object : AbstractBorder() { + override fun getBorderInsets(c: Component): Insets { + return if (handler != null && handler.isFullScreen()) JBInsets.emptyInsets() else topWindowInset } - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + override fun paintBorder(c: Component, g: Graphics, x: Int, y: Int, width: Int, height: Int) { if (handler != null && handler.isFullScreen()) { - return; + return } - Graphics2D graphics = (Graphics2D)g.create(); + + val graphics = g.create() as Graphics2D try { - Rectangle headerRectangle = new Rectangle(0, 0, c.getWidth(), topWindowInset.top); - graphics.setColor(UIUtil.getPanelBackground()); - graphics.fill(headerRectangle); - if (window instanceof RootPaneContainer) { - JRootPane pane = ((RootPaneContainer)window).getRootPane(); - if (pane == null || pane.getClientProperty(UIUtil.NO_BORDER_UNDER_WINDOW_TITLE_KEY) == Boolean.FALSE) { - graphics.setColor(JBUI.CurrentTheme.CustomFrameDecorations.separatorForeground()); - LinePainter2D.paint(graphics, 0, topWindowInset.top - 1, c.getWidth(), topWindowInset.top - 1, - LinePainter2D.StrokeType.INSIDE, 1); + val headerRectangle = Rectangle(0, 0, c.width, topWindowInset.top) + graphics.color = JBColor.PanelBackground + graphics.fill(headerRectangle) + if (window is RootPaneContainer) { + val pane = (window as RootPaneContainer).rootPane + if (pane == null || pane.getClientProperty(UIUtil.NO_BORDER_UNDER_WINDOW_TITLE_KEY) == false) { + graphics.color = JBUI.CurrentTheme.CustomFrameDecorations.separatorForeground() + LinePainter2D.paint(graphics, 0.0, (topWindowInset.top - 1).toDouble(), c.width.toDouble(), + (topWindowInset.top - 1).toDouble(), + LinePainter2D.StrokeType.INSIDE, 1.0) } } - Color color = window.isActive() ? JBColor.black : JBColor.gray; - graphics.setColor(color); + val color = if (window.isActive) JBColor.black else JBColor.gray + graphics.color = color } finally { - graphics.dispose(); + graphics.dispose() } } - }; - if (handler != null) { - Function1 onDisposeOld = onDispose; - onDispose = runnable -> { - onDisposeOld.invoke((Runnable)() -> { - runnable.run(); - handler.removeListener(window); - }); - return Unit.INSTANCE; - }; } - doSetCustomTitleBar(window, rootPane, onDispose, customBorder); - } - - private static void setCustomTitleForToolbar(@NotNull Window window, - @NotNull JRootPane rootPane, - Function1 onDispose) { - JBInsets topWindowInset = JBUI.insetsTop(UIUtil.getTransparentTitleBarHeight(rootPane)); - AbstractBorder customBorder = new AbstractBorder() { - @Override - public Insets getBorderInsets(Component c) { - return topWindowInset; - } - - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - Graphics2D graphics = (Graphics2D)g.create(); - try { - Rectangle headerRectangle = new Rectangle(0, 0, c.getWidth(), topWindowInset.top); - Color color = UIManager.getColor("MainToolbar.background"); - graphics.setColor(color != null ? color : UIUtil.getPanelBackground()); - graphics.fill(headerRectangle); - } - finally { - graphics.dispose(); + if (handler != null) { + val onDisposeOld = onDispose + onDispose = { runnable -> + onDisposeOld { + runnable.run() + handler.removeListener(window) } } - }; - rootPane.putClientProperty("apple.awt.windowTitleVisible", false); - doSetCustomTitleBar(window, rootPane, onDispose, customBorder); - } - - private static void doSetCustomTitleBar(@NotNull Window window, - @NotNull JRootPane rootPane, - Function1 onDispose, - @NotNull Border customBorder) { - - rootPane.putClientProperty("apple.awt.fullWindowContent", true); - rootPane.putClientProperty("apple.awt.transparentTitleBar", true); - - // Use standard properties starting jdk 17 - //if (Runtime.version().feature() >= 17) { - //rootPane.putClientProperty("apple.awt.windowTitleVisible", false); - //} - - rootPane.setBorder(customBorder); - - WindowAdapter windowAdapter = new WindowAdapter() { - @Override - public void windowActivated(WindowEvent e) { - rootPane.repaint(); - } - - @Override - public void windowDeactivated(WindowEvent e) { - rootPane.repaint(); - } - }; - PropertyChangeListener propertyChangeListener = e -> rootPane.repaint(); - window.addPropertyChangeListener("title", propertyChangeListener); - onDispose.invoke((Runnable)() -> { - window.removeWindowListener(windowAdapter); - window.removePropertyChangeListener("title", propertyChangeListener); - }); + } + doSetCustomTitleBar(window = window, rootPane = rootPane, onDispose = onDispose, customBorder = customBorder) } } + +private fun setCustomTitleForToolbar(window: Window, rootPane: JRootPane, onDispose: (Runnable) -> Unit) { + val topWindowInset = JBUI.insetsTop(UIUtil.getTransparentTitleBarHeight(rootPane)) + val customBorder = object : AbstractBorder() { + override fun getBorderInsets(c: Component): Insets = topWindowInset + + override fun paintBorder(c: Component, g: Graphics, x: Int, y: Int, width: Int, height: Int) { + val graphics = g.create() as Graphics2D + try { + val headerRectangle = Rectangle(0, 0, c.width, topWindowInset.top) + val color = UIManager.getColor("MainToolbar.background") + graphics.color = color ?: UIUtil.getPanelBackground() + graphics.fill(headerRectangle) + } + finally { + graphics.dispose() + } + } + } + rootPane.putClientProperty("apple.awt.windowTitleVisible", false) + doSetCustomTitleBar(window = window, rootPane = rootPane, onDispose = onDispose, customBorder = customBorder) +} + +private fun doSetCustomTitleBar(window: Window, rootPane: JRootPane, onDispose: (Runnable) -> Unit, customBorder: Border) { + rootPane.putClientProperty("apple.awt.fullWindowContent", true) + rootPane.putClientProperty("apple.awt.transparentTitleBar", true) + + rootPane.setBorder(customBorder) + val propertyChangeListener = PropertyChangeListener { rootPane.repaint() } + window.addPropertyChangeListener("title", propertyChangeListener) + onDispose { window.removePropertyChangeListener("title", propertyChangeListener) } +} From b42b5e3c6f8245e3a4c112065f721aa618d3a63f Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 00:47:57 +0200 Subject: [PATCH 162/226] cleanup GitOrigin-RevId: 4b5ee194c4f11930dc28964faf49c4e817250b77 --- .../impl/CompletionServiceImpl.java | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java index 12bec8b6a42b..beeb5c45aeff 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.completion.impl; import com.intellij.codeInsight.completion.*; @@ -6,8 +6,6 @@ import com.intellij.codeInsight.lookup.Classifier; import com.intellij.codeInsight.lookup.ClassifierFactory; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeWithMe.ClientId; -import com.intellij.platform.diagnostic.telemetry.IJTracer; -import com.intellij.platform.diagnostic.telemetry.TelemetryManager; import com.intellij.ide.plugins.DynamicPluginListener; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.openapi.Disposable; @@ -22,6 +20,8 @@ import com.intellij.openapi.project.ProjectCloseListener; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.NlsContexts; import com.intellij.patterns.ElementPattern; +import com.intellij.platform.diagnostic.telemetry.IJTracer; +import com.intellij.platform.diagnostic.telemetry.TelemetryManager; import com.intellij.psi.Weigher; import com.intellij.util.Consumer; import com.intellij.util.ExceptionUtil; @@ -31,7 +31,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import static com.intellij.codeInsight.util.CodeCompletionKt.*; +import static com.intellij.codeInsight.util.CodeCompletionKt.CodeCompletion; import static com.intellij.platform.diagnostic.telemetry.helpers.TraceKt.runWithSpan; /** @@ -44,18 +44,16 @@ public final class CompletionServiceImpl extends BaseCompletionService { private final IJTracer myCompletionTracer = TelemetryManager.getInstance().getTracer(CodeCompletion); private static class ClientCompletionService implements Disposable { - @Nullable - public static ClientCompletionService tryGetInstance(@Nullable ClientAppSession session) { - if (session == null) + public static @Nullable ClientCompletionService tryGetInstance(@Nullable ClientAppSession session) { + if (session == null) { return null; + } return session.getService(ClientCompletionService.class); } - @NotNull - private final ClientAppSession myAppSession; + private final @NotNull ClientAppSession myAppSession; - @NotNull - private volatile CompletionPhaseHolder myPhaseHolder = DEFAULT_PHASE_HOLDER; + private volatile @NotNull CompletionPhaseHolder myPhaseHolder = DEFAULT_PHASE_HOLDER; ClientCompletionService(@NotNull ClientAppSession appSession) { myAppSession = appSession; @@ -155,7 +153,7 @@ public final class CompletionServiceImpl extends BaseCompletionService { } @Override - public void setAdvertisementText(@NlsContexts.PopupAdvertisement @Nullable final String text) { + public void setAdvertisementText(final @NlsContexts.PopupAdvertisement @Nullable String text) { if (text == null) return; final CompletionProgressIndicator completion = getCurrentCompletionProgressIndicator(); if (completion != null) { @@ -182,8 +180,7 @@ public final class CompletionServiceImpl extends BaseCompletionService { return ClientId.isCurrentlyUnderLocalId() ? myApiCompletionProcess : null; } - @Nullable - public static CompletionProgressIndicator getCurrentCompletionProgressIndicator() { + public static @Nullable CompletionProgressIndicator getCurrentCompletionProgressIndicator() { ClientCompletionService clientCompletionService = ClientCompletionService.tryGetInstance(ClientSessionsManager.getAppSession()); if (clientCompletionService == null) return null; @@ -212,8 +209,7 @@ public final class CompletionServiceImpl extends BaseCompletionService { } @Override - @NotNull - public CompletionResultSet withPrefixMatcher(@NotNull final PrefixMatcher matcher) { + public @NotNull CompletionResultSet withPrefixMatcher(final @NotNull PrefixMatcher matcher) { if (matcher.equals(getPrefixMatcher())) { return this; } @@ -221,9 +217,8 @@ public final class CompletionServiceImpl extends BaseCompletionService { return new CompletionResultSetImpl(getConsumer(), matcher, myContributor, myParameters, mySorter, this); } - @NotNull @Override - public CompletionResultSet withRelevanceSorter(@NotNull CompletionSorter sorter) { + public @NotNull CompletionResultSet withRelevanceSorter(@NotNull CompletionSorter sorter) { return new CompletionResultSetImpl(getConsumer(), getPrefixMatcher(), myContributor, myParameters, sorter, this); } @@ -306,18 +301,16 @@ public final class CompletionServiceImpl extends BaseCompletionService { return clientCompletionService.getCompletionPhase(); } - @NotNull @Override - protected CompletionSorterImpl addWeighersBefore(@NotNull CompletionSorterImpl sorter) { + protected @NotNull CompletionSorterImpl addWeighersBefore(@NotNull CompletionSorterImpl sorter) { CompletionSorterImpl processed = super.addWeighersBefore(sorter); return processed.withClassifier(CompletionSorterImpl.weighingFactory(new LiveTemplateWeigher())); } - @NotNull @Override - protected CompletionSorterImpl processStatsWeigher(@NotNull CompletionSorterImpl sorter, - @NotNull Weigher weigher, - @NotNull CompletionLocation location) { + protected @NotNull CompletionSorterImpl processStatsWeigher(@NotNull CompletionSorterImpl sorter, + @NotNull Weigher weigher, + @NotNull CompletionLocation location) { CompletionSorterImpl processedSorter = super.processStatsWeigher(sorter, weigher, location); return processedSorter.withClassifier(new ClassifierFactory<>("stats") { @Override From d5006dcb6e5db408794aaaa91f2462826ef3ee1a Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 01:06:12 +0200 Subject: [PATCH 163/226] cleanup GitOrigin-RevId: deeee99846747bda4ed01c549485f27d3bc8eed7 --- .../header/DefaultFrameHeader.kt | 2 +- .../header/FrameHeader.kt | 34 ++++++------------- .../header/MenuFrameHeader.kt | 2 +- .../src/com/intellij/ui/ToolbarServiceImpl.kt | 2 +- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DefaultFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DefaultFrameHeader.kt index a559a0b5a477..65195029336a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DefaultFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DefaultFrameHeader.kt @@ -25,7 +25,7 @@ internal class DefaultFrameHeader(frame: JFrame, isForDockContainerProvider: Boo add(customDecorationTitle.view, gb.next().fillCell().weightx(1.0)) buttonPanes?.let { add(it.getView(), gb.next().anchor(GridBagConstraints.EAST)) } - setCustomFrameTopBorder(isTopNeeded = { myState != Frame.MAXIMIZED_VERT && myState != Frame.MAXIMIZED_BOTH }) + setCustomFrameTopBorder(isTopNeeded = { state != Frame.MAXIMIZED_VERT && state != Frame.MAXIMIZED_BOTH }) } override fun updateActive() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt index 6c788e400689..aebe15920cd7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt @@ -12,23 +12,19 @@ import com.intellij.util.ui.JBFont import java.awt.Font import java.awt.Frame import java.awt.Toolkit -import java.awt.event.WindowAdapter -import java.awt.event.WindowStateListener -import javax.swing.Action import javax.swing.JFrame import javax.swing.JPopupMenu import javax.swing.JSeparator internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(frame) { - private val iconifyAction: Action = CustomFrameAction(ActionsBundle.message("action.MinimizeCurrentWindow.text"), + private val iconifyAction = CustomFrameAction(ActionsBundle.message("action.MinimizeCurrentWindow.text"), AllIcons.Windows.MinimizeSmall) { iconify() } - private val restoreAction: Action = CustomFrameAction(CommonBundle.message("button.without.mnemonic.restore"), + private val restoreAction = CustomFrameAction(CommonBundle.message("button.without.mnemonic.restore"), AllIcons.Windows.RestoreSmall) { restore() } - private val maximizeAction: Action = CustomFrameAction(IdeBundle.message("action.maximize.text"), + private val maximizeAction = CustomFrameAction(IdeBundle.message("action.maximize.text"), AllIcons.Windows.MaximizeSmall) { maximize() } - private var windowStateListener: WindowStateListener - protected var myState = 0 + protected var state = 0 @Suppress("LeakingThis") private val closeAction = createCloseAction(this) @@ -37,33 +33,25 @@ internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(fram createButtonsPane() } - init { - windowStateListener = object : WindowAdapter() { - override fun windowStateChanged(e: java.awt.event.WindowEvent?) { - updateActions() - } - } - } - override fun windowStateChanged() { super.windowStateChanged() updateActions() } private fun iconify() { - frame.extendedState = myState or Frame.ICONIFIED + frame.extendedState = state or Frame.ICONIFIED } private fun maximize() { - frame.extendedState = myState or Frame.MAXIMIZED_BOTH + frame.extendedState = state or Frame.MAXIMIZED_BOTH } private fun restore() { - if (myState and Frame.ICONIFIED != 0) { - frame.extendedState = myState and Frame.ICONIFIED.inv() + if (state and Frame.ICONIFIED != 0) { + frame.extendedState = state and Frame.ICONIFIED.inv() } else { - frame.extendedState = myState and Frame.MAXIMIZED_BOTH.inv() + frame.extendedState = state and Frame.MAXIMIZED_BOTH.inv() } } @@ -73,9 +61,9 @@ internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(fram } private fun updateActions() { - myState = frame.extendedState + state = frame.extendedState if (frame.isResizable) { - if (myState and Frame.MAXIMIZED_BOTH != 0) { + if (state and Frame.MAXIMIZED_BOTH != 0) { maximizeAction.isEnabled = false restoreAction.isEnabled = true } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MenuFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MenuFrameHeader.kt index acca0c94e913..88f846678f93 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MenuFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/MenuFrameHeader.kt @@ -52,7 +52,7 @@ internal class MenuFrameHeader(frame: JFrame, add(view, "left, growx, gapbottom 1") buttonPanes?.let { add(it.getView(), "right, gapbottom 1") } - setCustomFrameTopBorder({ myState != Frame.MAXIMIZED_VERT && myState != Frame.MAXIMIZED_BOTH }, {true}) + setCustomFrameTopBorder({ state != Frame.MAXIMIZED_VERT && state != Frame.MAXIMIZED_BOTH }, {true}) mainMenuUpdater = UISettingsListener { menuHolder.isVisible = UISettings.getInstance().showMainMenu diff --git a/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt b/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt index b4b40865b8dd..30977a8378d7 100644 --- a/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt +++ b/platform/platform-impl/src/com/intellij/ui/ToolbarServiceImpl.kt @@ -41,7 +41,7 @@ open class ToolbarServiceImpl : ToolbarService { handler?.addListener(window) val topWindowInset = JBUI.insetsTop(UIUtil.getTransparentTitleBarHeight(rootPane)) - val customBorder: AbstractBorder = object : AbstractBorder() { + val customBorder = object : AbstractBorder() { override fun getBorderInsets(c: Component): Insets { return if (handler != null && handler.isFullScreen()) JBInsets.emptyInsets() else topWindowInset } From 234e743851494ef5a96e699c7e60f3c3bf6f909f Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 01:34:58 +0200 Subject: [PATCH 164/226] cleanup GitOrigin-RevId: 8fc31eadf65e58fa36a7b5cfb63be328ccacb08b --- .../wm/impl/welcomeScreen/TreeWelcomeScreenLeftPanel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/TreeWelcomeScreenLeftPanel.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/TreeWelcomeScreenLeftPanel.kt index 6effb9cd2edc..a1df6aea185f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/TreeWelcomeScreenLeftPanel.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/TreeWelcomeScreenLeftPanel.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.welcomeScreen import com.intellij.openapi.Disposable @@ -31,7 +31,7 @@ import javax.swing.event.TreeSelectionListener import javax.swing.tree.* import kotlin.collections.ArrayDeque -class TreeWelcomeScreenLeftPanel : WelcomeScreenLeftPanel { +internal class TreeWelcomeScreenLeftPanel : WelcomeScreenLeftPanel { private val root = DefaultMutableTreeNode() private val treeModel = DefaultTreeModel(root) private val tree: JTree = Tree(treeModel) From 8373c60c1849e1f743c0b81efab745830bee8bbf Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 01:36:47 +0200 Subject: [PATCH 165/226] welcome screen on mac - use native menu GitOrigin-RevId: 57c3488800483e518bea8a0d3cdbd9d1858ebf0f --- .../src/com/intellij/ide/menu/MacMenuBar.kt | 10 ++- .../wm/impl/welcomeScreen/FlatWelcomeFrame.kt | 74 ++++++++++++------- .../WelcomeScreenComponentFactory.java | 10 +-- .../recentProjects/RecentProjectTreeItem.kt | 8 +- 4 files changed, 64 insertions(+), 38 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt b/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt index d28b6aa26347..904a476a5834 100644 --- a/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt +++ b/platform/platform-impl/src/com/intellij/ide/menu/MacMenuBar.kt @@ -2,6 +2,7 @@ package com.intellij.ide.menu import com.intellij.diagnostic.runActivity +import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.util.Disposer import com.intellij.openapi.wm.impl.doUpdateAppMenu import com.intellij.ui.mac.foundation.NSDefaults @@ -11,7 +12,12 @@ import kotlinx.coroutines.job import javax.swing.JComponent import javax.swing.JFrame -internal fun createMacMenuBar(coroutineScope: CoroutineScope, component: JComponent, frame: JFrame): ActionAwareIdeMenuBar { +internal fun createMacMenuBar( + coroutineScope: CoroutineScope, + component: JComponent, + frame: JFrame, + mainMenuActionGroupProvider: suspend () -> ActionGroup? = { getMainMenuActionGroup(frame) }, +): ActionAwareIdeMenuBar { val flavor = object : IdeMenuFlavor { override fun updateAppMenu() { doUpdateAppMenu() @@ -31,7 +37,7 @@ internal fun createMacMenuBar(coroutineScope: CoroutineScope, component: JCompon override fun updateGlobalMenuRoots() { } - override suspend fun getMainMenuActionGroup() = getMainMenuActionGroup(frame) + override suspend fun getMainMenuActionGroup() = mainMenuActionGroupProvider() } val screenMenuPeer = runActivity("ide menu bar init") { MenuBar("MainMenu", frame) } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt index 1fd948e307a1..27533a987a28 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt @@ -9,10 +9,10 @@ import com.intellij.ide.RecentProjectListActionProvider import com.intellij.ide.dnd.FileCopyPasteUtil import com.intellij.ide.impl.ProjectUtil import com.intellij.ide.lightEdit.LightEditServiceListener +import com.intellij.ide.menu.createMacMenuBar import com.intellij.ide.ui.LafManagerListener import com.intellij.notification.NotificationsManager import com.intellij.notification.impl.NotificationsManagerImpl -import com.intellij.openapi.Disposable import com.intellij.openapi.MnemonicHelper import com.intellij.openapi.actionSystem.* import com.intellij.openapi.application.ApplicationManager @@ -41,6 +41,7 @@ import com.intellij.ui.components.labels.ActionLink import com.intellij.ui.components.panels.NonOpaquePanel import com.intellij.ui.components.panels.VerticalLayout import com.intellij.ui.components.panels.Wrapper +import com.intellij.ui.mac.screenmenu.Menu import com.intellij.ui.mac.touchbar.Touchbar import com.intellij.ui.mac.touchbar.TouchbarActionCustomizations import com.intellij.ui.scale.JBUIScale @@ -52,7 +53,7 @@ import com.intellij.util.ui.StartupUiUtil import com.intellij.util.ui.UIUtil import com.intellij.util.ui.accessibility.AccessibleContextAccessor import com.intellij.util.ui.update.UiNotifyConnector -import kotlinx.coroutines.launch +import kotlinx.coroutines.* import net.miginfocom.swing.MigLayout import java.awt.* import java.awt.dnd.* @@ -68,17 +69,20 @@ import javax.swing.event.ListDataListener @Suppress("LeakingThis") open class FlatWelcomeFrame @JvmOverloads constructor( suggestedScreen: AbstractWelcomeScreen? = if (USE_TABBED_WELCOME_SCREEN) TabbedWelcomeScreen() else null -) : JFrame(), IdeFrame, Disposable, AccessibleContextAccessor { +) : JFrame(), IdeFrame, AccessibleContextAccessor { val screen: AbstractWelcomeScreen private val content: Wrapper private var balloonLayout: WelcomeBalloonLayoutImpl? private var isDisposed = false private var header: DefaultFrameHeader? = null + private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default) + companion object { @JvmField var USE_TABBED_WELCOME_SCREEN: Boolean = java.lang.Boolean.parseBoolean(System.getProperty("use.tabbed.welcome.screen", "true")) const val BOTTOM_PANEL: String = "BOTTOM_PANEL" + @JvmField val DEFAULT_HEIGHT: Int = if (USE_TABBED_WELCOME_SCREEN) 650 else 460 const val MAX_DEFAULT_WIDTH: Int = 800 @@ -113,9 +117,7 @@ open class FlatWelcomeFrame @JvmOverloads constructor( content.setContent(getCustomContentHolder(this, screen.welcomePanel, header!!)) } else { - if (USE_TABBED_WELCOME_SCREEN && SystemInfoRt.isMac) { - rootPane.jMenuBar = WelcomeFrameMenuBar(this) - } + createWelcomeMenuBar(this, coroutineScope) content.setContent(screen.welcomePanel) } val glassPane = IdeGlassPaneImpl(rootPane) @@ -126,16 +128,16 @@ open class FlatWelcomeFrame @JvmOverloads constructor( // at this point, window insets may be unavailable, so we need to resize the window when it is shown UiNotifyConnector.doWhenFirstShown(this, ::pack) val app = ApplicationManager.getApplication() - val connection = app.messageBus.connect(this) + val connection = app.messageBus.connect(coroutineScope) connection.subscribe(ProjectManager.TOPIC, object : ProjectManagerListener { @Suppress("OVERRIDE_DEPRECATION") override fun projectOpened(project: Project) { - Disposer.dispose(this@FlatWelcomeFrame) + dispose() } }) connection.subscribe(LightEditServiceListener.TOPIC, object : LightEditServiceListener { override fun lightEditWindowOpened(project: Project) { - Disposer.dispose(this@FlatWelcomeFrame) + dispose() } }) connection.subscribe(AppLifecycleListener.TOPIC, object : AppLifecycleListener { @@ -159,17 +161,26 @@ open class FlatWelcomeFrame @JvmOverloads constructor( setupCloseAction() MnemonicHelper.init(this) - Disposer.register(app, this) ComponentUtil.decorateWindowHeader(getRootPane()) ToolbarService.getInstance().setTransparentTitleBar( window = this, rootPane = getRootPane(), - onDispose = { runnable -> Disposer.register(this) { runnable.run() } }, + onDispose = { runnable -> + coroutineScope.coroutineContext.job.invokeOnCompletion { + runnable.run() + } + }, ) app.invokeLater({ (NotificationsManager.getNotificationsManager() as NotificationsManagerImpl).dispatchEarlyNotifications() }, ModalityState.nonModal()) } + override fun removeNotify() { + super.removeNotify() + + coroutineScope.cancel() + } + protected open fun setupCloseAction() { WelcomeFrame.setupCloseAction(this) } @@ -183,9 +194,7 @@ open class FlatWelcomeFrame @JvmOverloads constructor( } } else { - if (USE_TABBED_WELCOME_SCREEN && SystemInfoRt.isMac) { - rootPane.jMenuBar = WelcomeFrameMenuBar(this) - } + createWelcomeMenuBar(this, coroutineScope) content.setContent(screen.welcomePanel) } if (USE_TABBED_WELCOME_SCREEN) { @@ -226,6 +235,7 @@ open class FlatWelcomeFrame @JvmOverloads constructor( } override fun dispose() { + coroutineScope.cancel() if (isDisposed) { return } @@ -380,12 +390,13 @@ open class FlatWelcomeFrame @JvmOverloads constructor( return panel } - private fun createSettingsAndDocsPanel(frame: JFrame): JComponent { + private fun createSettingsAndDocsPanel(frame: FlatWelcomeFrame): JComponent { val panel: JPanel = NonOpaquePanel(BorderLayout()) val toolbar = NonOpaquePanel() toolbar.layout = BoxLayout(toolbar, BoxLayout.X_AXIS) toolbar.add(WelcomeScreenComponentFactory.createErrorsLink(this)) - toolbar.add(createEventsLink()) + toolbar.add(WelcomeScreenComponentFactory.createEventLink(IdeBundle.message("action.Events"), + ApplicationManager.getApplication().messageBus.connect(frame.coroutineScope))) toolbar.add(WelcomeScreenComponentFactory.createActionLink( frame, IdeBundle.message("action.Anonymous.text.configure"), @@ -393,16 +404,14 @@ open class FlatWelcomeFrame @JvmOverloads constructor( AllIcons.General.GearPlain, UIUtil.findComponentOfType(frame.rootPane, JList::class.java)) ) - toolbar.add(WelcomeScreenComponentFactory.createActionLink(frame, IdeBundle.message("action.GetHelp"), IdeActions.GROUP_WELCOME_SCREEN_DOC, null, null)) + toolbar.add( + WelcomeScreenComponentFactory.createActionLink(frame, IdeBundle.message("action.GetHelp"), IdeActions.GROUP_WELCOME_SCREEN_DOC, + null, null)) panel.add(toolbar, BorderLayout.EAST) panel.border = JBUI.Borders.empty(0, 0, 8, 11) return panel } - private fun createEventsLink(): Component { - return WelcomeScreenComponentFactory.createEventLink(IdeBundle.message("action.Events"), frame) - } - private fun createQuickStartActionPanel(): ActionPanel { val group = DefaultActionGroup() val quickStart = ActionManager.getInstance().getAction(IdeActions.GROUP_WELCOME_SCREEN_QUICKSTART) as ActionGroup @@ -474,10 +483,25 @@ open class FlatWelcomeFrame @JvmOverloads constructor( } } -@Suppress("DEPRECATION") -private class WelcomeFrameMenuBar(frame: JFrame) : IdeMenuBar(ApplicationManager.getApplication().coroutineScope.childScope(), frame) { - override suspend fun getMainMenuActionGroup(): ActionGroup { +private fun createWelcomeMenuBar(frame: JFrame, parentCoroutineScope: CoroutineScope) { + if (!FlatWelcomeFrame.USE_TABBED_WELCOME_SCREEN || !SystemInfoRt.isMac) { + return + } + + val mainMenuActionGroupProvider: suspend () -> ActionGroup = { val manager = serviceAsync() - return DefaultActionGroup(manager.getAction(IdeActions.GROUP_FILE), manager.getAction(IdeActions.GROUP_HELP_MENU)) + DefaultActionGroup(manager.getAction(IdeActions.GROUP_FILE), manager.getAction(IdeActions.GROUP_HELP_MENU)) + } + + if (Menu.isJbScreenMenuEnabled()) { + createMacMenuBar(coroutineScope = parentCoroutineScope.childScope(), + component = frame.rootPane, + frame = frame, + mainMenuActionGroupProvider = mainMenuActionGroupProvider) + } + else { + frame.rootPane.jMenuBar = object : IdeMenuBar(parentCoroutineScope.childScope(), frame) { + override suspend fun getMainMenuActionGroup(): ActionGroup = mainMenuActionGroupProvider() + } } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java index 6a07725cb88c..7cfa2cf4675f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java @@ -1,7 +1,6 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.welcomeScreen; -import com.intellij.application.Topics; import com.intellij.diagnostic.IdeMessagePanel; import com.intellij.diagnostic.MessagePool; import com.intellij.icons.AllIcons; @@ -14,6 +13,7 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory; import com.intellij.openapi.application.ApplicationInfo; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.application.ex.ApplicationInfoEx; import com.intellij.openapi.ide.CopyPasteManager; @@ -33,6 +33,7 @@ import com.intellij.ui.popup.PopupFactoryImpl; import com.intellij.ui.popup.list.SelectablePanel; import com.intellij.ui.scale.JBUIScale; import com.intellij.util.IconUtil; +import com.intellij.util.messages.SimpleMessageBusConnection; import com.intellij.util.ui.*; import com.intellij.util.ui.accessibility.AccessibleContextDelegate; import org.jetbrains.annotations.Nls; @@ -280,7 +281,7 @@ public final class WelcomeScreenComponentFactory { * @deprecated use {@link NotificationEventAction} instead */ @Deprecated - public static @NotNull JComponent createEventLink(@NotNull @Nls String linkText, @NotNull Disposable parentDisposable) { + public static @NotNull JComponent createEventLink(@NotNull @Nls String linkText, @NotNull SimpleMessageBusConnection busConnection) { SelectablePanel selectablePanel = new SelectablePanel(); ActionLink actionLink = new ActionLink(linkText, getNotificationIcon(Collections.emptyList(), null), new DumbAwareAction() { private boolean hideListenerInstalled = false; @@ -299,7 +300,6 @@ public final class WelcomeScreenComponentFactory { } }); - JComponent panel = wrapActionLink(actionLink); selectablePanel.setLayout(new BorderLayout()); selectablePanel.add(panel); @@ -309,7 +309,7 @@ public final class WelcomeScreenComponentFactory { panel.setBorder(null); selectablePanel.setVisible(false); - Topics.subscribe(WelcomeBalloonLayoutImpl.BALLOON_NOTIFICATION_TOPIC, parentDisposable, types -> { + busConnection.subscribe(WelcomeBalloonLayoutImpl.BALLOON_NOTIFICATION_TOPIC, types -> { BalloonLayout balloonLayout = WelcomeFrame.getInstance().getBalloonLayout(); if (balloonLayout instanceof WelcomeBalloonLayoutImpl welcomeBalloonLayout) { if (welcomeBalloonLayout.getLocationComponent() == null) { @@ -385,7 +385,7 @@ public final class WelcomeScreenComponentFactory { @Deprecated public static @NotNull JPanel createNotificationPanel(@NotNull Disposable parentDisposable) { JComponent errorsLink = createErrorsLink(parentDisposable); - JComponent eventLink = createEventLink("", parentDisposable); + JComponent eventLink = createEventLink("", ApplicationManager.getApplication().getMessageBus().connect(parentDisposable)); JPanel panel = new NonOpaquePanel(); if (ExperimentalUI.isNewUI()) { panel.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0)); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/recentProjects/RecentProjectTreeItem.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/recentProjects/RecentProjectTreeItem.kt index e8dfdd8337c7..e537f99cca40 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/recentProjects/RecentProjectTreeItem.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/recentProjects/RecentProjectTreeItem.kt @@ -11,7 +11,6 @@ import com.intellij.openapi.actionSystem.PlatformCoreDataKeys import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project import com.intellij.openapi.ui.Messages -import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.NlsSafe import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.wm.impl.welcomeScreen.FlatWelcomeFrame @@ -91,11 +90,8 @@ internal data class RecentProjectItem( } if (event.place == ActionPlaces.WELCOME_SCREEN) { - val welcomeFrame = SwingUtilities.getAncestorOfClass(FlatWelcomeFrame::class.java, - event.getData(PlatformCoreDataKeys.CONTEXT_COMPONENT)) as FlatWelcomeFrame? - if (welcomeFrame != null) { - Disposer.dispose(welcomeFrame) - } + (SwingUtilities.getAncestorOfClass(FlatWelcomeFrame::class.java, + event.getData(PlatformCoreDataKeys.CONTEXT_COMPONENT)) as FlatWelcomeFrame?)?.dispose() } val forceOpenInNewFrame = BitUtil.isSet(event.modifiers, ActionEvent.CTRL_MASK) || From 3d783bf4392d7009a9cf84c22e5f4c988a164071 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 01:59:33 +0200 Subject: [PATCH 166/226] separate diff window - use native menu GitOrigin-RevId: 3380e4244fbd432741a3256b178ec7dc9d903a3c --- .../platform-impl/src/com/intellij/openapi/ui/FrameWrapper.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.kt b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.kt index 41194a15dbe8..b962c5aebcba 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.kt +++ b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.kt @@ -27,6 +27,7 @@ import com.intellij.openapi.wm.impl.LinuxIdeMenuBar.Companion.doBindAppMenuOfPar import com.intellij.openapi.wm.impl.customFrameDecorations.header.CustomFrameDialogContent import com.intellij.openapi.wm.impl.customFrameDecorations.header.CustomHeader import com.intellij.ui.* +import com.intellij.ui.mac.screenmenu.Menu import com.intellij.ui.mac.touchbar.TouchbarSupport import com.intellij.util.childScope import com.intellij.util.ui.ImageUtil @@ -299,10 +300,9 @@ open class FrameWrapper @JvmOverloads constructor(private var project: Project?, init { FrameState.setFrameStateListener(this) glassPane = IdeGlassPaneImpl(rootPane = getRootPane(), installPainters = true) - if (SystemInfoRt.isMac && !(SystemInfo.isMacSystemMenu && java.lang.Boolean.getBoolean("mac.system.menu.singleton"))) { + if (SystemInfoRt.isMac && !Menu.isJbScreenMenuEnabled()) { @Suppress("DEPRECATION") jMenuBar = createMenuBar(coroutineScope = ApplicationManager.getApplication().coroutineScope.childScope(), this) - } MouseGestureManager.getInstance().add(this) focusTraversalPolicy = IdeFocusTraversalPolicy() From cf62a5ba29fe6ac74192d920cc7b3037b45a90d5 Mon Sep 17 00:00:00 2001 From: "Alexander.Danilov" Date: Fri, 30 Jun 2023 17:23:33 +0200 Subject: [PATCH 167/226] Add test data for type aliases find usages GitOrigin-RevId: 17a21dd00f57bd643e9d2c6be1230095b785cd33 --- ...ompilerReferenceIndexFirTestGenerated.java | 13 ++++++ ...thCompilerReferenceIndexTestGenerated.java | 13 ++++++ .../FindUsagesFirTestGenerated.java | 5 +++ .../findUsages/FindUsagesTestGenerated.java | 5 +++ .../kotlinClassDerivedClasses.0.kt | 2 + .../kotlinClassDerivedClasses.1.kt | 2 + .../kotlinClassDerivedClasses.results.txt | 1 + .../findTypeAliasUsages/classAlias.0.kt | 45 +++++++++++++++++++ .../classAlias.fir.results.txt | 7 +++ .../classAlias.results.txt | 9 ++++ 10 files changed, 102 insertions(+) create mode 100644 plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.0.kt create mode 100644 plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.fir.results.txt create mode 100644 plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.results.txt diff --git a/plugins/kotlin/compiler-reference-index/tests.k2/test/org/jetbrains/kotlin/idea/fir/search/refIndex/FindUsagesWithCompilerReferenceIndexFirTestGenerated.java b/plugins/kotlin/compiler-reference-index/tests.k2/test/org/jetbrains/kotlin/idea/fir/search/refIndex/FindUsagesWithCompilerReferenceIndexFirTestGenerated.java index dfa474fba181..f8ddc5f2c575 100644 --- a/plugins/kotlin/compiler-reference-index/tests.k2/test/org/jetbrains/kotlin/idea/fir/search/refIndex/FindUsagesWithCompilerReferenceIndexFirTestGenerated.java +++ b/plugins/kotlin/compiler-reference-index/tests.k2/test/org/jetbrains/kotlin/idea/fir/search/refIndex/FindUsagesWithCompilerReferenceIndexFirTestGenerated.java @@ -3014,6 +3014,19 @@ public abstract class FindUsagesWithCompilerReferenceIndexFirTestGenerated exten @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("../../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages") public abstract static class FindTypeAliasUsages extends AbstractFindUsagesWithCompilerReferenceIndexFirTest { + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages") + public static class TestClassAlias extends AbstractFindUsagesWithCompilerReferenceIndexFirTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("classAlias.0.kt") + public void testClassAlias() throws Exception { + runTest("../../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.0.kt"); + } + } + @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("../../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages") public static class TestObjectAlias extends AbstractFindUsagesWithCompilerReferenceIndexFirTest { diff --git a/plugins/kotlin/compiler-reference-index/tests/test/org/jetbrains/kotlin/idea/search/refIndex/FindUsagesWithCompilerReferenceIndexTestGenerated.java b/plugins/kotlin/compiler-reference-index/tests/test/org/jetbrains/kotlin/idea/search/refIndex/FindUsagesWithCompilerReferenceIndexTestGenerated.java index f971ccf23571..e937d9589a13 100644 --- a/plugins/kotlin/compiler-reference-index/tests/test/org/jetbrains/kotlin/idea/search/refIndex/FindUsagesWithCompilerReferenceIndexTestGenerated.java +++ b/plugins/kotlin/compiler-reference-index/tests/test/org/jetbrains/kotlin/idea/search/refIndex/FindUsagesWithCompilerReferenceIndexTestGenerated.java @@ -3014,6 +3014,19 @@ public abstract class FindUsagesWithCompilerReferenceIndexTestGenerated extends @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("../../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages") public abstract static class FindTypeAliasUsages extends AbstractFindUsagesWithCompilerReferenceIndexTest { + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages") + public static class TestClassAlias extends AbstractFindUsagesWithCompilerReferenceIndexTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("classAlias.0.kt") + public void testClassAlias() throws Exception { + runTest("../../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.0.kt"); + } + } + @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("../../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages") public static class TestObjectAlias extends AbstractFindUsagesWithCompilerReferenceIndexTest { diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/findUsages/FindUsagesFirTestGenerated.java b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/findUsages/FindUsagesFirTestGenerated.java index 1840cfbf3800..3baa47dccf13 100644 --- a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/findUsages/FindUsagesFirTestGenerated.java +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/findUsages/FindUsagesFirTestGenerated.java @@ -1266,6 +1266,11 @@ public abstract class FindUsagesFirTestGenerated extends AbstractFindUsagesFirTe KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } + @TestMetadata("classAlias.0.kt") + public void testClassAlias() throws Exception { + runTest("../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.0.kt"); + } + @TestMetadata("objectAlias.0.kt") public void testObjectAlias() throws Exception { runTest("../idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/objectAlias.0.kt"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesTestGenerated.java index 6c06b5d5b5ed..d5cde72d4a9a 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesTestGenerated.java @@ -1266,6 +1266,11 @@ public abstract class FindUsagesTestGenerated extends AbstractFindUsagesTest { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } + @TestMetadata("classAlias.0.kt") + public void testClassAlias() throws Exception { + runTest("testData/findUsages/kotlin/findTypeAliasUsages/classAlias.0.kt"); + } + @TestMetadata("objectAlias.0.kt") public void testObjectAlias() throws Exception { runTest("testData/findUsages/kotlin/findTypeAliasUsages/objectAlias.0.kt"); diff --git a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.0.kt b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.0.kt index cb6f401ffae1..5ab3dcaf9dae 100644 --- a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.0.kt +++ b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.0.kt @@ -10,6 +10,8 @@ open class A: X { } +typealias TA = A + interface Y : X { } diff --git a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.1.kt b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.1.kt index 1cf9c865165d..8fdce7c49f78 100644 --- a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.1.kt +++ b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.1.kt @@ -16,3 +16,5 @@ open class Z : A() { class U : Z() { } + +class InheritTypeAlias : TA() diff --git a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.results.txt b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.results.txt index 703b7ecfd4ec..f0191b16dab8 100644 --- a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.results.txt +++ b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.results.txt @@ -1,5 +1,6 @@ [kotlinClassDerivedClasses.1.kt] Unclassified 12 open class Z : A() { [kotlinClassDerivedClasses.1.kt] Unclassified 16 class U : Z() { +[kotlinClassDerivedClasses.1.kt] Unclassified 20 class InheritTypeAlias : TA() [kotlinClassDerivedClasses.1.kt] Unclassified 4 open class B : A() { [kotlinClassDerivedClasses.2.kt] Unclassified 1 open class SimpleClass : A() [kotlinClassDerivedClasses.3.kt] Unclassified 1 object abc : A() diff --git a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.0.kt b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.0.kt new file mode 100644 index 000000000000..7b6966827ffc --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.0.kt @@ -0,0 +1,45 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtTypeAlias +// OPTIONS: usages + +open class OOO { + + open fun opFun() {} + + companion object { + const val CONST = "" + } + +} +typealias Alias = OOO + +class Child : Alias() { + + override fun opFun() { + super.opFun() //not found in K2, see KTIJ-26095 + } +} + +class Child2 : OOO() + +class WithGeneric + +fun f2(par: Alias, par2: OOO) : Alias { + + val a: Alias + + a = Alias() //not found in K2, see KTIJ-26095 + + val b = WithGeneric() //not found in K2, see KTIJ-26095 + val b2 = WithGeneric() + + Alias.CONST //not found in K1, found in K2 + OOO.CONST + + if (par2 is Alias) {} + if (par2 is OOO) {} + + val c = par2 as Alias + val c2 = par2 as OOO + + return c +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.fir.results.txt b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.fir.results.txt new file mode 100644 index 000000000000..57ca5ef0fc98 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.fir.results.txt @@ -0,0 +1,7 @@ +Function return types 26 fun f2(par: Alias, par2: OOO) : Alias { +Local variable declaration 28 val a: Alias +Nested class/object 35 Alias.CONST //not found in K1, found in K2 +Parameter type 26 fun f2(par: Alias, par2: OOO) : Alias { +Supertype 15 class Child : Alias() { +Target type of 'is' operation 38 if (par2 is Alias) {} +Usage in cast target type 41 val c = par2 as Alias diff --git a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.results.txt b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.results.txt new file mode 100644 index 000000000000..b12d027d0615 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/findTypeAliasUsages/classAlias.results.txt @@ -0,0 +1,9 @@ +Function return types 26 fun f2(par: Alias, par2: OOO) : Alias { +Local variable declaration 28 val a: Alias +New instance creation 30 a = Alias() //not found in K2, see KTIJ-26095 +Parameter type 26 fun f2(par: Alias, par2: OOO) : Alias { +Super type qualifier 18 super.opFun() //not found in K2, see KTIJ-26095 +Supertype 15 class Child : Alias() { +Target type of 'is' operation 38 if (par2 is Alias) {} +Type parameter 32 val b = WithGeneric() //not found in K2, see KTIJ-26095 +Usage in cast target type 41 val c = par2 as Alias From 045798e76b73e3d47704a83ecd1dd569c01a58fb Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Mon, 3 Jul 2023 09:09:06 +0200 Subject: [PATCH 168/226] [java-inspection] IDEA-324133 not resolve for UnsupportedChronoFieldUnitCallInspection GitOrigin-RevId: 5d8dca30a901e84340b592c7d074dee28c6cbb86 --- .../bugs/UnsupportedChronoFieldUnitCallInspection.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/UnsupportedChronoFieldUnitCallInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/UnsupportedChronoFieldUnitCallInspection.java index 670d6af7f0e8..3c54dd26c350 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/UnsupportedChronoFieldUnitCallInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/UnsupportedChronoFieldUnitCallInspection.java @@ -29,16 +29,19 @@ public class UnsupportedChronoFieldUnitCallInspection extends AbstractBaseJavaLo return new JavaElementVisitor() { @Override public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) { - PsiMethod method = call.resolveMethod(); - if (method == null) return; - String methodName = method.getName(); + String methodName = call.getMethodExpression().getReferenceName(); if (!"get".equals(methodName) && !"getLong".equals(methodName) && !"with".equals(methodName) && !"plus".equals(methodName) && !"minus".equals(methodName)) { return; } + if (!myMatcher.test(call)) { return; } + + PsiMethod method = call.resolveMethod(); + if (method == null) return; + int fieldArgumentIndex = 1; if ("get".equals(methodName) || "getLong".equals(methodName) || "with".equals(methodName)) { fieldArgumentIndex = 0; From 28bafa0ae3bb55e7621cabb260e4ac749a75397d Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Mon, 3 Jul 2023 09:32:46 +0200 Subject: [PATCH 169/226] [java-inspection] IDEA-324133 not resolve for RedundantExplicitChronoFieldInspection GitOrigin-RevId: 883695de18261d6202065f6fa4f640d6a0de4d49 --- .../RedundantExplicitChronoFieldInspection.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/redundancy/RedundantExplicitChronoFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/redundancy/RedundantExplicitChronoFieldInspection.java index bb37d8e535fb..d4c6db2c7945 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/redundancy/RedundantExplicitChronoFieldInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/redundancy/RedundantExplicitChronoFieldInspection.java @@ -32,16 +32,13 @@ public class RedundantExplicitChronoFieldInspection extends AbstractBaseJavaLoca return new JavaElementVisitor() { @Override public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) { - PsiMethod method = call.resolveMethod(); - if (method == null) { - return; - } - String methodName = method.getName(); + String methodName = call.getMethodExpression().getReferenceName(); if (!"get".equals(methodName) && !"with".equals(methodName) && !"plus".equals(methodName) && !"minus".equals(methodName)) { return; } - if (!CAN_BE_SIMPLIFIED_MATCHERS.methodMatches(method)) return; + + if (!CAN_BE_SIMPLIFIED_MATCHERS.matches(call)) return; int fieldArgumentIndex = 1; if ("get".equals(methodName) || "with".equals(methodName)) { fieldArgumentIndex = 0; From 0a5938f9dce7be0c3f7d472068b891a7a1d212ee Mon Sep 17 00:00:00 2001 From: Liubov Afanaseva Date: Mon, 3 Jul 2023 09:19:31 +0200 Subject: [PATCH 170/226] IDEA-297814 FUS: SerializationHelper must be object GitOrigin-RevId: 1996acdbe88be7ec3a923c57db104e6194cb7e14 --- .../statistic/eventLog/LogEventSerializer.kt | 105 +++++++++--------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/LogEventSerializer.kt b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/LogEventSerializer.kt index 8985ba69f564..250666b2350b 100644 --- a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/LogEventSerializer.kt +++ b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/LogEventSerializer.kt @@ -7,8 +7,8 @@ import com.fasterxml.jackson.core.exc.StreamReadException import com.fasterxml.jackson.databind.* import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.module.SimpleModule -import com.fasterxml.jackson.module.kotlin.kotlinModule import com.fasterxml.jackson.databind.node.* +import com.fasterxml.jackson.module.kotlin.kotlinModule import com.jetbrains.fus.reporting.model.lion3.LogEvent import com.jetbrains.fus.reporting.model.lion3.LogEventAction import com.jetbrains.fus.reporting.model.lion3.LogEventGroup @@ -52,7 +52,7 @@ object LogEventSerializer { /** * Serialize events manually, so it won't be changed by scrambling */ - fun toJson(event: LogEvent): ObjectNode { + private fun toJson(event: LogEvent): ObjectNode { val mapper = ObjectMapper() val obj = mapper.createObjectNode() @@ -119,62 +119,61 @@ class LogEventRecordRequestJsonDeserializer : JsonDeserializer Date: Mon, 3 Jul 2023 09:21:25 +0200 Subject: [PATCH 171/226] [java-intentions] More ModCommands (IDEA-322693) GitOrigin-RevId: 9e4d2085352ac53769ea1f5b2fbdd5f37a019522 --- .../analysis/AdaptExpressionTypeFixUtil.java | 2 +- .../impl/quickfix/WrapExpressionFix.java | 79 +++++----------- ...VariableAccessFromInnerClassJava10Fix.java | 72 +++++--------- .../WrapSwitchRuleStatementsIntoBlockFix.java | 58 +++++------- .../intention/impl/SortContentAction.java | 28 +++--- .../impl/SplitDeclarationAction.java | 37 ++++---- .../intention/impl/SplitFilterAction.java | 46 +++++---- ...itchBranchWithSeveralCaseValuesAction.java | 62 ++++++------ .../impl/WrapWithUnmodifiableAction.java | 94 ++++++++----------- .../impl/config/QuickFixFactoryImpl.java | 4 +- 10 files changed, 188 insertions(+), 294 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AdaptExpressionTypeFixUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AdaptExpressionTypeFixUtil.java index 5e8fc108743c..e0f7de0dc1eb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AdaptExpressionTypeFixUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AdaptExpressionTypeFixUtil.java @@ -233,7 +233,7 @@ final class AdaptExpressionTypeFixUtil { info.registerFix(action3, null, null, null, null); IntentionAction action2 = QUICK_FIX_FACTORY.createWrapWithOptionalFix(expectedType, expression); info.registerFix(action2, null, null, null, null); - IntentionAction action1 = new WrapExpressionFix(expectedType, expression, role); + var action1 = new WrapExpressionFix(expectedType, expression, role); info.registerFix(action1, null, null, null, null); PsiType castToType = suggestCastTo(expectedType, actualType); if (castToType != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapExpressionFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapExpressionFix.java index b306100aa6ac..31fa87ab7711 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapExpressionFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapExpressionFix.java @@ -1,20 +1,15 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 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.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.codeInspection.PsiUpdateModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,33 +18,20 @@ import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; -public class WrapExpressionFix implements IntentionAction { +public class WrapExpressionFix extends PsiUpdateModCommandAction { private static final Logger LOG = Logger.getInstance(WrapExpressionFix.class); - private final PsiExpression myExpression; private final @Nullable String myRole; private final PsiClassType myExpectedType; private final boolean myPrimitiveExpected; private final String myMethodPresentation; public WrapExpressionFix(@NotNull PsiType expectedType, @NotNull PsiExpression expression, @Nullable String role) { - myExpression = expression; + super(expression); myRole = role; myExpectedType = getClassType(expectedType, expression); myPrimitiveExpected = expectedType instanceof PsiPrimitiveType; - myMethodPresentation = getMethodPresentation(myExpression, myExpectedType, myPrimitiveExpected); - } - - private WrapExpressionFix(PsiExpression expression, - PsiClassType expectedType, - boolean primitiveExpected, - String methodPresentation, - @Nullable String role) { - myExpression = expression; - myExpectedType = expectedType; - myPrimitiveExpected = primitiveExpected; - myMethodPresentation = methodPresentation; - myRole = role; + myMethodPresentation = getMethodPresentation(expression, myExpectedType, myPrimitiveExpected); } @Nullable @@ -63,13 +45,6 @@ public class WrapExpressionFix implements IntentionAction { return null; } - @Override - @NotNull - public String getText() { - return myRole == null ? QuickFixBundle.message("wrap.expression.using.static.accessor.text", myMethodPresentation) : - QuickFixBundle.message("wrap.expression.using.static.accessor.text.role", myMethodPresentation, myRole); - } - private static String getMethodPresentation(PsiExpression expression, PsiClassType expectedType, boolean primitiveExpected) { PsiType type = expression.getType(); if (expectedType != null && type != null) { @@ -127,43 +102,40 @@ public class WrapExpressionFix implements IntentionAction { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return myMethodPresentation != null - && myExpression.isValid() - && BaseIntentionAction.canModify(myExpression) + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiExpression myExpression) { + boolean available = myMethodPresentation != null && PsiImplUtil.getSwitchLabel(myExpression) == null && myExpectedType != null && myExpectedType.isValid() && myExpression.getType() != null && findWrapper(myExpression.getType(), myExpectedType, myPrimitiveExpected, myExpression) != null; + if (!available) return null; + String message = myRole == null ? QuickFixBundle.message("wrap.expression.using.static.accessor.text", myMethodPresentation) : + QuickFixBundle.message("wrap.expression.using.static.accessor.text.role", myMethodPresentation, myRole); + return Presentation.of(message); } + @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - PsiType type = myExpression.getType(); + protected void invoke(@NotNull ActionContext context, @NotNull PsiExpression expression, @NotNull ModPsiUpdater updater) { + PsiType type = expression.getType(); if (type == null) { LOG.error("Expression type is null"); return; } - PsiMethod wrapper = findWrapper(type, myExpectedType, myPrimitiveExpected, myExpression); + PsiMethod wrapper = findWrapper(type, myExpectedType, myPrimitiveExpected, expression); if (wrapper == null) { LOG.error("Wrapper not found; expectedType = " + myExpectedType.getCanonicalText() + "; primitiveExpected = " + myPrimitiveExpected); return; } - PsiElementFactory factory = JavaPsiFacade.getElementFactory(file.getProject()); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.project()); @NonNls String methodCallText = "Foo." + wrapper.getName() + "()"; - PsiMethodCallExpression call = (PsiMethodCallExpression)factory.createExpressionFromText(methodCallText, - null); - call.getArgumentList().add(myExpression); + PsiMethodCallExpression call = (PsiMethodCallExpression)factory.createExpressionFromText(methodCallText, null); + call.getArgumentList().add(expression); PsiReferenceExpression qualifier = (PsiReferenceExpression)Objects.requireNonNull(call.getMethodExpression().getQualifierExpression()); PsiClass wrapperClass = Objects.requireNonNull(wrapper.getContainingClass()); qualifier.bindToElement(wrapperClass); - myExpression.replace(call); - } - - @Override - public boolean startInWriteAction() { - return true; + expression.replace(call); } public static void registerWrapAction(JavaResolveResult[] candidates, @@ -208,17 +180,8 @@ public class WrapExpressionFix implements IntentionAction { } if (expectedType != null) { - IntentionAction action = new WrapExpressionFix(expectedType, expr, null); + var action = new WrapExpressionFix(expectedType, expr, null); highlightInfo.registerFix(action, null, null, fixRange, null); } } - - @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new WrapExpressionFix(PsiTreeUtil.findSameElementInCopy(myExpression, target), - myExpectedType, - myPrimitiveExpected, - myMethodPresentation, - myRole); - } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassJava10Fix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassJava10Fix.java index d48f3579ad67..ca848a810f2f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassJava10Fix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassJava10Fix.java @@ -1,38 +1,33 @@ // Copyright 2000-2023 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.quickfix; -import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer; import com.intellij.util.CommonJavaRefactoringUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.SmartList; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.TypeUtils; +import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; -import java.util.LinkedHashSet; import java.util.List; -import java.util.stream.Collectors; import static com.intellij.util.ObjectUtils.tryCast; import static java.util.Collections.emptyList; -public class VariableAccessFromInnerClassJava10Fix extends BaseIntentionAction { +public class VariableAccessFromInnerClassJava10Fix extends PsiUpdateModCommandAction { @NonNls private final static String[] NAMES = { "ref", "lambdaContext", @@ -40,15 +35,8 @@ public class VariableAccessFromInnerClassJava10Fix extends BaseIntentionAction { "rContext" }; - private final PsiElement myContext; - public VariableAccessFromInnerClassJava10Fix(PsiElement context) { - myContext = context; - } - - @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new VariableAccessFromInnerClassJava10Fix(PsiTreeUtil.findSameElementInCopy(myContext, target)); + super(context); } @Nls(capitalization = Nls.Capitalization.Sentence) @@ -59,30 +47,27 @@ public class VariableAccessFromInnerClassJava10Fix extends BaseIntentionAction { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - if (!PsiUtil.isLanguageLevel10OrHigher(file)) return false; - if (!myContext.isValid()) return false; - PsiReferenceExpression reference = tryCast(myContext, PsiReferenceExpression.class); - if (reference == null) return false; + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiElement element) { + if (!PsiUtil.isLanguageLevel10OrHigher(context.file())) return null; + PsiReferenceExpression reference = tryCast(element, PsiReferenceExpression.class); + if (reference == null) return null; PsiLocalVariable variable = tryCast(reference.resolve(), PsiLocalVariable.class); - if (variable == null) return false; + if (variable == null) return null; PsiDeclarationStatement declarationStatement = tryCast(variable.getParent(), PsiDeclarationStatement.class); - if (declarationStatement == null) return false; - if (declarationStatement.getDeclaredElements().length != 1) return false; + if (declarationStatement == null) return null; + if (declarationStatement.getDeclaredElements().length != 1) return null; String name = variable.getName(); PsiType type = variable.getType(); if (!PsiTypesUtil.isDenotableType(type, variable)) { - return false; + return null; } - setText(QuickFixBundle.message("convert.variable.to.field.in.anonymous.class.fix.name", name)); - return true; + return Presentation.of(QuickFixBundle.message("convert.variable.to.field.in.anonymous.class.fix.name", name)); } @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - if (!(myContext instanceof PsiReferenceExpression referenceExpression) || !myContext.isValid()) return; - if (!FileModificationService.getInstance().preparePsiElementsForWrite(myContext)) return; + protected void invoke(@NotNull ActionContext context, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) { + if (!(element instanceof PsiReferenceExpression referenceExpression)) return; PsiLocalVariable variable = tryCast(referenceExpression.resolve(), PsiLocalVariable.class); if (variable == null) return; @@ -97,9 +82,10 @@ public class VariableAccessFromInnerClassJava10Fix extends BaseIntentionAction { return; } - - JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); - String boxName = codeStyleManager.suggestUniqueVariableName(NAMES[0], variable, true); + Project project = context.project(); + List suggestions = new VariableNameGenerator(variable, VariableKind.LOCAL_VARIABLE) + .byName(NAMES).generateAll(true); + String boxName = suggestions.get(0); String boxDeclarationText = "var " + boxName + " = new Object(){" + @@ -107,25 +93,11 @@ public class VariableAccessFromInnerClassJava10Fix extends BaseIntentionAction { "};"; PsiStatement boxDeclaration = JavaPsiFacade.getElementFactory(project).createStatementFromText(boxDeclarationText, variable); replaceReferences(variable, boxName); - if (editor == null) { - variable.replace(boxDeclaration); - return; - } PsiStatement statement = PsiTreeUtil.getParentOfType(variable, PsiStatement.class); if (statement == null) return; PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)statement.replace(boxDeclaration); PsiLocalVariable localVariable = (PsiLocalVariable)declarationStatement.getDeclaredElements()[0]; - SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project); - SmartPsiElementPointer pointer = smartPointerManager.createSmartPsiElementPointer(localVariable); - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); - PsiLocalVariable varToChange = pointer.getElement(); - if (varToChange == null) return; - editor.getCaretModel().moveToOffset(varToChange.getTextOffset()); - editor.getSelectionModel().removeSelection(); - LinkedHashSet suggestions = Arrays.stream(NAMES) - .map(suggestion -> codeStyleManager.suggestUniqueVariableName(suggestion, varToChange, var -> var == varToChange)) - .collect(Collectors.toCollection(() -> new LinkedHashSet<>())); - new MemberInplaceRenamer(varToChange, varToChange, editor).performInplaceRefactoring(suggestions); + updater.rename(localVariable, suggestions); } private static void replaceReferences(PsiLocalVariable variable, String boxName) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapSwitchRuleStatementsIntoBlockFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapSwitchRuleStatementsIntoBlockFix.java index 072840874563..84b87e753d51 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapSwitchRuleStatementsIntoBlockFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapSwitchRuleStatementsIntoBlockFix.java @@ -1,17 +1,13 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 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.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.daemon.impl.actions.IntentionActionWithFixAllOption; -import com.intellij.codeInsight.intention.FileModifier; -import com.intellij.codeInsight.intention.impl.BaseIntentionAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; +import com.intellij.codeInspection.PsiUpdateModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -19,17 +15,9 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; -public class WrapSwitchRuleStatementsIntoBlockFix extends BaseIntentionAction implements IntentionActionWithFixAllOption { - @NotNull - private final PsiSwitchLabeledRuleStatement myRuleStatement; - +public class WrapSwitchRuleStatementsIntoBlockFix extends PsiUpdateModCommandAction { public WrapSwitchRuleStatementsIntoBlockFix(@NotNull PsiSwitchLabeledRuleStatement ruleStatement) { - myRuleStatement = ruleStatement; - } - - @Override - public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { - return new WrapSwitchRuleStatementsIntoBlockFix(PsiTreeUtil.findSameElementInCopy(myRuleStatement, target)); + super(ruleStatement); } @Nls(capitalization = Nls.Capitalization.Sentence) @@ -40,27 +28,23 @@ public class WrapSwitchRuleStatementsIntoBlockFix extends BaseIntentionAction im } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - if (!(file instanceof PsiJavaFile)) return false; - if (!myRuleStatement.isValid()) return false; - if (myRuleStatement.getBody() instanceof PsiBlockStatement) return false; - PsiStatement sibling = PsiTreeUtil.getNextSiblingOfType(myRuleStatement, PsiStatement.class); + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiSwitchLabeledRuleStatement ruleStatement) { + if (ruleStatement.getBody() instanceof PsiBlockStatement) return null; + PsiStatement sibling = PsiTreeUtil.getNextSiblingOfType(ruleStatement, PsiStatement.class); if (sibling == null || sibling instanceof PsiSwitchLabelStatementBase) { - setText(getFamilyName()); - } else { - setText(QuickFixBundle.message("wrap.with.block")); + return Presentation.of(getFamilyName()).withFixAllOption(this); } - return true; + return Presentation.of(QuickFixBundle.message("wrap.with.block")).withFixAllOption(this); } @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - if (!myRuleStatement.isValid()) return; - PsiCodeBlock parent = ObjectUtils.tryCast(myRuleStatement.getParent(), PsiCodeBlock.class); + protected void invoke(@NotNull ActionContext context, @NotNull PsiSwitchLabeledRuleStatement ruleStatement, @NotNull ModPsiUpdater updater) { + if (!ruleStatement.isValid()) return; + PsiCodeBlock parent = ObjectUtils.tryCast(ruleStatement.getParent(), PsiCodeBlock.class); if (parent == null) return; PsiJavaToken rBrace = parent.getRBrace(); PsiElement[] children = parent.getChildren(); - int index = ArrayUtil.indexOf(children, myRuleStatement); + int index = ArrayUtil.indexOf(children, ruleStatement); assert index >= 0; int nextIndex = index + 1; while (nextIndex < children.length && !(children[nextIndex] instanceof PsiSwitchLabelStatementBase) && children[nextIndex] != rBrace) { @@ -70,18 +54,18 @@ public class WrapSwitchRuleStatementsIntoBlockFix extends BaseIntentionAction im nextIndex--; } PsiElement oldBody = null; - if (myRuleStatement.getBody() != null) { - oldBody = myRuleStatement.getBody().copy(); - myRuleStatement.getBody().delete(); + if (ruleStatement.getBody() != null) { + oldBody = ruleStatement.getBody().copy(); + ruleStatement.getBody().delete(); } - for (PsiElement lastChild = myRuleStatement.getLastChild(); lastChild != null; lastChild = lastChild.getPrevSibling()) { + for (PsiElement lastChild = ruleStatement.getLastChild(); lastChild != null; lastChild = lastChild.getPrevSibling()) { if (PsiUtil.isJavaToken(lastChild, JavaTokenType.SEMICOLON)) { lastChild.delete(); break; } } - PsiSwitchLabeledRuleStatement newRule = (PsiSwitchLabeledRuleStatement)JavaPsiFacade.getElementFactory(project).createStatementFromText( - myRuleStatement.getText() + "{}", myRuleStatement); + PsiSwitchLabeledRuleStatement newRule = (PsiSwitchLabeledRuleStatement)JavaPsiFacade.getElementFactory(context.project()) + .createStatementFromText(ruleStatement.getText() + "{}", ruleStatement); PsiCodeBlock block = ((PsiBlockStatement)Objects.requireNonNull(newRule.getBody())).getCodeBlock(); if (oldBody != null) { block.add(oldBody); @@ -92,6 +76,6 @@ public class WrapSwitchRuleStatementsIntoBlockFix extends BaseIntentionAction im block.addRange(first, last); parent.deleteChildRange(first, last); } - myRuleStatement.replace(newRule); + ruleStatement.replace(newRule); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SortContentAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SortContentAction.java index 85075a9f3652..b3b2090b26d9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SortContentAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SortContentAction.java @@ -1,11 +1,11 @@ -// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.intention.impl; import com.google.common.collect.Comparators; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.javadoc.PsiDocComment; @@ -13,7 +13,6 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -27,9 +26,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.stream.Collectors; -public final class SortContentAction extends PsiElementBaseIntentionAction { +public final class SortContentAction extends PsiUpdateModCommandAction { public static final int MIN_ELEMENTS_COUNT = 3; private static final class Holder { @@ -51,6 +49,10 @@ public final class SortContentAction extends PsiElementBaseIntentionAction { ); } + public SortContentAction() { + super(PsiElement.class); + } + @Nls @NotNull @Override @@ -58,14 +60,8 @@ public final class SortContentAction extends PsiElementBaseIntentionAction { return JavaBundle.message("intention.family.sort.content"); } - @NotNull @Override - public String getText() { - return getFamilyName(); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + protected void invoke(@NotNull ActionContext context, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) { for (Sortable sortable : Holder.OUR_SORTABLES) { if (sortable.isAvailable(element)) { sortable.replaceWithSorted(element); @@ -74,11 +70,11 @@ public final class SortContentAction extends PsiElementBaseIntentionAction { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiElement element) { for (Sortable sortable : Holder.OUR_SORTABLES) { - if (sortable.isAvailable(element)) return true; + if (sortable.isAvailable(element)) return Presentation.of(getFamilyName()); } - return false; + return null; } private interface SortingStrategy { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java index 46d4f16967dc..fec2f9998723 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java @@ -1,19 +1,22 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.intention.impl; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.java.JavaBundle; -import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class SplitDeclarationAction extends PsiElementBaseIntentionAction { +public class SplitDeclarationAction extends PsiUpdateModCommandAction { + public SplitDeclarationAction() { + super(PsiDeclarationStatement.class); + } + @Override @NotNull public String getFamilyName() { @@ -21,14 +24,13 @@ public class SplitDeclarationAction extends PsiElementBaseIntentionAction { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - if (element instanceof PsiCompiledElement) return false; - if (!canModify(element)) return false; - if (!element.getLanguage().isKindOf(JavaLanguage.INSTANCE)) return false; - - final PsiDeclarationStatement - context = PsiTreeUtil.getParentOfType(element, PsiDeclarationStatement.class, false, PsiClass.class, PsiCodeBlock.class); - return context != null && isAvailableOnDeclarationStatement(context); + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiDeclarationStatement element) { + if (PsiTreeUtil.getParentOfType(context.findLeaf(), PsiDeclarationStatement.class, false, PsiClass.class, PsiCodeBlock.class) + != element) { + return null; + } + return isAvailableOnDeclarationStatement(element) ? + Presentation.of(JavaBundle.message("intention.split.declaration.assignment.text")) : null; } private boolean isAvailableOnDeclarationStatement(PsiDeclarationStatement decl) { @@ -65,16 +67,11 @@ public class SplitDeclarationAction extends PsiElementBaseIntentionAction { parent = parent.getNextSibling(); } } - setText(JavaBundle.message("intention.split.declaration.assignment.text")); return true; } @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - final PsiDeclarationStatement decl = PsiTreeUtil.getParentOfType(element, PsiDeclarationStatement.class); - - if (decl != null) { - ExpressionUtils.splitDeclaration(decl, project); - } + protected void invoke(@NotNull ActionContext context, @NotNull PsiDeclarationStatement decl, @NotNull ModPsiUpdater updater) { + ExpressionUtils.splitDeclaration(decl, context.project()); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitFilterAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitFilterAction.java index 4e4196448aca..9695673d755a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitFilterAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitFilterAction.java @@ -1,18 +1,17 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.intention.impl; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.java.JavaBundle; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.JavaPsiPatternUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.psiutils.VariableAccessUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -21,25 +20,29 @@ import java.util.List; import static com.intellij.codeInsight.intention.impl.SplitConditionUtil.getLOperands; import static com.intellij.codeInsight.intention.impl.SplitConditionUtil.getROperands; -public class SplitFilterAction extends PsiElementBaseIntentionAction { +public class SplitFilterAction extends PsiUpdateModCommandAction { private static final Logger LOG = Logger.getInstance(SplitFilterAction.class.getName()); + public SplitFilterAction() { + super(PsiJavaToken.class); + } + @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiJavaToken element) { final PsiPolyadicExpression expression = SplitConditionUtil.findCondition(element, true, false); - if (expression == null || expression.getOperands().length < 2) return false; + if (expression == null || expression.getOperands().length < 2) return null; PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); - if (!(parent instanceof PsiLambdaExpression)) return false; - if (((PsiLambdaExpression)parent).getParameterList().getParametersCount() != 1) return false; + if (!(parent instanceof PsiLambdaExpression lambda)) return null; + if (lambda.getParameterList().getParametersCount() != 1) return null; parent = PsiUtil.skipParenthesizedExprUp(parent.getParent()); - if (!(parent instanceof PsiExpressionList)) return false; + if (!(parent instanceof PsiExpressionList)) return null; final PsiElement gParent = parent.getParent(); - if (!(gParent instanceof PsiMethodCallExpression)) return false; - - return MergeFilterChainAction.isFilterCall((PsiMethodCallExpression)gParent) && - !hasPatternVariablesUsedAfterSplit(expression, element); + if (!(gParent instanceof PsiMethodCallExpression call)) return null; + if (!MergeFilterChainAction.isFilterCall(call) || hasPatternVariablesUsedAfterSplit(expression, element)) return null; + + return Presentation.of(JavaBundle.message("intention.split.filter.text")); } private static boolean hasPatternVariablesUsedAfterSplit(@NotNull PsiPolyadicExpression expression, @NotNull PsiElement token) { @@ -61,12 +64,6 @@ public class SplitFilterAction extends PsiElementBaseIntentionAction { return false; } - @NotNull - @Override - public String getText() { - return JavaBundle.message("intention.split.filter.text"); - } - @Override @NotNull public String getFamilyName() { @@ -74,8 +71,7 @@ public class SplitFilterAction extends PsiElementBaseIntentionAction { } @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - final PsiJavaToken token = (PsiJavaToken)element; + protected void invoke(@NotNull ActionContext context, @NotNull PsiJavaToken token, @NotNull ModPsiUpdater updater) { final PsiPolyadicExpression expression = SplitConditionUtil.findCondition(token, true, false); final PsiLambdaExpression originalLambdaExpression = PsiTreeUtil.getParentOfType(expression, PsiLambdaExpression.class); @@ -89,8 +85,8 @@ public class SplitFilterAction extends PsiElementBaseIntentionAction { final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); LOG.assertTrue(qualifierExpression != null); - final PsiMethodCallExpression newFilterCall = (PsiMethodCallExpression) - JavaPsiFacade.getElementFactory(project).createExpressionFromText("a.filter(" + lambdaParameterName + " -> x)", methodCallExpression); + final PsiMethodCallExpression newFilterCall = (PsiMethodCallExpression)JavaPsiFacade.getElementFactory(context.project()) + .createExpressionFromText("a.filter(" + lambdaParameterName + " -> x)", methodCallExpression); final PsiLambdaExpression newFilterLambda = (PsiLambdaExpression)newFilterCall.getArgumentList().getExpressions()[0]; final PsiExpression filterCallQualifier = newFilterCall.getMethodExpression().getQualifierExpression(); LOG.assertTrue(filterCallQualifier != null); diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitSwitchBranchWithSeveralCaseValuesAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitSwitchBranchWithSeveralCaseValuesAction.java index 7d8537643711..b9bed2b53816 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitSwitchBranchWithSeveralCaseValuesAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitSwitchBranchWithSeveralCaseValuesAction.java @@ -1,14 +1,15 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.intention.impl; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.codeInspection.ModCommands; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import com.siyeh.ig.psiutils.SwitchUtils; import org.jetbrains.annotations.Contract; @@ -24,7 +25,7 @@ import static com.intellij.psi.util.PsiTreeUtil.getNextSiblingOfType; import static com.intellij.psi.util.PsiTreeUtil.getPrevSiblingOfType; import static com.siyeh.ig.psiutils.ControlFlowUtils.statementMayCompleteNormally; -public class SplitSwitchBranchWithSeveralCaseValuesAction extends PsiElementBaseIntentionAction { +public class SplitSwitchBranchWithSeveralCaseValuesAction implements ModCommandAction { @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @@ -34,23 +35,23 @@ public class SplitSwitchBranchWithSeveralCaseValuesAction extends PsiElementBase } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - PsiSwitchLabelStatementBase labelStatement = findLabelStatement(editor, element); - if (labelStatement == null || labelStatement.getEnclosingSwitchBlock() == null) return false; + public @Nullable Presentation getPresentation(@NotNull ActionContext context) { + PsiElement element = context.findLeaf(); + if (element == null) return null; + PsiSwitchLabelStatementBase labelStatement = findLabelStatement(context, element); + if (labelStatement == null || labelStatement.getEnclosingSwitchBlock() == null) return null; if (labelStatement instanceof PsiSwitchLabelStatement) { if (isMultiValueCase(labelStatement)) { // mixed syntax "case 1, 2: some code" if (isAvailableForLabel(labelStatement)) { - setText(JavaBundle.message("intention.split.switch.branch.with.several.case.values.split.text")); - return true; + return Presentation.of(JavaBundle.message("intention.split.switch.branch.with.several.case.values.split.text")); } } else if (hasSiblingLabel(labelStatement)) { // traditional syntax "case 1: case 2: some code" PsiSwitchLabelStatement lastSiblingLabel = findLastSiblingLabel(labelStatement, false); if (isAvailableForLabel(lastSiblingLabel)) { - setText(JavaBundle.message("intention.split.switch.branch.with.several.case.values.copy.text")); - return true; + return Presentation.of(JavaBundle.message("intention.split.switch.branch.with.several.case.values.copy.text")); } } } @@ -59,12 +60,11 @@ public class SplitSwitchBranchWithSeveralCaseValuesAction extends PsiElementBase if (isMultiValueCase(labelStatement)) { PsiStatement body = ruleStatement.getBody(); if (body != null && element.getTextOffset() < body.getTextOffset()) { - setText(JavaBundle.message("intention.split.switch.branch.with.several.case.values.split.text")); - return true; + return Presentation.of(JavaBundle.message("intention.split.switch.branch.with.several.case.values.split.text")); } } } - return false; + return null; } private static boolean isAvailableForLabel(@Nullable PsiSwitchLabelStatementBase label) { @@ -87,25 +87,31 @@ public class SplitSwitchBranchWithSeveralCaseValuesAction extends PsiElementBase * Handle the case where the caret is on the right side of the element we're interested in */ @Nullable - private static PsiElement getPreviousElement(@NotNull Editor editor, @NotNull PsiElement element) { - PsiFile file = element.getContainingFile(); - int caretOffset = editor.getCaretModel().getOffset(); + private static PsiElement getPreviousElement(@NotNull ActionContext context, @NotNull PsiElement element) { + int caretOffset = context.offset(); int elementOffset = element.getTextRange().getStartOffset(); if (caretOffset == elementOffset && caretOffset > 0) { - return file.findElementAt(caretOffset - 1); + return context.findLeafOnTheLeft(); } return null; } @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - PsiSwitchLabelStatementBase statement = findLabelStatement(editor, element); + public @NotNull ModCommand perform(@NotNull ActionContext context) { + return ModCommands.psiUpdate(context, updater -> invoke(context, updater)); + } + + private static void invoke(@NotNull ActionContext context, @NotNull ModPsiUpdater updater) { + context = context.withFile(updater.getWritable(context.file())); + PsiElement element = context.findLeaf(); + if (element == null) return; + PsiSwitchLabelStatementBase statement = findLabelStatement(context, element); PsiElement result = null; if (statement instanceof PsiSwitchLabelStatement labelStatement) { PsiCaseLabelElementList labelElementList = labelStatement.getCaseLabelElementList(); if (labelElementList != null && labelElementList.getElementCount() > 1) { - PsiCaseLabelElement labelElement = findLabelElement(element, labelElementList, editor); + PsiCaseLabelElement labelElement = findLabelElement(element, labelElementList, context); Branch branch = Branch.fromLabel(labelStatement); if (branch != null) { if (isInList(labelElement, labelElementList)) { @@ -132,7 +138,7 @@ public class SplitSwitchBranchWithSeveralCaseValuesAction extends PsiElementBase else if (statement instanceof PsiSwitchLabeledRuleStatement labeledRule) { PsiCaseLabelElementList labelElementList = labeledRule.getCaseLabelElementList(); if (labelElementList != null) { - PsiCaseLabelElement labelElement = findLabelElement(element, labelElementList, editor); + PsiCaseLabelElement labelElement = findLabelElement(element, labelElementList, context); if (isInList(labelElement, labelElementList)) { result = moveRuleAfter(labelElement, labeledRule); } @@ -142,16 +148,16 @@ public class SplitSwitchBranchWithSeveralCaseValuesAction extends PsiElementBase } } if (result != null) { - editor.getCaretModel().moveToOffset(result.getTextOffset()); + updater.moveTo(result); } } private static PsiCaseLabelElement findLabelElement(@NotNull PsiElement element, @NotNull PsiCaseLabelElementList labelElementList, - @NotNull Editor editor) { + @NotNull ActionContext context) { PsiCaseLabelElement labelElement = PsiTreeUtil.getNonStrictParentOfType(element, PsiCaseLabelElement.class); if (!isInList(labelElement, labelElementList)) { - PsiElement previousElement = getPreviousElement(editor, element); + PsiElement previousElement = getPreviousElement(context, element); labelElement = PsiTreeUtil.getNonStrictParentOfType(previousElement, PsiCaseLabelElement.class); } PsiElement caseLabel = PsiTreeUtil.findFirstParent(labelElement, parent -> @@ -166,14 +172,12 @@ public class SplitSwitchBranchWithSeveralCaseValuesAction extends PsiElementBase } @Nullable - private static PsiSwitchLabelStatementBase findLabelStatement(@NotNull Editor editor, - @NotNull PsiElement element) { - // Can't use BaseElementAtCaretIntentionAction, because there's ambiguity when the caret is after the list of case values before the arrow + private static PsiSwitchLabelStatementBase findLabelStatement(@NotNull ActionContext context, PsiElement element) { PsiStatement statement = PsiTreeUtil.getParentOfType(element, PsiStatement.class); if (statement instanceof PsiSwitchLabelStatementBase labelStatement) { return labelStatement; } - PsiElement previousElement = getPreviousElement(editor, element); + PsiElement previousElement = getPreviousElement(context, element); statement = PsiTreeUtil.getParentOfType(previousElement, PsiStatement.class); return ObjectUtils.tryCast(statement, PsiSwitchLabelStatementBase.class); } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/WrapWithUnmodifiableAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/WrapWithUnmodifiableAction.java index 06d42f9b0fde..14ebe55ed03d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/WrapWithUnmodifiableAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/WrapWithUnmodifiableAction.java @@ -1,19 +1,17 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.intention.impl; +import com.intellij.codeInspection.PsiUpdateModCommandAction; import com.intellij.codeInspection.dataFlow.CommonDataflow; import com.intellij.codeInspection.dataFlow.Mutability; import com.intellij.codeInspection.dataFlow.types.DfType; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ExpectedTypeUtils; @@ -28,7 +26,7 @@ import java.util.Set; import static com.intellij.psi.CommonClassNames.*; import static com.intellij.util.ObjectUtils.tryCast; -public class WrapWithUnmodifiableAction extends BaseIntentionAction { +public class WrapWithUnmodifiableAction extends PsiUpdateModCommandAction { private static final String JAVA_UTIL_SORTED_MAP = "java.util.SortedMap"; private static final Map CLASS_TO_METHOD = Map.of( @@ -38,42 +36,32 @@ public class WrapWithUnmodifiableAction extends BaseIntentionAction { JAVA_UTIL_SORTED_MAP, "unmodifiableSortedMap", JAVA_UTIL_MAP, "unmodifiableMap" ); + + public WrapWithUnmodifiableAction() { + super(PsiExpression.class); + } @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - if (editor == null || file == null || !canModify(file)) { - return; - } - PsiExpression expression = getParentExpression(editor, file); - if (expression != null) { - PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(expression.getType()); - if (psiClass != null) { + protected void invoke(@NotNull ActionContext context, @NotNull PsiExpression element, @NotNull ModPsiUpdater updater) { + PsiExpression expression = getParentExpression(element); + PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(expression.getType()); + if (psiClass != null) { - PsiClass expectedClass = PsiUtil.resolveClassInClassTypeOnly(getExpectedType(expression)); - if (expectedClass != null) { - String collectionClass = findSuperClass(psiClass, expectedClass, CLASS_TO_METHOD.keySet()); - if (collectionClass != null) { - String method = CLASS_TO_METHOD.get(collectionClass); - wrapWith(expression, method); - } + PsiClass expectedClass = PsiUtil.resolveClassInClassTypeOnly(getExpectedType(expression)); + if (expectedClass != null) { + String collectionClass = findSuperClass(psiClass, expectedClass, CLASS_TO_METHOD.keySet()); + if (collectionClass != null) { + String method = CLASS_TO_METHOD.get(collectionClass); + wrapWith(expression, method); } } } } - @Nullable - private static PsiExpression getParentExpression(@NotNull Editor editor, @NotNull PsiFile file) { - PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); - PsiExpression expression = PsiTreeUtil.getNonStrictParentOfType(element, PsiExpression.class); - if (expression == null) { - element = file.findElementAt(editor.getCaretModel().getOffset() - 1); - expression = PsiTreeUtil.getNonStrictParentOfType(element, PsiExpression.class); - } - if (expression != null) { - PsiMethodCallExpression methodCall = tryCast(expression.getParent(), PsiMethodCallExpression.class); - if (methodCall != null && methodCall.getMethodExpression() == expression) { - return methodCall; - } + private static @NotNull PsiExpression getParentExpression(@NotNull PsiExpression expression) { + PsiMethodCallExpression methodCall = tryCast(expression.getParent(), PsiMethodCallExpression.class); + if (methodCall != null && methodCall.getMethodExpression() == expression) { + return methodCall; } return expression; } @@ -86,32 +74,26 @@ public class WrapWithUnmodifiableAction extends BaseIntentionAction { } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - if (editor == null || file == null || !canModify(file)) { - return false; - } - PsiExpression expression = getParentExpression(editor, file); - if (expression != null) { - if (PsiUtil.isOnAssignmentLeftHand(expression)) return false; - PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(expression.getType()); - if (psiClass != null) { - PsiClass expectedClass = PsiUtil.resolveClassInClassTypeOnly(getExpectedType(expression)); + protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiExpression element) { + PsiExpression expression = getParentExpression(element); + if (PsiUtil.isOnAssignmentLeftHand(expression)) return null; + PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(expression.getType()); + if (psiClass != null) { + PsiClass expectedClass = PsiUtil.resolveClassInClassTypeOnly(getExpectedType(expression)); - if (expectedClass != null) { - String collectionClass = findSuperClass(psiClass, expectedClass, CLASS_TO_METHOD.keySet()); - if (collectionClass != null && !isUnmodifiable(expression)) { - String message = switch (collectionClass) { - case JAVA_UTIL_LIST -> "intention.wrap.with.unmodifiable.list"; - case JAVA_UTIL_SET, JAVA_UTIL_SORTED_SET -> "intention.wrap.with.unmodifiable.set"; - default -> "intention.wrap.with.unmodifiable.map"; - }; - setText(JavaBundle.message(message)); - return true; - } + if (expectedClass != null) { + String collectionClass = findSuperClass(psiClass, expectedClass, CLASS_TO_METHOD.keySet()); + if (collectionClass != null && !isUnmodifiable(expression)) { + String message = switch (collectionClass) { + case JAVA_UTIL_LIST -> "intention.wrap.with.unmodifiable.list"; + case JAVA_UTIL_SET, JAVA_UTIL_SORTED_SET -> "intention.wrap.with.unmodifiable.set"; + default -> "intention.wrap.with.unmodifiable.map"; + }; + return Presentation.of(JavaBundle.message(message)); } } } - return false; + return null; } private static PsiType getExpectedType(@NotNull PsiExpression expression) { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java index 07b6b2160700..ac0472575aee 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java @@ -1001,7 +1001,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @NotNull @Override public IntentionAction createWrapSwitchRuleStatementsIntoBlockFix(@NotNull PsiSwitchLabeledRuleStatement rule) { - return new WrapSwitchRuleStatementsIntoBlockFix(rule); + return new WrapSwitchRuleStatementsIntoBlockFix(rule).asIntention(); } @NotNull @@ -1192,7 +1192,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @Override public @NotNull IntentionAction createSplitSwitchBranchWithSeveralCaseValuesAction() { - return new SplitSwitchBranchWithSeveralCaseValuesAction(); + return new SplitSwitchBranchWithSeveralCaseValuesAction().asIntention(); } @Override From 7a885addc1d70d3681f1c24225ec5d621dea639a Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 3 Jul 2023 10:50:34 +0200 Subject: [PATCH 172/226] fix ide menu on maOS for old ui GitOrigin-RevId: 9e77fc433b5608e3243c9ad310c06809b26a0af7 --- .../intellij/openapi/wm/impl/IdeMenuBar.kt | 4 -- .../intellij/openapi/wm/impl/IdeRootPane.kt | 37 +++++++++++++------ .../header/toolbar/ToolbarFrameHeader.kt | 1 + 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt index 3450f58a133a..4d37b6df91c5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.kt @@ -225,10 +225,6 @@ internal fun doUpdateAppMenu() { //} } -internal fun createMenuBar(coroutineScope: CoroutineScope, frame: JFrame): IdeMenuBar { - return if (SystemInfoRt.isLinux) LinuxIdeMenuBar(coroutineScope, frame) else IdeMenuBar(coroutineScope, frame) -} - internal fun installAppMenuIfNeeded(frame: JFrame) { if (!SystemInfoRt.isLinux) { return diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt index b35cdf6eada6..2f40faeb4d23 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.kt @@ -166,7 +166,7 @@ open class IdeRootPane internal constructor(private val frame: IdeFrameImpl, val isDecoratedMenu = isDecoratedMenu val isFloatingMenuBarSupported = isFloatingMenuBarSupported if (!isDecoratedMenu && !isFloatingMenuBarSupported) { - jMenuBar = createMenuBar(coroutineScope.childScope(), frame) + createMacAwareMenuBar(frame = frame, component = this, coroutineScope.childScope()) helper = UndecoratedHelper(isFloatingMenuBarSupported = false) } else { @@ -177,21 +177,12 @@ open class IdeRootPane internal constructor(private val frame: IdeFrameImpl, val ideMenu: ActionAwareIdeMenuBar val customFrameTitlePane = if (ExperimentalUI.isNewUI()) { selectedEditorFilePath = null + ideMenu = createMacAwareMenuBar(frame = frame, component = this, coroutineScope.childScope()) if (SystemInfoRt.isMac) { - ideMenu = if (Menu.isJbScreenMenuEnabled()) { - createMacMenuBar(coroutineScope = coroutineScope.childScope(), component = this, frame = frame) - } - else { - val menuBar = IdeMenuBar(coroutineScope = coroutineScope.childScope(), frame = frame) - // if -DjbScreenMenuBar.enabled=false - frame.jMenuBar = menuBar - menuBar - } MacToolbarFrameHeader(coroutineScope = coroutineScope.childScope(), frame = frame, root = this) } else { - ideMenu = createMenuBar(coroutineScope = coroutineScope.childScope(), frame = frame) - ToolbarFrameHeader(coroutineScope = coroutineScope.childScope(), frame = frame, root = this, ideMenuBar = ideMenu) + ToolbarFrameHeader(coroutineScope = coroutineScope.childScope(), frame = frame, root = this, ideMenuBar = ideMenu as IdeMenuBar) } } else { @@ -760,4 +751,26 @@ private fun disposeIfNeeded(component: JComponent) { if (component is Disposable && !Disposer.isDisposed(component)) { Disposer.dispose(component) } +} + +private fun createMacAwareMenuBar(frame: JFrame, component: JComponent, coroutineScope: CoroutineScope): ActionAwareIdeMenuBar { + if (SystemInfoRt.isMac) { + val ideMenu = if (Menu.isJbScreenMenuEnabled()) { + createMacMenuBar(coroutineScope = coroutineScope, component = component, frame = frame) + } + else { + val menuBar = IdeMenuBar(coroutineScope = coroutineScope, frame = frame) + // if -DjbScreenMenuBar.enabled=false + frame.jMenuBar = menuBar + menuBar + } + return ideMenu + } + else { + return createMenuBar(coroutineScope = coroutineScope, frame = frame) + } +} + +internal fun createMenuBar(coroutineScope: CoroutineScope, frame: JFrame): IdeMenuBar { + return if (SystemInfoRt.isLinux) LinuxIdeMenuBar(coroutineScope, frame) else IdeMenuBar(coroutineScope, frame) } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/toolbar/ToolbarFrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/toolbar/ToolbarFrameHeader.kt index 20e186da60df..a9a1610816e6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/toolbar/ToolbarFrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/toolbar/ToolbarFrameHeader.kt @@ -2,6 +2,7 @@ package com.intellij.openapi.wm.impl.customFrameDecorations.header.toolbar import com.intellij.ide.ProjectWindowCustomizerService +import com.intellij.ide.menu.ActionAwareIdeMenuBar import com.intellij.ide.ui.UISettings import com.intellij.ide.ui.UISettingsListener import com.intellij.ide.ui.customization.CustomActionsSchema From 51ea37d03ddf8c0ed7053aca688717ce891dc363 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Mon, 3 Jul 2023 10:19:07 +0200 Subject: [PATCH 173/226] [project model] speed up processing module changes in ModuleDependencyIndexImpl (IDEA-313305) It's more efficient to first determine which dependencies were removed and which were added if something changes in ModuleEntity, and then update the index accordingly. GitOrigin-RevId: e46b25bc562755d75bf597c9d9df5e0dd314b121 --- .../module/ModuleDependencyIndexImpl.kt | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/platform/projectModel-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleDependencyIndexImpl.kt b/platform/projectModel-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleDependencyIndexImpl.kt index 621b55f35377..8e0cf20607f7 100644 --- a/platform/projectModel-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleDependencyIndexImpl.kt +++ b/platform/projectModel-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleDependencyIndexImpl.kt @@ -14,17 +14,18 @@ import com.intellij.openapi.roots.ex.ProjectRootManagerEx import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.roots.libraries.LibraryTable import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar +import com.intellij.platform.backend.workspace.WorkspaceModel import com.intellij.platform.workspace.jps.entities.* +import com.intellij.platform.workspace.jps.serialization.impl.LibraryNameGenerator +import com.intellij.platform.workspace.storage.EntityChange +import com.intellij.platform.workspace.storage.VersionedStorageChange +import com.intellij.platform.workspace.storage.orderToRemoveReplaceAdd import com.intellij.util.EventDispatcher import com.intellij.util.containers.BidirectionalMultiMap import com.intellij.util.containers.MultiMap -import com.intellij.platform.backend.workspace.WorkspaceModel -import com.intellij.platform.workspace.jps.serialization.impl.LibraryNameGenerator import com.intellij.workspaceModel.ide.legacyBridge.ModifiableRootModelBridge import com.intellij.workspaceModel.ide.legacyBridge.ModuleDependencyIndex import com.intellij.workspaceModel.ide.legacyBridge.ModuleDependencyListener -import com.intellij.platform.workspace.storage.VersionedStorageChange -import com.intellij.platform.workspace.storage.orderToRemoveReplaceAdd import java.util.function.Supplier class ModuleDependencyIndexImpl(private val project: Project): ModuleDependencyIndex, Disposable { @@ -52,9 +53,11 @@ class ModuleDependencyIndexImpl(private val project: Project): ModuleDependencyI } override fun setupTrackedLibrariesAndJdks() { + ApplicationManager.getApplication().assertWriteAccessAllowed() + LOG.debug { "Add tracked global libraries and SDK for all modules" } val currentStorage = WorkspaceModel.getInstance(project).currentSnapshot for (moduleEntity in currentStorage.entities(ModuleEntity::class.java)) { - addTrackedLibraryAndJdkFromEntity(moduleEntity) + addTrackedLibrariesAndSdks(moduleEntity.dependencies, moduleEntity) } } @@ -80,16 +83,29 @@ class ModuleDependencyIndexImpl(private val project: Project): ModuleDependencyI // Roots changed event should be fired for the global libraries linked with module val moduleChanges = event.getChanges(ModuleEntity::class.java).orderToRemoveReplaceAdd() for (change in moduleChanges) { - change.oldEntity?.let { removeTrackedLibrariesAndJdkFromEntity(it) } - change.newEntity?.let { addTrackedLibraryAndJdkFromEntity(it) } + when (change) { + is EntityChange.Added -> { + LOG.debug { "Add tracked global libraries and SDK from ${change.entity.name}" } + addTrackedLibrariesAndSdks(change.entity.dependencies, change.entity) + } + is EntityChange.Removed -> { + LOG.debug { "Removed tracked global libraries and SDK from ${change.entity.name}" } + removeTrackedLibrariesAndSdks(change.entity.dependencies, change.entity) + } + is EntityChange.Replaced -> { + val removedDependencies = change.oldEntity.dependencies - change.newEntity.dependencies.toSet() + val addedDependencies = change.newEntity.dependencies - change.oldEntity.dependencies.toSet() + LOG.debug { "Update tracked global libraries and SDK for ${change.newEntity.name}: ${removedDependencies.size} removed, ${addedDependencies.size} added" } + removeTrackedLibrariesAndSdks(removedDependencies, change.oldEntity) + addTrackedLibrariesAndSdks(addedDependencies, change.newEntity) + } + } } } - private fun addTrackedLibraryAndJdkFromEntity(moduleEntity: ModuleEntity) { - ApplicationManager.getApplication().assertWriteAccessAllowed() - LOG.debug { "Add tracked global libraries and JDK from ${moduleEntity.name}" } + private fun addTrackedLibrariesAndSdks(dependencies: List, moduleEntity: ModuleEntity) { val libraryTablesRegistrar = LibraryTablesRegistrar.getInstance() - moduleEntity.dependencies.forEach { + dependencies.forEach { when { it is ModuleDependencyItem.Exportable.LibraryDependency && it.library.tableId !is LibraryTableId.ModuleLibraryTableId -> { val libraryName = it.library.name @@ -105,10 +121,9 @@ class ModuleDependencyIndexImpl(private val project: Project): ModuleDependencyI } } - private fun removeTrackedLibrariesAndJdkFromEntity(moduleEntity: ModuleEntity) { - LOG.debug { "Removed tracked global libraries and JDK from ${moduleEntity.name}" } + private fun removeTrackedLibrariesAndSdks(dependencies: List, moduleEntity: ModuleEntity) { val libraryTablesRegistrar = LibraryTablesRegistrar.getInstance() - moduleEntity.dependencies.forEach { + dependencies.forEach { when { it is ModuleDependencyItem.Exportable.LibraryDependency && it.library.tableId !is LibraryTableId.ModuleLibraryTableId -> { val libraryName = it.library.name From 5366dc5b81ec2f7b28890eaa03d5ad6ca0735432 Mon Sep 17 00:00:00 2001 From: Rustam Vishniakov Date: Wed, 28 Jun 2023 13:21:20 +0200 Subject: [PATCH 174/226] [formatter] ReformatCodeProcessor: drop allowSlowOperations() [IDEA-305604] GitOrigin-RevId: bc1e2a012ec749ba0405145a253eecb87d53615a --- .../actions/ReformatCodeProcessor.java | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java index bd315e1308e5..ab978a314c4a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java @@ -14,7 +14,6 @@ import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.SelectionModel; -import com.intellij.openapi.editor.ex.util.EditorScrollingPositionKeeper; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; @@ -28,7 +27,6 @@ import com.intellij.psi.codeStyle.ChangedRangesInfo; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.SlowOperations; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -182,25 +180,23 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor { KeptLineFeedsCollector.setup(fileToProcess); } try { - SlowOperations.allowSlowOperations(() -> { - if (document != null) { - // In languages that are supported by a non-commit typing assistant (such as C++ and Kotlin), - // the `document` here can be in an uncommitted state. In the case of an external formatter, - // this may be the cause of formatting artifacts - PsiDocumentManager.getInstance(myProject).commitDocument(document); + if (document != null) { + // In languages that are supported by a non-commit typing assistant (such as C++ and Kotlin), + // the `document` here can be in an uncommitted state. In the case of an external formatter, + // this may be the cause of formatting artifacts + PsiDocumentManager.getInstance(myProject).commitDocument(document); + } + if (processChangedTextOnly) { + ChangedRangesInfo info = VcsFacade.getInstance().getChangedRangesInfo(fileToProcess); + if (info != null) { + assertFileIsValid(fileToProcess); + CodeStyleManager.getInstance(myProject).reformatChanges(fileToProcess, info); } - if (processChangedTextOnly) { - ChangedRangesInfo info = VcsFacade.getInstance().getChangedRangesInfo(fileToProcess); - if (info != null) { - assertFileIsValid(fileToProcess); - CodeStyleManager.getInstance(myProject).reformatChanges(fileToProcess, info); - } - } - else { - Collection ranges = getRangesToFormat(fileToProcess); - CodeStyleManager.getInstance(myProject).reformatText(fileToProcess, ranges); - } - }); + } + else { + Collection ranges = getRangesToFormat(fileToProcess); + CodeStyleManager.getInstance(myProject).reformatText(fileToProcess, ranges); + } } catch (ProcessCanceledException pce) { if (before != null) { From fed7fcdb23a8fc3dfa2df689696b9f545a6d1fb1 Mon Sep 17 00:00:00 2001 From: Aydar Mukhametzyanov Date: Mon, 3 Jul 2023 10:56:43 +0200 Subject: [PATCH 175/226] IDEA-321897 IDEA-323777 IDEA-323784 Add clarifying comment GitOrigin-RevId: db8e7d1bb9bb788fa501b8ab4e96938d2c8ffb49 --- platform/util/ui/src/com/intellij/util/ui/JBInsets.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/util/ui/src/com/intellij/util/ui/JBInsets.java b/platform/util/ui/src/com/intellij/util/ui/JBInsets.java index 8e3182b79982..73dad6f29c3e 100644 --- a/platform/util/ui/src/com/intellij/util/ui/JBInsets.java +++ b/platform/util/ui/src/com/intellij/util/ui/JBInsets.java @@ -158,6 +158,7 @@ public class JBInsets extends Insets { @ApiStatus.Internal public static Insets unwrap(@NotNull Insets insets) { if (insets instanceof JBInsets jbInsets) { + // Check that scaled values consistent with unscaled ones JBInsets cleanInsets = create(jbInsets.getUnscaled()); if (insets.equals(cleanInsets)) return jbInsets.getUnscaled(); From d4e8ce91ff6eaf1d5fd805dd13d2ce30007f40bb Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Fri, 30 Jun 2023 14:14:49 -0700 Subject: [PATCH 176/226] FIR/UAST: attempt to retrieve extension receiver first ...so that we can pick the extension receiver for extension function! ^IDEA-307665 GitOrigin-RevId: 21e1a574e354d87a6eb14fa04e9acbad63006dd4 --- .../common/kotlin/UastApiFixtureTestBase.kt | 18 ++++++++++++++++++ .../FirKotlinUastResolveProviderService.kt | 2 +- .../internal/firKotlinInternalUastUtils.kt | 18 +++--------------- .../fir/uast/test/FirUastApiFixtureTest.kt | 4 ++++ .../kotlin/KotlinUastResolveProviderService.kt | 2 +- .../kotlin/comparison/FE1UastApiFixtureTest.kt | 4 ++++ 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/plugins/kotlin/uast/uast-kotlin-base/tests/test/org/jetbrains/uast/test/common/kotlin/UastApiFixtureTestBase.kt b/plugins/kotlin/uast/uast-kotlin-base/tests/test/org/jetbrains/uast/test/common/kotlin/UastApiFixtureTestBase.kt index 38b4b96d0f92..54c22cbab73b 100644 --- a/plugins/kotlin/uast/uast-kotlin-base/tests/test/org/jetbrains/uast/test/common/kotlin/UastApiFixtureTestBase.kt +++ b/plugins/kotlin/uast/uast-kotlin-base/tests/test/org/jetbrains/uast/test/common/kotlin/UastApiFixtureTestBase.kt @@ -689,4 +689,22 @@ interface UastApiFixtureTestBase : UastPluginSelection { val identifier = extensionReceiver.uastAnchor as? UIdentifier TestCase.assertNotNull(identifier) } + + fun checkReceiverTypeOfExtensionFunction(myFixture: JavaCodeInsightTestFixture) { + myFixture.configureByText( + "main.kt", """ + class Foo + class Bar { + fun Foo.ext() {} + + fun test(f: Foo) { + f.ext() + } + } + """.trimIndent() + ) + val uCallExpression = myFixture.file.findElementAt(myFixture.caretOffset).toUElement().getUCallExpression() + .orFail("cant convert to UCallExpression") + TestCase.assertEquals("Foo", uCallExpression.receiverType?.canonicalText) + } } \ No newline at end of file diff --git a/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt b/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt index 8634e2ea41f5..8bf998fa61c0 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt +++ b/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt @@ -267,7 +267,7 @@ interface FirKotlinUastResolveProviderService : BaseKotlinUastResolveProviderSer override fun isResolvedToExtension(ktCallElement: KtCallElement): Boolean { analyzeForUast(ktCallElement) { val ktCall = ktCallElement.resolveCall()?.singleFunctionCallOrNull() ?: return false - return isExtension(ktCall) + return ktCall.symbol.isExtension } } diff --git a/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/firKotlinInternalUastUtils.kt b/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/firKotlinInternalUastUtils.kt index bf353dbf479b..926bd478b336 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/firKotlinInternalUastUtils.kt +++ b/plugins/kotlin/uast/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/firKotlinInternalUastUtils.kt @@ -8,7 +8,6 @@ import com.intellij.psi.util.PsiTypesUtil import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.analyze import org.jetbrains.kotlin.analysis.api.calls.KtCallableMemberCall -import org.jetbrains.kotlin.analysis.api.calls.symbol import org.jetbrains.kotlin.analysis.api.components.buildClassType import org.jetbrains.kotlin.analysis.api.getModule import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeTokenFactory @@ -227,25 +226,14 @@ internal fun KtAnalysisSession.toPsiType( ) ?: UastErrorType } -internal fun KtAnalysisSession.isExtension( - ktCall: KtCallableMemberCall<*, *> -): Boolean { - return ktCall.symbol.isExtension -} - internal fun KtAnalysisSession.receiverType( ktCall: KtCallableMemberCall<*, *>, source: UElement, context: KtElement, ): PsiType? { - var ktType = ktCall.partiallyAppliedSymbol.signature.receiverType - if (ktType == null) { - ktType = - if (isExtension(ktCall)) - ktCall.partiallyAppliedSymbol.extensionReceiver?.type - else - ktCall.partiallyAppliedSymbol.dispatchReceiver?.type - } + val ktType = ktCall.partiallyAppliedSymbol.signature.receiverType + ?: ktCall.partiallyAppliedSymbol.extensionReceiver?.type + ?: ktCall.partiallyAppliedSymbol.dispatchReceiver?.type if (ktType == null || ktType is KtErrorType) return null return toPsiType( ktType, diff --git a/plugins/kotlin/uast/uast-kotlin-fir/tests/test/org/jetbrains/fir/uast/test/FirUastApiFixtureTest.kt b/plugins/kotlin/uast/uast-kotlin-fir/tests/test/org/jetbrains/fir/uast/test/FirUastApiFixtureTest.kt index e2951a10721e..76bf1c9f0cd8 100644 --- a/plugins/kotlin/uast/uast-kotlin-fir/tests/test/org/jetbrains/fir/uast/test/FirUastApiFixtureTest.kt +++ b/plugins/kotlin/uast/uast-kotlin-fir/tests/test/org/jetbrains/fir/uast/test/FirUastApiFixtureTest.kt @@ -84,4 +84,8 @@ class FirUastApiFixtureTest : KotlinLightCodeInsightFixtureTestCase(), UastApiFi fun testIdentifierOfNullableExtensionReceiver() { checkIdentifierOfNullableExtensionReceiver(myFixture) } + + fun testReceiverTypeOfExtensionFunction() { + checkReceiverTypeOfExtensionFunction(myFixture) + } } \ No newline at end of file diff --git a/plugins/kotlin/uast/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastResolveProviderService.kt b/plugins/kotlin/uast/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastResolveProviderService.kt index 21f924eae176..10ffd6ffbcd3 100644 --- a/plugins/kotlin/uast/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastResolveProviderService.kt +++ b/plugins/kotlin/uast/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastResolveProviderService.kt @@ -345,7 +345,7 @@ interface KotlinUastResolveProviderService : BaseKotlinUastResolveProviderServic override fun getReceiverType(ktCallElement: KtCallElement, source: UElement): PsiType? { val resolvedCall = ktCallElement.getResolvedCall(ktCallElement.analyze()) ?: return null - val receiver = resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver ?: return null + val receiver = resolvedCall.extensionReceiver ?: resolvedCall.dispatchReceiver ?: return null return receiver.type.toPsiType(source, ktCallElement, PsiTypeConversionConfiguration.create(ktCallElement, isBoxed = true)) } diff --git a/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/comparison/FE1UastApiFixtureTest.kt b/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/comparison/FE1UastApiFixtureTest.kt index c163202a5a3a..b55dc97eafdd 100644 --- a/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/comparison/FE1UastApiFixtureTest.kt +++ b/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/comparison/FE1UastApiFixtureTest.kt @@ -82,4 +82,8 @@ class FE1UastApiFixtureTest : KotlinLightCodeInsightFixtureTestCase(), UastApiFi fun testIdentifierOfNullableExtensionReceiver() { checkIdentifierOfNullableExtensionReceiver(myFixture) } + + fun testReceiverTypeOfExtensionFunction() { + checkReceiverTypeOfExtensionFunction(myFixture) + } } \ No newline at end of file From 88841bfe7e77724cfea79b6109cabdbdec2a9550 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Tue, 27 Jun 2023 18:22:55 +0200 Subject: [PATCH 177/226] PY-58168 SDK is null: Respect module while detecting test framework (cherry picked from commit d9fdace43e403e2190cf26f4a565578815407b86) IJ-MR-109792 GitOrigin-RevId: 74d7014d30cdddcdb5256d98ec2d0f387752c32d --- .../AbstractPythonTestRunConfiguration.kt | 2 +- .../PyAutoDetectTestConfiguration.kt | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.kt b/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.kt index 6624ab5be30b..99645f29ffd5 100644 --- a/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.kt +++ b/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.kt @@ -90,7 +90,7 @@ protected constructor(project: Project, factory: ConfigurationFactory, private v val sdk = sdk if (sdk == null) { // No SDK -- no tests - logger>().warn("SDK is null") + logger>().warn("Failed to detect test framework: SDK is null") return false } val requiredPackage = this.requiredPackage ?: return true // Installed by default diff --git a/python/src/com/jetbrains/python/testing/autoDetectTests/PyAutoDetectTestConfiguration.kt b/python/src/com/jetbrains/python/testing/autoDetectTests/PyAutoDetectTestConfiguration.kt index 494c9e994af8..19eee7b4dba2 100644 --- a/python/src/com/jetbrains/python/testing/autoDetectTests/PyAutoDetectTestConfiguration.kt +++ b/python/src/com/jetbrains/python/testing/autoDetectTests/PyAutoDetectTestConfiguration.kt @@ -4,6 +4,7 @@ package com.jetbrains.python.testing.autoDetectTests import com.intellij.execution.Executor import com.intellij.execution.configurations.RunProfileState import com.intellij.execution.runners.ExecutionEnvironment +import com.intellij.openapi.module.Module import com.intellij.openapi.options.SettingsEditor import com.intellij.openapi.project.Project import com.intellij.util.xmlb.BeanBinding @@ -19,7 +20,14 @@ class PyAutoDetectTestConfiguration(project: Project, factory: PyAutoDetectionCo override val useFrameworkNameInConfiguration: Boolean = false override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? { - val conf = detectedConfiguration() ?: return null + val runProfile = environment.runProfile + val module = if (runProfile is PyAbstractTestConfiguration) { + runProfile.module + } + else { + null + } + val conf = detectedConfiguration(module) ?: return null copyTo(getProperties(conf)) for (accessor in BeanBinding.getAccessors(PyAbstractTestConfiguration::class.java)) { @@ -32,10 +40,12 @@ class PyAutoDetectTestConfiguration(project: Project, factory: PyAutoDetectionCo return conf.getState(executor, environment) } - fun detectedConfiguration(): PyAbstractTestConfiguration? { + fun detectedConfiguration(module: Module?): PyAbstractTestConfiguration? { return PyAutoDetectionConfigurationFactory.factoriesExcludingThis .asSequence().map { - it.createTemplateConfiguration(project) + val tempConfig = it.createTemplateConfiguration(project) + tempConfig.module = module + tempConfig }.filter { it.isFrameworkInstalled() }.firstOrNull() From 95e05ebbaf84e22aa7284c6dacb1e83c028029a0 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Mon, 3 Jul 2023 11:03:03 +0200 Subject: [PATCH 178/226] PY-58168 Fixes after review IJ-MR-109792 (cherry picked from commit c28da009f8939ad42966c269f0435f950fb4250c) IJ-MR-109792 GitOrigin-RevId: 6104eca12124caccc3a1b75372f10b1f0a49fd39 --- .../PyAutoDetectTestConfiguration.kt | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/python/src/com/jetbrains/python/testing/autoDetectTests/PyAutoDetectTestConfiguration.kt b/python/src/com/jetbrains/python/testing/autoDetectTests/PyAutoDetectTestConfiguration.kt index 19eee7b4dba2..8db61ef10b17 100644 --- a/python/src/com/jetbrains/python/testing/autoDetectTests/PyAutoDetectTestConfiguration.kt +++ b/python/src/com/jetbrains/python/testing/autoDetectTests/PyAutoDetectTestConfiguration.kt @@ -21,12 +21,7 @@ class PyAutoDetectTestConfiguration(project: Project, factory: PyAutoDetectionCo override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? { val runProfile = environment.runProfile - val module = if (runProfile is PyAbstractTestConfiguration) { - runProfile.module - } - else { - null - } + val module = (runProfile as? PyAbstractTestConfiguration)?.module val conf = detectedConfiguration(module) ?: return null copyTo(getProperties(conf)) @@ -43,9 +38,9 @@ class PyAutoDetectTestConfiguration(project: Project, factory: PyAutoDetectionCo fun detectedConfiguration(module: Module?): PyAbstractTestConfiguration? { return PyAutoDetectionConfigurationFactory.factoriesExcludingThis .asSequence().map { - val tempConfig = it.createTemplateConfiguration(project) - tempConfig.module = module - tempConfig + it.createTemplateConfiguration(project).apply { + this.module = module + } }.filter { it.isFrameworkInstalled() }.firstOrNull() From 5136615d94849029de08b88d14062b71047ee76d Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 3 Jul 2023 11:46:27 +0200 Subject: [PATCH 179/226] attempt #2 to fix IDEA-321907 (right now we set new UI automatically for isNewUser() == true || bundled plugin state does not exist) GitOrigin-RevId: a9988777fe1fbc496bab20ccf7b6eb82b6888f22 --- .../src/com/intellij/idea/StartupUtil.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt b/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt index dcd37cb4c363..d396ca90c46b 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.kt @@ -214,12 +214,15 @@ fun CoroutineScope.startApplication(args: List, appStarter = appStarterDeferred.await(), euaDocumentDeferred = euaDocumentDeferred, ) + } - if (ConfigImportHelper.isNewUser() && System.getProperty(NewUiValue.KEY) == null) { - runCatching { - EarlyAccessRegistryManager.setAndFlush(mapOf(NewUiValue.KEY to true.toString())) - }.getOrLogException(log) - } + if ((ConfigImportHelper.isNewUser() || + // config directory may exist even if user is a new. + !(BundledPluginsState.checkStateExistedAtTheStart() || ApplicationManagerEx.isInIntegrationTest())) + && System.getProperty(NewUiValue.KEY) == null) { + runCatching { + EarlyAccessRegistryManager.setAndFlush(mapOf(NewUiValue.KEY to true.toString())) + }.getOrLogException(logDeferred.await()) } PluginManagerCore.scheduleDescriptorLoading(asyncScope, zipFilePoolDeferred) @@ -343,7 +346,6 @@ fun isConfigImportNeeded(configPath: Path): Boolean { return !Files.exists(configPath) || Files.exists(configPath.resolve(ConfigImportHelper.CUSTOM_MARKER_FILE_NAME)) || customTargetDirectoryToImportConfig != null - || !(BundledPluginsState.checkStateExistedAtTheStart() || ApplicationManagerEx.isInIntegrationTest()) } /** From c9468002a855d6ae91bc59304912e4202a03ac70 Mon Sep 17 00:00:00 2001 From: "Kirill.Krylov" Date: Sat, 1 Jul 2023 14:19:57 +0200 Subject: [PATCH 180/226] [full-line] implement new version of inline completion GitOrigin-RevId: b21856066c6a0b692ea3e305c3e4185056fcbef4 --- .../InlineCompletionLookupManagerListener.kt | 29 +++++ .../codeInsight/inline/completion/Actions.kt | 51 +++----- .../DebouncedInlineCompletionProvider.kt | 51 ++++++++ .../completion/InlineCompletionContext.kt | 10 +- .../InlineCompletionEditorListener.kt | 117 ------------------ .../completion/InlineCompletionElements.kt | 97 +++++++++++++-- .../completion/InlineCompletionHandler.kt | 78 +++++++++--- .../completion/InlineCompletionProvider.kt | 31 +++-- .../InlineCompletionEditorListener.kt | 46 +++++++ .../listeners/InlineCompletionListeners.kt | 89 +++++++++++++ .../src/META-INF/LangExtensions.xml | 4 +- .../src/idea/LangActions.xml | 4 +- .../util/resources/misc/registry.properties | 3 - 13 files changed, 413 insertions(+), 197 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionLookupManagerListener.kt create mode 100644 platform/platform-impl/src/com/intellij/codeInsight/inline/completion/DebouncedInlineCompletionProvider.kt delete mode 100644 platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionEditorListener.kt create mode 100644 platform/platform-impl/src/com/intellij/codeInsight/inline/completion/listeners/InlineCompletionEditorListener.kt create mode 100644 platform/platform-impl/src/com/intellij/codeInsight/inline/completion/listeners/InlineCompletionListeners.kt diff --git a/platform/lang-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionLookupManagerListener.kt b/platform/lang-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionLookupManagerListener.kt new file mode 100644 index 000000000000..50bdb1d7f267 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionLookupManagerListener.kt @@ -0,0 +1,29 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInsight.inline.completion + +import com.intellij.codeInsight.lookup.Lookup +import com.intellij.codeInsight.lookup.LookupEvent +import com.intellij.codeInsight.lookup.LookupListener +import com.intellij.codeInsight.lookup.LookupManagerListener + +class InlineCompletionLookupManagerListener : LookupManagerListener { + override fun activeLookupChanged(oldLookup: Lookup?, newLookup: Lookup?) { + newLookup?.addLookupListener(object : LookupListener { + override fun currentItemChanged(event: LookupEvent) { + if (!event.lookup.isFocused || event.item == null) { + return + } + val listener = event.lookup.editor.getUserData(InlineCompletionHandler.KEY) ?: return + listener.invoke(event) + } + + override fun lookupCanceled(event: LookupEvent) { + // TODO: Try to continue inline completion + } + + override fun lookupShown(event: LookupEvent) { + // TODO: Strip current inline completion text to one-line + } + }) + } +} diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/Actions.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/Actions.kt index f57b281ab64f..553493374e43 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/Actions.kt +++ b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/Actions.kt @@ -4,50 +4,14 @@ package com.intellij.codeInsight.inline.completion import com.intellij.codeInsight.hint.HintManagerImpl import com.intellij.codeInsight.inline.completion.InlineCompletionContext.Companion.getInlineCompletionContextOrNull import com.intellij.codeInsight.inline.completion.InlineCompletionContext.Companion.resetInlineCompletionContext +import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.actionSystem.EditorAction import com.intellij.openapi.editor.actionSystem.EditorActionHandler import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler -import com.intellij.openapi.editor.event.CaretEvent -import com.intellij.openapi.editor.event.CaretListener -import com.intellij.openapi.editor.ex.FocusChangeListener import org.jetbrains.annotations.ApiStatus -import java.awt.event.KeyAdapter -import java.awt.event.KeyEvent - -@ApiStatus.Experimental -class InlineCompletionCaretListener : CaretListener { - override fun caretPositionChanged(event: CaretEvent) { - event.editor.resetInlineCompletionContext() - } -} - -@ApiStatus.Experimental -class InlineCompletionFocusListener : FocusChangeListener { - override fun focusGained(editor: Editor) {} - override fun focusLost(editor: Editor) { - editor.resetInlineCompletionContext() - } -} - -@ApiStatus.Experimental -class InlineCompletionKeyListener(private val editor: Editor) : KeyAdapter() { - private val usedKeys = listOf( - KeyEvent.VK_ALT, - KeyEvent.VK_OPEN_BRACKET, - KeyEvent.VK_CLOSE_BRACKET, - KeyEvent.VK_TAB, - ) - - override fun keyReleased(event: KeyEvent) { - if (usedKeys.contains(event.keyCode)) { - return - } - editor.resetInlineCompletionContext() - } -} @ApiStatus.Experimental class InsertInlineCompletionAction : EditorAction(InsertInlineCompletionHandler()), HintManagerImpl.ActionToIgnore { @@ -80,3 +44,16 @@ class EscapeInlineCompletionHandler(val originalHandler: EditorActionHandler) : return originalHandler.isEnabled(editor, caret, dataContext) } } + +@ApiStatus.Experimental +class CallInlineCompletionAction : EditorAction(CallInlineCompletionHandler()), HintManagerImpl.ActionToIgnore { + class CallInlineCompletionHandler : EditorWriteActionHandler() { + override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) { + if (caret == null) return + val listener = editor.getUserData(InlineCompletionHandler.KEY) ?: return + val file = dataContext?.getData(CommonDataKeys.PSI_FILE) ?: return + + listener.invoke(editor, file, caret) + } + } +} diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/DebouncedInlineCompletionProvider.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/DebouncedInlineCompletionProvider.kt new file mode 100644 index 000000000000..d8b33b3d3307 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/DebouncedInlineCompletionProvider.kt @@ -0,0 +1,51 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInsight.inline.completion + +import com.intellij.openapi.application.ApplicationManager +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.job +import org.jetbrains.annotations.ApiStatus +import kotlin.coroutines.coroutineContext +import kotlin.time.Duration + +@ApiStatus.Experimental +abstract class DebouncedInlineCompletionProvider : InlineCompletionProvider { + private var jobCall: Job? = null + abstract val delay: Duration + + /** + * Returns a Flow of InlineCompletionElement objects with debounced proposals for the given InlineCompletionRequest. + * Override [delay] to control debounce delay + */ + abstract suspend fun getProposalsDebounced(request: InlineCompletionRequest): Flow + + /** + * Forces the inline completion for the given request. + * Might be useful for direct call, since it does not requires any delays + * + * @return `true` if the inline completion need to be forced, `false` otherwise. + */ + abstract fun force(request: InlineCompletionRequest): Boolean + + override suspend fun getProposals(request: InlineCompletionRequest): Flow { + if (ApplicationManager.getApplication().isUnitTestMode) { + return getProposalsDebounced(request) + } + + if (force(request)) { + jobCall?.cancel() + getProposalsDebounced(request) + } + + return debounce(request) + } + + private suspend fun debounce(request: InlineCompletionRequest): Flow { + jobCall?.cancel() + jobCall = coroutineContext.job + delay(delay) + return getProposalsDebounced(request) + } +} diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionContext.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionContext.kt index 05060d1df4b6..2e6a1fef8c8d 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionContext.kt +++ b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionContext.kt @@ -2,9 +2,9 @@ package com.intellij.codeInsight.inline.completion import com.intellij.codeInsight.inline.completion.InlineState.Companion.resetInlineCompletionState +import com.intellij.codeInsight.inline.completion.listeners.InlineCompletionKeyListener import com.intellij.openapi.Disposable import com.intellij.openapi.editor.Editor -import com.intellij.openapi.editor.ex.EditorEx import com.intellij.openapi.editor.impl.EditorImpl import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Key @@ -20,13 +20,6 @@ class InlineCompletionContext private constructor(val editor: Editor) : Disposab private var completions = emptyList() private var selectedIndex = -1 - init { - editor.caretModel.addCaretListener(InlineCompletionCaretListener()) - if (editor is EditorEx) { - editor.addFocusListener(InlineCompletionFocusListener()) - } - } - val isCurrentlyDisplayingInlays: Boolean get() = !inlay.isEmpty @@ -87,6 +80,7 @@ class InlineCompletionContext private constructor(val editor: Editor) : Disposab putUserData(INLINE_COMPLETION_CONTEXT, it) } } + fun Editor.getInlineCompletionContextOrNull(): InlineCompletionContext? = getUserData(INLINE_COMPLETION_CONTEXT) fun Editor.removeInlineCompletionContext(): Unit = putUserData(INLINE_COMPLETION_CONTEXT, null) fun Editor.resetInlineCompletionContext(): Unit? = getInlineCompletionContextOrNull()?.let { diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionEditorListener.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionEditorListener.kt deleted file mode 100644 index 57fe38bb69f4..000000000000 --- a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionEditorListener.kt +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.codeInsight.inline.completion - -import com.intellij.codeInsight.completion.CompletionUtil -import com.intellij.codeInsight.inline.completion.InlineCompletionContext.Companion.getInlineCompletionContextOrNull -import com.intellij.openapi.Disposable -import com.intellij.openapi.actionSystem.IdeActions -import com.intellij.openapi.actionSystem.ex.ActionUtil -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.editor.EditorKind -import com.intellij.openapi.editor.event.DocumentEvent -import com.intellij.openapi.editor.event.DocumentListener -import com.intellij.openapi.editor.event.EditorFactoryEvent -import com.intellij.openapi.editor.event.EditorFactoryListener -import com.intellij.openapi.editor.impl.EditorImpl -import com.intellij.openapi.project.DumbAwareAction -import com.intellij.openapi.util.Disposer -import com.intellij.openapi.util.Key -import com.intellij.openapi.util.registry.Registry -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.debounce -import org.jetbrains.annotations.ApiStatus - -/** - * Inline completion will be shown only if at least one [InlineCompletionProvider] is enabled and returns at least one proposal - */ -@ApiStatus.Experimental -class InlineCompletionEditorListener(private val scope: CoroutineScope) : EditorFactoryListener { - override fun editorCreated(event: EditorFactoryEvent) { - val editor = event.editor - if (editor.project == null || editor !is EditorImpl || editor.editorKind != EditorKind.MAIN_EDITOR) return - - InlineCompletionDocumentListener(editor, scope).listenForChanges() - } -} - -@Suppress("MemberVisibilityCanBePrivate") -@OptIn(FlowPreview::class) -@ApiStatus.Experimental -class InlineCompletionDocumentListener(private val editor: EditorImpl, private val scope: CoroutineScope) : DocumentListener, Disposable { - private val handler = InlineCompletionHandler(scope) - private var flow = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) - private var jobCall: Job? = null - - fun isEnabled(event: DocumentEvent): Boolean { - return event.newFragment != CompletionUtil.DUMMY_IDENTIFIER && event.newLength >= 1 - } - - private fun documentChangedDebounced(inlineCompletionEvent: InlineCompletionEvent) { - val (event, providers) = inlineCompletionEvent - if (event.document.isInBulkUpdate) return - - // As PoC inline completion does not support multiple providers - // TODO: handle multiple providers - handler.invoke(event, editor, providers.first()) - } - - fun listenForChanges() { - Disposer.register(editor.disposable, this) - editor.document.addDocumentListener(this, this) - editor.putUserData(KEY, this) - - //overrideCaretMove(editor) - - jobCall = scope.launch(CoroutineName("inline.completion.call")) { - flow.debounce(minDelay) - .collect(::documentChangedDebounced) - } - } - - override fun documentChanged(event: DocumentEvent) { - if (InlineCompletionHandler.isMuted.get() || !isEnabled(event)) { - return - } - - val providers = InlineCompletionProvider.extensions().filter { it.isEnabled(event) } - .takeIf { it.isNotEmpty() } ?: return - val inlineCompletionEvent = InlineCompletionEvent(event, providers) - - if (ApplicationManager.getApplication().isUnitTestMode) { - documentChangedDebounced(inlineCompletionEvent) - } - else { - flow.tryEmit(inlineCompletionEvent) - } - } - - private fun overrideCaretMove(editor: EditorImpl) { - //val moveCaretAction = ActionUtil.getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT) ?: return - // - //DumbAwareAction.create { - // val toAct = if (editor.getInlineCompletionContextOrNull()?.isCurrentlyDisplayingInlays == true) { - // InsertInlineCompletionAction() - // } - // else { - // moveCaretAction - // } - // - // ActionUtil.performActionDumbAwareWithCallbacks(toAct, it) - //}.registerCustomShortcutSet(moveCaretAction.shortcutSet, editor.component) - } - - override fun dispose() { - editor.putUserData(KEY, null) - jobCall?.cancel() - } - - private data class InlineCompletionEvent(val event: DocumentEvent, val providers: List) - - companion object { - private val KEY = Key.create("inline.completion.listener") - - val minDelay: Long = Registry.get("inline.completion.trigger.delay").asInteger().toLong() - } -} diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionElements.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionElements.kt index 7fdd2d21fa9d..4a891662eb35 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionElements.kt +++ b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionElements.kt @@ -1,33 +1,116 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.inline.completion +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupEvent import com.intellij.openapi.application.ReadAction +import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.event.DocumentEvent +import com.intellij.openapi.editor.event.EditorMouseEvent import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager import org.jetbrains.annotations.ApiStatus +private typealias EditorCaret = Caret + @ApiStatus.Experimental data class InlineCompletionRequest( + val event: InlineCompletionEvent, + val file: PsiFile, val editor: Editor, val document: Document, val startOffset: Int, val endOffset: Int, -) { + val lookupElement: LookupElement? = null, +) + +@ApiStatus.Experimental +data class InlineCompletionElement(val text: String) { + fun withText(text: String) = InlineCompletionElement(text) +} + +@ApiStatus.Experimental +sealed interface InlineCompletionEvent { + fun toRequest(): InlineCompletionRequest? + + /** + * A class representing a direct call in the code editor by [InsertInlineCompletionAction]. + */ + @ApiStatus.Experimental + class DirectCall(val editor: Editor, val file: PsiFile, val caret: EditorCaret) : InlineCompletionEvent { + override fun toRequest(): InlineCompletionRequest? { + return InlineCompletionRequest(this, file, editor, editor.document, caret.offset, caret.offset, null) + } + } + + /** + * Represents a non-dummy not empty document event call in the editor. + */ + @ApiStatus.Experimental + class Document(val event: DocumentEvent, val editor: Editor) : InlineCompletionEvent { + override fun toRequest(): InlineCompletionRequest? { + val virtualFile = editor.virtualFile ?: return null + val project = editor.project ?: return null + if (editor.caretModel.caretCount != 1) return null + + val file = ReadAction.compute { PsiManager.getInstance(project).findFile(virtualFile) } + + return InlineCompletionRequest(this, file, editor, event.document, event.offset, event.offset + event.newLength, null) + } + } + + + /** + * Represents a caret move event only in selected editor. + * + * Be careful with this one because it might duplicate document events. It worth to add check for "non-simple offset change" + * ``` + * if (event.oldPosition.line == event.newPosition.line && event.oldPosition.column + 1 == event.newPosition.column) { + * return + * } + * ``` + */ + @ApiStatus.Experimental + class Caret(val event: EditorMouseEvent) : InlineCompletionEvent { + override fun toRequest(): InlineCompletionRequest? { + val editor = event.editor + val virtualFile = editor.virtualFile ?: return null + val project = editor.project ?: return null + if (editor.caretModel.caretCount != 1) return null + + val file = ReadAction.compute { PsiManager.getInstance(project).findFile(virtualFile) } + + val offset = ReadAction.compute { editor.caretModel.offset } + + return InlineCompletionRequest(this, file, editor, editor.document, offset, offset, null) + } + } + + /** + * A class representing a lookup event. + * + * This class implements the [InlineCompletionEvent] interface and provides a method to convert the event to a request + * using the [toRequest] method. + * + * @param event The lookup event. + */ + @ApiStatus.Experimental + class Lookup(val event: LookupEvent) : InlineCompletionEvent { + override fun toRequest(): InlineCompletionRequest? { + val item = event.item ?: return null + val editor = event.lookup?.editor ?: return null + if (editor.caretModel.caretCount != 1) return null - companion object { - fun fromDocumentEvent(event: DocumentEvent, editor: Editor): InlineCompletionRequest? { val virtualFile = editor.virtualFile ?: return null val project = editor.project ?: return null val file = ReadAction.compute { PsiManager.getInstance(project).findFile(virtualFile) } - return InlineCompletionRequest(file, editor, event.document, event.offset, event.offset + event.newLength) + val offset = ReadAction.compute { editor.caretModel.offset } + + return InlineCompletionRequest(this, file, editor, editor.document, offset, offset, item) } } } - -@ApiStatus.Experimental -data class InlineCompletionElement(val text: String) diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionHandler.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionHandler.kt index 312c93af7c05..af46e39af74e 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionHandler.kt +++ b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionHandler.kt @@ -5,46 +5,78 @@ import com.intellij.codeInsight.CodeInsightActionHandler import com.intellij.codeInsight.inline.completion.InlineCompletionContext.Companion.initOrGetInlineCompletionContext import com.intellij.codeInsight.inline.completion.InlineState.Companion.getInlineCompletionState import com.intellij.codeInsight.inline.completion.InlineState.Companion.initOrGetInlineCompletionState +import com.intellij.codeInsight.lookup.LookupEvent +import com.intellij.codeInsight.lookup.LookupManager import com.intellij.openapi.application.EDT +import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.event.DocumentEvent +import com.intellij.openapi.editor.event.EditorMouseEvent import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key import com.intellij.psi.PsiFile -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collectIndexed +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.takeWhile import org.jetbrains.annotations.ApiStatus import java.util.concurrent.atomic.AtomicBoolean @ApiStatus.Experimental class InlineCompletionHandler(private val scope: CoroutineScope) : CodeInsightActionHandler { + private var runningJob: Job? = null + + private fun getProvider(event: InlineCompletionEvent): InlineCompletionProvider? { + return InlineCompletionProvider.extensions().filter { it.isEnabled(event) }.firstOrNull() + } + override fun invoke(project: Project, editor: Editor, file: PsiFile) { val inlineState = editor.getInlineCompletionState() ?: return showInlineSuggestion(editor, inlineState, editor.caretModel.offset) } - fun invoke(event: DocumentEvent, editor: Editor, provider: InlineCompletionProvider) { - val request = InlineCompletionRequest.fromDocumentEvent(event, editor) ?: return - invoke(request, provider) - } + fun invoke(event: DocumentEvent, editor: Editor) = invoke(InlineCompletionEvent.Document(event, editor)) + fun invoke(event: EditorMouseEvent) = invoke(InlineCompletionEvent.Caret(event)) + fun invoke(event: LookupEvent) = invoke(InlineCompletionEvent.Lookup(event)) + fun invoke(editor: Editor, file: PsiFile, caret: Caret) = invoke(InlineCompletionEvent.DirectCall(editor, file, caret)) - fun invoke(request: InlineCompletionRequest, provider: InlineCompletionProvider) { - scope.launch { + private fun invoke(event: InlineCompletionEvent) { + if (isMuted.get()) { + return + } + val request = event.toRequest() ?: return + val provider = getProvider(event) ?: return + + runningJob?.cancel() + runningJob = scope.launch { val modificationStamp = request.document.modificationStamp - val result = provider.getProposals(request) + val resultFlow = provider.getProposals(request) val editor = request.editor val offset = request.endOffset val inlineState = editor.initOrGetInlineCompletionState() - if (modificationStamp == request.document.modificationStamp) { - inlineState.suggestions = result - } withContext(Dispatchers.EDT) { - showInlineSuggestion(editor, inlineState, offset) + resultFlow.let { + // In case lookup is shown - request must be only single line, due to lookup render issues + if (LookupManager.getActiveLookup(request.editor) != null) { + it.takeFirstLine() + } + else { + it + } + }.collectIndexed { index, value -> + if (index == 0 && modificationStamp != request.document.modificationStamp) { + cancel() + return@collectIndexed + } + + inlineState.suggestions = listOf(InlineCompletionElement(value.text)) + showInlineSuggestion(editor, inlineState, offset) + } } } } @@ -70,7 +102,23 @@ class InlineCompletionHandler(private val scope: CoroutineScope) : CodeInsightAc inlineContext.lastModificationStamp = editor.document.modificationStamp } + @OptIn(ExperimentalCoroutinesApi::class) + private fun Flow.takeFirstLine(): Flow { + var found = false + return takeWhile { + val value = it.text + !found.also { + if (value.contains("\n")) found = true + } + }.mapLatest { + it.withText(it.text.takeWhile { c -> c != '\n' }) + } + } + + companion object { + val KEY = Key.create("inline.completion.handler") + val isMuted: AtomicBoolean = AtomicBoolean(false) fun mute(): Unit = isMuted.set(true) fun unmute(): Unit = isMuted.set(false) diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionProvider.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionProvider.kt index 62b4de3c77f1..ab16e64e73b4 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionProvider.kt +++ b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/InlineCompletionProvider.kt @@ -1,20 +1,36 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.inline.completion -import com.intellij.openapi.editor.event.DocumentEvent import com.intellij.openapi.extensions.ExtensionPointName +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.emptyFlow import org.jetbrains.annotations.ApiStatus /** * Proposals provider for inline completion. - * Implement [getProposals] method to return a list of proposals and [isEnabled] to control if a provider need to be called. - * Inline completion has a user type delay. By default, it's 300ms. You can change it by modifying `inline.completion.listener` registry value (@see [InlineCompletionDocumentListener]) + * + * The [getProposals] method should return a [Flow] of [InlineCompletionElement] objects representing the proposals for completion. + * The [isEnabled] method should be implemented to control whether the provider should be called for a particular [InlineCompletionEvent]. + * + * #### Things to note: + * - Currently delay ([Flow.debounce]) for [InlineCompletionEvent.Document] is disabled and might be implemented later. + * You may implement it on provider side or use [DebouncedInlineCompletionProvider] as a entrypoint, + * otherwise, proposals will be generated/canceled on each typing. + * - Any inline completion request will be cancelled if inline is in rendering mode + * - In case a newer inline completion proposals are generated, previous call will be cancelled and hidden + * + * @see InlineCompletionElement + * @see InlineCompletionRequest + * @see InlineCompletionEvent + * + * @since experimental API */ @ApiStatus.Experimental interface InlineCompletionProvider { - suspend fun getProposals(request: InlineCompletionRequest): List + suspend fun getProposals(request: InlineCompletionRequest): Flow - fun isEnabled(event: DocumentEvent): Boolean + fun isEnabled(event: InlineCompletionEvent): Boolean companion object { private val EP_NAME = ExtensionPointName.create("com.intellij.inline.completion.provider") @@ -22,7 +38,8 @@ interface InlineCompletionProvider { } object DUMMY : InlineCompletionProvider { - override suspend fun getProposals(request: InlineCompletionRequest): List = emptyList() - override fun isEnabled(event: DocumentEvent): Boolean = true + override suspend fun getProposals(request: InlineCompletionRequest): Flow = emptyFlow() + override fun isEnabled(event: InlineCompletionEvent): Boolean = false } } + diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/listeners/InlineCompletionEditorListener.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/listeners/InlineCompletionEditorListener.kt new file mode 100644 index 000000000000..bf284bfef55e --- /dev/null +++ b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/listeners/InlineCompletionEditorListener.kt @@ -0,0 +1,46 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInsight.inline.completion.listeners + +import com.intellij.codeInsight.inline.completion.InlineCompletionHandler +import com.intellij.codeInsight.inline.completion.InlineCompletionProvider +import com.intellij.openapi.editor.EditorKind +import com.intellij.openapi.editor.event.EditorFactoryEvent +import com.intellij.openapi.editor.event.EditorFactoryListener +import com.intellij.openapi.editor.ex.util.EditorUtil +import com.intellij.openapi.editor.impl.EditorImpl +import com.intellij.openapi.util.Disposer +import kotlinx.coroutines.CoroutineScope +import org.jetbrains.annotations.ApiStatus + +/** + * Inline completion will be shown only if at least one [InlineCompletionProvider] is enabled and returns at least one proposal + */ +@ApiStatus.Experimental +class InlineCompletionEditorListener(scope: CoroutineScope) : EditorFactoryListener { + val caretListener = InlineCompletionCaretListener() + val focusListener = InlineCompletionFocusListener() + + val handler = InlineCompletionHandler(scope) + + override fun editorCreated(event: EditorFactoryEvent) { + val editor = event.editor + if (editor.project == null || editor !is EditorImpl || editor.editorKind != EditorKind.MAIN_EDITOR || editor.project?.isDisposed != false) return + + val disposable = Disposer.newDisposable("inline-completion").also { + EditorUtil.disposeWithEditor(editor, it) + } + + editor.putUserData(InlineCompletionHandler.KEY, handler) + val docListener = InlineCompletionDocumentListener(editor) + + editor.document.addDocumentListener(docListener, disposable) + editor.addEditorMouseListener(caretListener, disposable) + editor.addFocusListener(focusListener, disposable) + } + + override fun editorReleased(event: EditorFactoryEvent) { + event.editor.putUserData(InlineCompletionHandler.KEY, null) + } +} + + diff --git a/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/listeners/InlineCompletionListeners.kt b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/listeners/InlineCompletionListeners.kt new file mode 100644 index 000000000000..ba42783405ad --- /dev/null +++ b/platform/platform-impl/src/com/intellij/codeInsight/inline/completion/listeners/InlineCompletionListeners.kt @@ -0,0 +1,89 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInsight.inline.completion.listeners + +import com.intellij.codeInsight.completion.CompletionUtil +import com.intellij.codeInsight.inline.completion.InlineCompletionContext.Companion.resetInlineCompletionContext +import com.intellij.codeInsight.inline.completion.InlineCompletionHandler +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.event.DocumentEvent +import com.intellij.openapi.editor.event.DocumentListener +import com.intellij.openapi.editor.event.EditorMouseEvent +import com.intellij.openapi.editor.event.EditorMouseListener +import com.intellij.openapi.editor.ex.FocusChangeListener +import com.intellij.openapi.editor.impl.EditorImpl +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.TextEditor +import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl +import org.jetbrains.annotations.ApiStatus +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent + +@ApiStatus.Experimental +class InlineCompletionDocumentListener(private val editor: EditorImpl) : DocumentListener { + override fun documentChanged(event: DocumentEvent) { + if (!isEnabled(event) || event.document.isInBulkUpdate) { + return + } + + if (event.document.isInBulkUpdate) return + editor.getUserData(InlineCompletionHandler.KEY)?.invoke(event, editor) + } + + fun isEnabled(event: DocumentEvent): Boolean { + return event.newFragment != CompletionUtil.DUMMY_IDENTIFIER && event.newLength >= 1 + } +} + +@ApiStatus.Experimental +class InlineCompletionCaretListener : EditorMouseListener { + override fun mouseClicked(event: EditorMouseEvent) { + super.mouseClicked(event) + + // Check that edit is selected and opened + if (!event.editor.isSelected()) { + return + } + event.editor.resetInlineCompletionContext() + event.editor.getUserData(InlineCompletionHandler.KEY)?.invoke(event) + } + + private fun Editor.isSelected(): Boolean { + val project = this.project ?: return false + if (project.isDisposed()) { + return false + } + val editorManager = FileEditorManager.getInstance(project) ?: return false + + if (editorManager is FileEditorManagerImpl) { + val current = editorManager.getSelectedTextEditor(true) + return current != null && current == this + } + + val current = editorManager.getSelectedEditor() + return current is TextEditor && this == current.getEditor() + } +} + +@ApiStatus.Experimental +class InlineCompletionKeyListener(private val editor: Editor) : KeyAdapter() { + private val usedKeys = listOf( + KeyEvent.VK_ALT, + KeyEvent.VK_OPEN_BRACKET, + KeyEvent.VK_CLOSE_BRACKET, + KeyEvent.VK_TAB, + ) + + override fun keyReleased(event: KeyEvent) { + if (usedKeys.contains(event.keyCode)) { + return + } + editor.resetInlineCompletionContext() + } +} + +@ApiStatus.Experimental +class InlineCompletionFocusListener : FocusChangeListener { + override fun focusLost(editor: Editor) { + editor.resetInlineCompletionContext() + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 566d7d414680..1032fe0370bf 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -1556,7 +1556,7 @@ id="inline.completion.escape" action="EditorEscape" implementationClass="com.intellij.codeInsight.inline.completion.EscapeInlineCompletionHandler" order="before hide-hints"/> - + @@ -1746,6 +1746,8 @@ topic="com.intellij.ide.SaveAndSyncHandlerListener"/> + diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 01460ee9ec9a..ad35cbaab027 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -1747,11 +1747,11 @@ + + - - diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index b36da5a35549..e61821372f84 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -1057,9 +1057,6 @@ completion.show.intention.icon=true always.show.intention.above.current.line=false always.show.intention.above.current.line.description=Avoid showing intention popup on line where caret stays (e.g. show it above current line) -inline.completion.trigger.delay=300 -inline.completion.trigger.delay.description==Delay in milliseconds before triggering gray text pipeline - python.django.timeout=30 python.django.timeout.description=Number of seconds to wait for manage.py list commands introduce.variable.prefer.statements=false From 3acc6e0714d0a4660c397bb0c3ef705c3d58b5fe Mon Sep 17 00:00:00 2001 From: "Kirill.Krylov" Date: Mon, 3 Jul 2023 11:37:54 +0200 Subject: [PATCH 181/226] [full-line] temporary remove action shortcut due to conflicts GitOrigin-RevId: c95a2eb42c966642b952e0947faec10d4d87d31d --- .../platform-resources-en/src/messages/ActionsBundle.properties | 2 ++ platform/platform-resources/src/idea/LangActions.xml | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 8084b0e00d52..2ebd52eee5c0 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -856,6 +856,8 @@ action.Inline.text=I_nline... action.Inline.description=Inline the selected method or variable action.InsertInlineCompletionAction.text=Insert inline proposal action.InsertInlineCompletionAction.description=Insert current inline completion proposal +action.CallInlineCompletionAction.text=Call inline completion +action.CallInlineCompletionAction.description=Generate suggestion for current cursor position and show as inline action.AnonymousToInner.text=Convert Anon_ymous to Inner... action.AnonymousToInner.description=Convert anonymous class into an inner class action.EncapsulateFields.text=_Encapsulate Fields... diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index ad35cbaab027..ef650b4fe379 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -1747,7 +1747,6 @@ - From ad57d5d8a514cf75e2f7ba9e2d85490fd0fbcb03 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Mon, 3 Jul 2023 11:50:44 +0200 Subject: [PATCH 182/226] [tests] refactoring: rename CopyReferenceActionFilesTest.groovy to CopyReferenceActionFilesTest.kt This is needed to make it simpler to add a new test for IDEA-316752. GitOrigin-RevId: ae566554a6e80422a631722ac9bf5f9dc268a6ec --- ...enceActionFilesTest.groovy => CopyReferenceActionFilesTest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename java/java-tests/testSrc/com/intellij/java/codeInsight/{CopyReferenceActionFilesTest.groovy => CopyReferenceActionFilesTest.kt} (100%) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt similarity index 100% rename from java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.groovy rename to java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt From 215ce8fb6094c15a433c0196c515ce4883ab9c70 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Mon, 3 Jul 2023 11:55:53 +0200 Subject: [PATCH 183/226] [tests] refactoring: convert CopyReferenceActionFilesTest to Kotlin This is needed to make it simpler to add a new test for IDEA-316752. GitOrigin-RevId: ecb858633dcfd57e9e74f9bdf658a194b69e3980 --- .../CopyReferenceActionFilesTest.kt | 139 ++++++++---------- 1 file changed, 62 insertions(+), 77 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt index 4fb406199191..86ec6ba07c40 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt @@ -21,135 +21,120 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.module.JavaModuleType import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.psi.PsiManager import com.intellij.testFramework.PsiTestUtil -import groovy.transform.CompileStatic +import junit.framework.TestCase -@CompileStatic -class CopyReferenceActionFilesTest extends JavaCodeInsightTestCase { - VirtualFile additionalRoot - - @Override - protected void setUp() throws Exception { +internal class CopyReferenceActionFilesTest : JavaCodeInsightTestCase() { + lateinit var additionalRoot: VirtualFile + @Throws(Exception::class) + override fun setUp() { super.setUp() - getModule().setModuleType(JavaModuleType.getModuleType().getId()) - ApplicationManager.application.runWriteAction(new Runnable() { - @Override - void run() { - additionalRoot = VirtualFileManager.getInstance().findFileByUrl("temp:///").createChildDirectory(this, "newRoot") + module.setModuleType(JavaModuleType.getModuleType().id) + ApplicationManager.getApplication().runWriteAction(object : Runnable { + override fun run() { + additionalRoot = VirtualFileManager.getInstance().findFileByUrl("temp:///")!!.createChildDirectory(this, "newRoot") } }) } - @Override - protected void tearDown() throws Exception { + @Throws(Exception::class) + override fun tearDown() { try { - ApplicationManager.application.runWriteAction(new Runnable() { - @Override - void run() { - additionalRoot.delete(this) - } - }) + ApplicationManager.getApplication().runWriteAction( + Runnable { additionalRoot.delete(this) }) } finally { super.tearDown() } } - void testCopyFile_RegisteredAsSourceRoots_ShouldContainItsName() throws Exception { + @Throws(Exception::class) + fun testCopyFile_RegisteredAsSourceRoots_ShouldContainItsName() { // CPP-4315 "Edit | Copy Reference" result doesn't contain the file name - - VirtualFile dir - VirtualFile dir_subfile - VirtualFile file - - ApplicationManager.application.runWriteAction(new Runnable() { - @Override - void run() { + lateinit var dir: VirtualFile + lateinit var dir_subfile: VirtualFile + lateinit var file: VirtualFile + ApplicationManager.getApplication().runWriteAction(object : Runnable { + override fun run() { dir = additionalRoot.createChildDirectory(this, "dir") dir_subfile = dir.createChildData(this, "dir_subfile.txt") file = additionalRoot.createChildData(this, "file.txt") - PsiTestUtil.addContentRoot(getModule(), additionalRoot) PsiTestUtil.addSourceRoot(getModule(), dir) PsiTestUtil.addSourceRoot(getModule(), file) } }) - - assertEquals("dir", CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findDirectory(dir))) - assertEquals("dir_subfile.txt", CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findFile(dir_subfile))) - assertEquals("file.txt", CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findFile(file))) + TestCase.assertEquals("dir", CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir))) + TestCase.assertEquals("dir_subfile.txt", + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(dir_subfile))) + TestCase.assertEquals("file.txt", CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(file))) } - void testCopyFile_RegisteredAsContentRoot_ShouldContainItsFullPath() throws Exception { + @Throws(Exception::class) + fun testCopyFile_RegisteredAsContentRoot_ShouldContainItsFullPath() { // IDEA-144300 Copy Reference for source folder/content root copies empty string - - VirtualFile dir - VirtualFile dir_subfile - VirtualFile file - - ApplicationManager.application.runWriteAction(new Runnable() { - @Override - void run() { + lateinit var dir: VirtualFile + lateinit var dir_subfile: VirtualFile + lateinit var file: VirtualFile + ApplicationManager.getApplication().runWriteAction(object : Runnable { + override fun run() { dir = additionalRoot.createChildDirectory(this, "dir") dir_subfile = dir.createChildData(this, "dir_subfile.txt") file = additionalRoot.createChildData(this, "file.txt") - PsiTestUtil.addContentRoot(getModule(), dir) PsiTestUtil.addContentRoot(getModule(), file) } }) - - assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findDirectory(dir))) - assertEquals("dir_subfile.txt", CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findFile(dir_subfile))) - assertEquals(file.getPath(), CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findFile(file))) + TestCase.assertEquals(dir.getPath(), + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir))) + TestCase.assertEquals("dir_subfile.txt", + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(dir_subfile))) + TestCase.assertEquals(file.getPath(), CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(file))) } - void testCopyFile_RegisteredAsNestedContentRoot_ShouldContainPathFromOuterMostRoot() throws Exception { + @Throws(Exception::class) + fun testCopyFile_RegisteredAsNestedContentRoot_ShouldContainPathFromOuterMostRoot() { // IDEA-144300 Copy Reference for source folder/content root copies empty string - - VirtualFile dir - VirtualFile dir_dir - VirtualFile dir_dir_file - - ApplicationManager.application.runWriteAction(new Runnable() { - @Override - void run() { + lateinit var dir: VirtualFile + lateinit var dir_dir: VirtualFile + lateinit var dir_dir_file: VirtualFile + ApplicationManager.getApplication().runWriteAction(object : Runnable { + override fun run() { dir = additionalRoot.createChildDirectory(this, "dir") dir_dir = dir.createChildDirectory(this, "dir_dir") dir_dir_file = dir_dir.createChildData(this, "file.txt") - PsiTestUtil.addContentRoot(getModule(), dir) PsiTestUtil.addContentRoot(getModule(), dir_dir) } }) - - assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findDirectory(dir))) - assertEquals("dir_dir", CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findDirectory(dir_dir))) - assertEquals("dir_dir/file.txt", CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findFile(dir_dir_file))) + TestCase.assertEquals(dir.getPath(), + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir))) + TestCase.assertEquals("dir_dir", + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir_dir))) + TestCase.assertEquals("dir_dir/file.txt", + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(dir_dir_file))) } - void testCopyFile_UnderExcludeRoot_ShouldContainPathFromTheCorrespondingContentRoot() throws Exception { + @Throws(Exception::class) + fun testCopyFile_UnderExcludeRoot_ShouldContainPathFromTheCorrespondingContentRoot() { // IDEA-144316 Copy Reference should work for excluded subfolders same way as it works for regular project subdirs - - VirtualFile dir - VirtualFile dir_dir - VirtualFile dir_dir_file - - ApplicationManager.application.runWriteAction(new Runnable() { - @Override - void run() { + lateinit var dir: VirtualFile + lateinit var dir_dir: VirtualFile + lateinit var dir_dir_file: VirtualFile + ApplicationManager.getApplication().runWriteAction(object : Runnable { + override fun run() { dir = additionalRoot.createChildDirectory(this, "dir") dir_dir = dir.createChildDirectory(this, "dir_dir") dir_dir_file = dir_dir.createChildData(this, "file.txt") - PsiTestUtil.addContentRoot(getModule(), dir) PsiTestUtil.addExcludedRoot(getModule(), dir_dir) } }) - - assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findDirectory(dir))) - assertEquals("dir_dir", CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findDirectory(dir_dir))) - assertEquals("dir_dir/file.txt", CopyReferenceAction.elementToFqn(PsiManager.getInstance(project).findFile(dir_dir_file))) + TestCase.assertEquals(dir.getPath(), + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir))) + TestCase.assertEquals("dir_dir", + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir_dir))) + TestCase.assertEquals("dir_dir/file.txt", + CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(dir_dir_file))) } } From bdcbeb026eeeba880a1c5eec24580602b8549508 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Mon, 3 Jul 2023 12:11:20 +0200 Subject: [PATCH 184/226] [tests] refactoring: convert CopyReferenceActionFilesTest to JUnit5 This is needed to make it simpler to add a new test for IDEA-316752. GitOrigin-RevId: 2714727d1f51a32319170661ca825b8482061876 --- .../CopyReferenceActionFilesTest.kt | 175 +++++++++--------- 1 file changed, 85 insertions(+), 90 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt index 86ec6ba07c40..956e1af4467f 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt @@ -15,126 +15,121 @@ */ package com.intellij.java.codeInsight -import com.intellij.codeInsight.JavaCodeInsightTestCase import com.intellij.ide.actions.CopyReferenceAction -import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.readAction +import com.intellij.openapi.application.writeAction import com.intellij.openapi.module.JavaModuleType +import com.intellij.openapi.module.Module import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.psi.PsiManager import com.intellij.testFramework.PsiTestUtil -import junit.framework.TestCase +import com.intellij.testFramework.junit5.TestApplication +import com.intellij.testFramework.rules.ProjectModelExtension +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension -internal class CopyReferenceActionFilesTest : JavaCodeInsightTestCase() { - lateinit var additionalRoot: VirtualFile - @Throws(Exception::class) - override fun setUp() { - super.setUp() - module.setModuleType(JavaModuleType.getModuleType().id) - ApplicationManager.getApplication().runWriteAction(object : Runnable { - override fun run() { - additionalRoot = VirtualFileManager.getInstance().findFileByUrl("temp:///")!!.createChildDirectory(this, "newRoot") - } - }) - } +@TestApplication +class CopyReferenceActionFilesTest { + @JvmField + @RegisterExtension + val projectModel: ProjectModelExtension = ProjectModelExtension() - @Throws(Exception::class) - override fun tearDown() { - try { - ApplicationManager.getApplication().runWriteAction( - Runnable { additionalRoot.delete(this) }) - } - finally { - super.tearDown() + lateinit var module: Module + lateinit var rootDir: VirtualFile + + private val psiManager: PsiManager + get() = PsiManager.getInstance(projectModel.project) + + @BeforeEach + fun setUp() = runBlocking { + writeAction { + rootDir = projectModel.baseProjectDir.newVirtualDirectory("root") + module = projectModel.createModule() + module.setModuleType(JavaModuleType.getModuleType().id) } } - @Throws(Exception::class) - fun testCopyFile_RegisteredAsSourceRoots_ShouldContainItsName() { + @Test + fun `reference to file registered as source root must contain its name`() = runBlocking { // CPP-4315 "Edit | Copy Reference" result doesn't contain the file name lateinit var dir: VirtualFile lateinit var dir_subfile: VirtualFile lateinit var file: VirtualFile - ApplicationManager.getApplication().runWriteAction(object : Runnable { - override fun run() { - dir = additionalRoot.createChildDirectory(this, "dir") - dir_subfile = dir.createChildData(this, "dir_subfile.txt") - file = additionalRoot.createChildData(this, "file.txt") - PsiTestUtil.addContentRoot(getModule(), additionalRoot) - PsiTestUtil.addSourceRoot(getModule(), dir) - PsiTestUtil.addSourceRoot(getModule(), file) - } - }) - TestCase.assertEquals("dir", CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir))) - TestCase.assertEquals("dir_subfile.txt", - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(dir_subfile))) - TestCase.assertEquals("file.txt", CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(file))) + writeAction { + dir = rootDir.createChildDirectory(this, "dir") + dir_subfile = dir.createChildData(this, "dir_subfile.txt") + file = rootDir.createChildData(this, "file.txt") + PsiTestUtil.addContentRoot(module, rootDir) + PsiTestUtil.addSourceRoot(module, dir) + PsiTestUtil.addSourceRoot(module, file) + } + readAction { + assertEquals("dir", CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir))) + assertEquals("dir_subfile.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dir_subfile))) + assertEquals("file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(file))) + } } - @Throws(Exception::class) - fun testCopyFile_RegisteredAsContentRoot_ShouldContainItsFullPath() { + @Test + fun `reference to file registered as content root must contain its full path`() = runBlocking { // IDEA-144300 Copy Reference for source folder/content root copies empty string lateinit var dir: VirtualFile lateinit var dir_subfile: VirtualFile lateinit var file: VirtualFile - ApplicationManager.getApplication().runWriteAction(object : Runnable { - override fun run() { - dir = additionalRoot.createChildDirectory(this, "dir") - dir_subfile = dir.createChildData(this, "dir_subfile.txt") - file = additionalRoot.createChildData(this, "file.txt") - PsiTestUtil.addContentRoot(getModule(), dir) - PsiTestUtil.addContentRoot(getModule(), file) - } - }) - TestCase.assertEquals(dir.getPath(), - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir))) - TestCase.assertEquals("dir_subfile.txt", - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(dir_subfile))) - TestCase.assertEquals(file.getPath(), CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(file))) + writeAction { + dir = rootDir.createChildDirectory(this, "dir") + dir_subfile = dir.createChildData(this, "dir_subfile.txt") + file = rootDir.createChildData(this, "file.txt") + PsiTestUtil.addContentRoot(module, dir) + PsiTestUtil.addContentRoot(module, file) + } + readAction { + assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir))) + assertEquals("dir_subfile.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dir_subfile))) + assertEquals(file.getPath(), CopyReferenceAction.elementToFqn(psiManager.findFile(file))) + } } - @Throws(Exception::class) - fun testCopyFile_RegisteredAsNestedContentRoot_ShouldContainPathFromOuterMostRoot() { + @Test + fun `reference to file registered as nested content root must contain path from outer most root`() = runBlocking { // IDEA-144300 Copy Reference for source folder/content root copies empty string lateinit var dir: VirtualFile lateinit var dir_dir: VirtualFile lateinit var dir_dir_file: VirtualFile - ApplicationManager.getApplication().runWriteAction(object : Runnable { - override fun run() { - dir = additionalRoot.createChildDirectory(this, "dir") - dir_dir = dir.createChildDirectory(this, "dir_dir") - dir_dir_file = dir_dir.createChildData(this, "file.txt") - PsiTestUtil.addContentRoot(getModule(), dir) - PsiTestUtil.addContentRoot(getModule(), dir_dir) - } - }) - TestCase.assertEquals(dir.getPath(), - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir))) - TestCase.assertEquals("dir_dir", - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir_dir))) - TestCase.assertEquals("dir_dir/file.txt", - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(dir_dir_file))) + writeAction { + dir = rootDir.createChildDirectory(this, "dir") + dir_dir = dir.createChildDirectory(this, "dir_dir") + dir_dir_file = dir_dir.createChildData(this, "file.txt") + PsiTestUtil.addContentRoot(module, dir) + PsiTestUtil.addContentRoot(module, dir_dir) + } + readAction { + assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir))) + assertEquals("dir_dir", CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir_dir))) + assertEquals("dir_dir/file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dir_dir_file))) + } } - @Throws(Exception::class) - fun testCopyFile_UnderExcludeRoot_ShouldContainPathFromTheCorrespondingContentRoot() { + @Test + fun `reference to file under exclude root must contain path from the corresponding content root`() = runBlocking { // IDEA-144316 Copy Reference should work for excluded subfolders same way as it works for regular project subdirs lateinit var dir: VirtualFile lateinit var dir_dir: VirtualFile lateinit var dir_dir_file: VirtualFile - ApplicationManager.getApplication().runWriteAction(object : Runnable { - override fun run() { - dir = additionalRoot.createChildDirectory(this, "dir") - dir_dir = dir.createChildDirectory(this, "dir_dir") - dir_dir_file = dir_dir.createChildData(this, "file.txt") - PsiTestUtil.addContentRoot(getModule(), dir) - PsiTestUtil.addExcludedRoot(getModule(), dir_dir) - } - }) - TestCase.assertEquals(dir.getPath(), - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir))) - TestCase.assertEquals("dir_dir", - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findDirectory(dir_dir))) - TestCase.assertEquals("dir_dir/file.txt", - CopyReferenceAction.elementToFqn(com.intellij.psi.PsiManager.getInstance(project).findFile(dir_dir_file))) + writeAction { + dir = rootDir.createChildDirectory(this, "dir") + dir_dir = dir.createChildDirectory(this, "dir_dir") + dir_dir_file = dir_dir.createChildData(this, "file.txt") + PsiTestUtil.addContentRoot(module, dir) + PsiTestUtil.addExcludedRoot(module, dir_dir) + } + readAction { + assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir))) + assertEquals("dir_dir", CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir_dir))) + assertEquals("dir_dir/file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dir_dir_file))) + } } } From ecaf479180e2eb554eac86629a81e3bbe4019f10 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Mon, 3 Jul 2023 12:22:09 +0200 Subject: [PATCH 185/226] [tests] cleanup: rename local variable in CopyReferenceActionFilesTest to follow code style GitOrigin-RevId: f463f9794d23896028656b0005f714571281f6ea --- .../CopyReferenceActionFilesTest.kt | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt index 956e1af4467f..88364a70711b 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt @@ -56,11 +56,11 @@ class CopyReferenceActionFilesTest { fun `reference to file registered as source root must contain its name`() = runBlocking { // CPP-4315 "Edit | Copy Reference" result doesn't contain the file name lateinit var dir: VirtualFile - lateinit var dir_subfile: VirtualFile + lateinit var dirSubFile: VirtualFile lateinit var file: VirtualFile writeAction { dir = rootDir.createChildDirectory(this, "dir") - dir_subfile = dir.createChildData(this, "dir_subfile.txt") + dirSubFile = dir.createChildData(this, "dir_subfile.txt") file = rootDir.createChildData(this, "file.txt") PsiTestUtil.addContentRoot(module, rootDir) PsiTestUtil.addSourceRoot(module, dir) @@ -68,7 +68,7 @@ class CopyReferenceActionFilesTest { } readAction { assertEquals("dir", CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir))) - assertEquals("dir_subfile.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dir_subfile))) + assertEquals("dir_subfile.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dirSubFile))) assertEquals("file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(file))) } } @@ -77,18 +77,18 @@ class CopyReferenceActionFilesTest { fun `reference to file registered as content root must contain its full path`() = runBlocking { // IDEA-144300 Copy Reference for source folder/content root copies empty string lateinit var dir: VirtualFile - lateinit var dir_subfile: VirtualFile + lateinit var dirSubFile: VirtualFile lateinit var file: VirtualFile writeAction { dir = rootDir.createChildDirectory(this, "dir") - dir_subfile = dir.createChildData(this, "dir_subfile.txt") + dirSubFile = dir.createChildData(this, "dir_subfile.txt") file = rootDir.createChildData(this, "file.txt") PsiTestUtil.addContentRoot(module, dir) PsiTestUtil.addContentRoot(module, file) } readAction { assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir))) - assertEquals("dir_subfile.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dir_subfile))) + assertEquals("dir_subfile.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dirSubFile))) assertEquals(file.getPath(), CopyReferenceAction.elementToFqn(psiManager.findFile(file))) } } @@ -97,19 +97,19 @@ class CopyReferenceActionFilesTest { fun `reference to file registered as nested content root must contain path from outer most root`() = runBlocking { // IDEA-144300 Copy Reference for source folder/content root copies empty string lateinit var dir: VirtualFile - lateinit var dir_dir: VirtualFile - lateinit var dir_dir_file: VirtualFile + lateinit var dirDir: VirtualFile + lateinit var dirDirFile: VirtualFile writeAction { dir = rootDir.createChildDirectory(this, "dir") - dir_dir = dir.createChildDirectory(this, "dir_dir") - dir_dir_file = dir_dir.createChildData(this, "file.txt") + dirDir = dir.createChildDirectory(this, "dir_dir") + dirDirFile = dirDir.createChildData(this, "file.txt") PsiTestUtil.addContentRoot(module, dir) - PsiTestUtil.addContentRoot(module, dir_dir) + PsiTestUtil.addContentRoot(module, dirDir) } readAction { assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir))) - assertEquals("dir_dir", CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir_dir))) - assertEquals("dir_dir/file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dir_dir_file))) + assertEquals("dir_dir", CopyReferenceAction.elementToFqn(psiManager.findDirectory(dirDir))) + assertEquals("dir_dir/file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dirDirFile))) } } @@ -117,19 +117,19 @@ class CopyReferenceActionFilesTest { fun `reference to file under exclude root must contain path from the corresponding content root`() = runBlocking { // IDEA-144316 Copy Reference should work for excluded subfolders same way as it works for regular project subdirs lateinit var dir: VirtualFile - lateinit var dir_dir: VirtualFile - lateinit var dir_dir_file: VirtualFile + lateinit var dirDir: VirtualFile + lateinit var dirDirFile: VirtualFile writeAction { dir = rootDir.createChildDirectory(this, "dir") - dir_dir = dir.createChildDirectory(this, "dir_dir") - dir_dir_file = dir_dir.createChildData(this, "file.txt") + dirDir = dir.createChildDirectory(this, "dir_dir") + dirDirFile = dirDir.createChildData(this, "file.txt") PsiTestUtil.addContentRoot(module, dir) - PsiTestUtil.addExcludedRoot(module, dir_dir) + PsiTestUtil.addExcludedRoot(module, dirDir) } readAction { assertEquals(dir.getPath(), CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir))) - assertEquals("dir_dir", CopyReferenceAction.elementToFqn(psiManager.findDirectory(dir_dir))) - assertEquals("dir_dir/file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dir_dir_file))) + assertEquals("dir_dir", CopyReferenceAction.elementToFqn(psiManager.findDirectory(dirDir))) + assertEquals("dir_dir/file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(dirDirFile))) } } } From 8ea02f930e0315bf3237e58ecb6841a87c54d29d Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Mon, 3 Jul 2023 12:40:26 +0200 Subject: [PATCH 186/226] [platform] "Copy Reference" action for non-java modules should copy the path from the content root (IDEA-316752) WorkspaceFileIndex::getContentFileSetRoot will return the path to the nearest parent content or source root, this is not that people expect for non-java modules. BaseProjectDirectories::getBaseDirectoryFor called below will return the parent (top-level) content root. Files in Java modules are handled by JavaVirtualFileQualifiedNameProvider, so nothing will change for them. GitOrigin-RevId: 916ce28ba7bf85b44cf19bb8734dcd0e0494fea5 --- .../codeInsight/CopyReferenceActionFilesTest.kt | 16 ++++++++++++++++ .../src/com/intellij/ide/actions/FqnUtil.java | 10 ---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt index 88364a70711b..927212bfef8b 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/CopyReferenceActionFilesTest.kt @@ -20,6 +20,7 @@ import com.intellij.openapi.application.readAction import com.intellij.openapi.application.writeAction import com.intellij.openapi.module.JavaModuleType import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleTypeId import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiManager import com.intellij.testFramework.PsiTestUtil @@ -72,6 +73,21 @@ class CopyReferenceActionFilesTest { assertEquals("file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(file))) } } + + @Test + fun `reference to file under non-java source root must include path from content root`() = runBlocking { + lateinit var file: VirtualFile + writeAction { + module.setModuleType(ModuleTypeId.WEB_MODULE) + val sourceRoot = rootDir.createChildDirectory(this, "src") + PsiTestUtil.addContentRoot(module, rootDir) + PsiTestUtil.addSourceRoot(module, sourceRoot) + file = sourceRoot.createChildData(this, "file.txt") + } + readAction { + assertEquals("src/file.txt", CopyReferenceAction.elementToFqn(psiManager.findFile(file))) + } + } @Test fun `reference to file registered as content root must contain its full path`() = runBlocking { diff --git a/platform/refactoring/src/com/intellij/ide/actions/FqnUtil.java b/platform/refactoring/src/com/intellij/ide/actions/FqnUtil.java index a5fa25b10546..a39a0506a04c 100644 --- a/platform/refactoring/src/com/intellij/ide/actions/FqnUtil.java +++ b/platform/refactoring/src/com/intellij/ide/actions/FqnUtil.java @@ -10,7 +10,6 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.Strings; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -18,7 +17,6 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; -import com.intellij.workspaceModel.core.fileIndex.WorkspaceFileIndex; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -70,14 +68,6 @@ public class FqnUtil { } } - VirtualFile root = WorkspaceFileIndex.getInstance(project).getContentFileSetRoot(virtualFile, false); - if (root != null) { - String relativePath = VfsUtilCore.getRelativePath(virtualFile, root); - if (Strings.isNotEmpty(relativePath)) { - return relativePath; - } - } - VirtualFile baseDirectory = BaseProjectDirectories.getInstance(project).getBaseDirectoryFor(virtualFile); if (baseDirectory != null) { String relativePath = VfsUtilCore.getRelativePath(virtualFile, baseDirectory); From 22e9f1ac8fc31ced55eee35fba65c3695e072216 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Mon, 3 Jul 2023 13:12:50 +0200 Subject: [PATCH 187/226] [mod-commands] Use original editor in chooser Editor may differ from openTextEditor; it could be a diff panel, or editor inside a toolwindow. Fixes IDEA-324148 Replace side-effect dialog - Chooser with quick-fix opens in the incorrect place for the "Inspect Code" option GitOrigin-RevId: e90485e6143b7bc80ad585d0a3ada640226541a5 --- .../lookup/VariableLookupItem.java | 2 +- .../intention/SplitIfActionTest.java | 2 +- ...uickFixAndIntentionActionOnPsiElement.java | 2 +- .../modcommand/ModCommandQuickFix.java | 2 +- .../modcommand/ModCommandService.java | 4 ++- .../impl/ShowIntentionActionsHandler.java | 2 +- .../modcommand/ModCommandActionWrapper.java | 2 +- .../modcommand/ModCommandServiceImpl.java | 30 +++++++++---------- 8 files changed, 24 insertions(+), 22 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java index 8a4e060b153d..430f2509ea84 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java @@ -247,7 +247,7 @@ public class VariableLookupItem extends LookupItem implements Typed if (fix != null) { ModCommandAction.ActionContext actionContext = ModCommandAction.ActionContext.from(context.getEditor(), context.getFile()); if (fix.getPresentation(actionContext) != null) { - ModCommandService.getInstance().executeInteractively(actionContext, fix.perform(actionContext)); + ModCommandService.getInstance().executeInteractively(actionContext, fix.perform(actionContext), context.getEditor()); } } } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/SplitIfActionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/SplitIfActionTest.java index 95df984cfd3e..9ffef309b922 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/SplitIfActionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/SplitIfActionTest.java @@ -97,6 +97,6 @@ public class SplitIfActionTest extends LightJavaCodeInsightTestCase { ModCommandAction.ActionContext context = ModCommandAction.ActionContext.from(getEditor(), getFile()); assertNotNull(action.getPresentation(context)); ModCommand command = action.perform(context); - ApplicationManager.getApplication().runWriteAction(() -> ModCommandService.getInstance().executeInteractively(context, command)); + ApplicationManager.getApplication().runWriteAction(() -> ModCommandService.getInstance().executeInteractively(context, command, getEditor())); } } diff --git a/platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFixAndIntentionActionOnPsiElement.java b/platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFixAndIntentionActionOnPsiElement.java index 0b09edacf304..08b6cf42116f 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFixAndIntentionActionOnPsiElement.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFixAndIntentionActionOnPsiElement.java @@ -120,7 +120,7 @@ public abstract class LocalQuickFixAndIntentionActionOnPsiElement extends LocalQ @NotNull PsiElement endElement) { ModCommandAction.ActionContext context = ModCommandAction.ActionContext.from(editor, file).withElement(startElement); ModCommand command = action.perform(context); - ModCommandService.getInstance().executeInteractively(context, command); + ModCommandService.getInstance().executeInteractively(context, command, editor); } @Override diff --git a/platform/analysis-api/src/com/intellij/modcommand/ModCommandQuickFix.java b/platform/analysis-api/src/com/intellij/modcommand/ModCommandQuickFix.java index 73a8617d2c53..68fbf7cbd5ba 100644 --- a/platform/analysis-api/src/com/intellij/modcommand/ModCommandQuickFix.java +++ b/platform/analysis-api/src/com/intellij/modcommand/ModCommandQuickFix.java @@ -47,7 +47,7 @@ public abstract class ModCommandQuickFix implements LocalQuickFix { @Override public final void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { ModCommand command = perform(project, descriptor); - ModCommandService.getInstance().executeInteractively(ModCommandAction.ActionContext.from(descriptor), command); + ModCommandService.getInstance().executeInteractively(ModCommandAction.ActionContext.from(descriptor), command, null); } @Override diff --git a/platform/analysis-api/src/com/intellij/modcommand/ModCommandService.java b/platform/analysis-api/src/com/intellij/modcommand/ModCommandService.java index 609f27a1fe2a..c56c2e7dd406 100644 --- a/platform/analysis-api/src/com/intellij/modcommand/ModCommandService.java +++ b/platform/analysis-api/src/com/intellij/modcommand/ModCommandService.java @@ -5,6 +5,7 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.modcommand.ModCommandAction.ActionContext; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; import com.intellij.util.concurrency.annotations.RequiresEdt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,9 +52,10 @@ public interface ModCommandService { * * @param context current context * @param command a command to execute + * @param editor context editor, if known */ @RequiresEdt - void executeInteractively(@NotNull ActionContext context, @NotNull ModCommand command); + void executeInteractively(@NotNull ActionContext context, @NotNull ModCommand command, @Nullable Editor editor); /** * Executes given {@link ModCommand} in batch (applies default options, do not navigate) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java index 08abdfd9efee..47145205e080 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java @@ -294,7 +294,7 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler { Project project = context.project(); IntentionFUSCollector.record(project, commandAction, context.file().getLanguage()); CommandProcessor.getInstance().executeCommand(project, () -> { - ModCommandService.getInstance().executeInteractively(context, contextAndCommand.command()); + ModCommandService.getInstance().executeInteractively(context, contextAndCommand.command(), hostEditor); }, commandName, null); } diff --git a/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandActionWrapper.java b/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandActionWrapper.java index 49ca7f093df5..9bc459b1abf2 100644 --- a/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandActionWrapper.java +++ b/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandActionWrapper.java @@ -70,7 +70,7 @@ import java.util.Objects; public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { ModCommandAction.ActionContext context = ModCommandAction.ActionContext.from(editor, file); ModCommand command = myAction.perform(context); - ModCommandService.getInstance().executeInteractively(context, command); + ModCommandService.getInstance().executeInteractively(context, command, editor); } @Override diff --git a/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java b/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java index 9aec5450397f..d0550f45ed6f 100644 --- a/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java @@ -86,9 +86,9 @@ public class ModCommandServiceImpl implements ModCommandService { @RequiresEdt @Override - public void executeInteractively(@NotNull ActionContext context, @NotNull ModCommand command) { + public void executeInteractively(@NotNull ActionContext context, @NotNull ModCommand command, @Nullable Editor editor) { if (!ensureWritable(context.project(), command)) return; - doExecute(context, command, true); + doExecute(context, command, editor, true); } private static boolean ensureWritable(@NotNull Project project, @NotNull ModCommand command) { @@ -99,16 +99,16 @@ public class ModCommandServiceImpl implements ModCommandService { @Override public void executeInBatch(@NotNull ActionContext context, @NotNull ModCommand command) { if (!ensureWritable(context.project(), command)) return; - doExecute(context, command, false); + doExecute(context, command, null, false); } - private boolean doExecute(@NotNull ActionContext context, @NotNull ModCommand command, boolean onTheFly) { + private boolean doExecute(@NotNull ActionContext context, @NotNull ModCommand command, @Nullable Editor editor, boolean onTheFly) { Project project = context.project(); if (command instanceof ModUpdateFileText upd) { return executeUpdate(project, upd); } if (command instanceof ModCompositeCommand cmp) { - return executeComposite(context, cmp, onTheFly); + return executeComposite(context, cmp, editor, onTheFly); } if (command instanceof ModNavigate nav) { if (!onTheFly) return true; @@ -122,7 +122,7 @@ public class ModCommandServiceImpl implements ModCommandService { return true; } if (command instanceof ModChooseAction chooser) { - return executeChoose(context, chooser, onTheFly); + return executeChoose(context, chooser, onTheFly, editor); } if (command instanceof ModDisplayMessage message) { if (!onTheFly) return true; // TODO: gather all errors and display them together? @@ -266,7 +266,7 @@ public class ModCommandServiceImpl implements ModCommandService { return true; } - private boolean executeChoose(@NotNull ActionContext context, ModChooseAction chooser, boolean onTheFly) { + private boolean executeChoose(@NotNull ActionContext context, ModChooseAction chooser, boolean onTheFly, @Nullable Editor editor) { record ActionAndPresentation(@NotNull ModCommandAction action, @NotNull ModCommandAction.Presentation presentation) {} List actions = StreamEx.of(chooser.actions()).mapToEntry(action -> action.getPresentation(context)) .nonNullValues().mapKeyValue(ActionAndPresentation::new).toList(); @@ -275,7 +275,7 @@ public class ModCommandServiceImpl implements ModCommandService { String name = CommandProcessor.getInstance().getCurrentCommandName(); if (actions.size() == 1 || !onTheFly) { ModCommandAction action = actions.get(0).action(); - executeNextStep(context, name, onTheFly, () -> { + executeNextStep(context, name, editor, onTheFly, () -> { if (action.getPresentation(context) == null) return null; return action.perform(context); }); @@ -283,14 +283,14 @@ public class ModCommandServiceImpl implements ModCommandService { } VirtualFile file = context.file().getVirtualFile(); if (file == null) return false; - Editor editor = getEditor(context.project(), file); + Editor finalEditor = editor == null ? getEditor(context.project(), file) : editor; if (editor == null) return false; ShowIntentionsPass.IntentionsInfo info = new ShowIntentionsPass.IntentionsInfo(); List descriptors = ContainerUtil.map( actions, (actionAndPresentation) -> { ModCommandAction.Presentation presentation = actionAndPresentation.presentation(); IntentionAction intention = actionAndPresentation.action().asIntention(); - intention.isAvailable(context.project(), editor, context.file()); // cache text + intention.isAvailable(context.project(), finalEditor, context.file()); // cache text return new HighlightInfo.IntentionActionDescriptor(intention, List.of(), presentation.name(), presentation.icon(), null, null, null); }); info.intentionsToShow.addAll(descriptors); @@ -300,15 +300,15 @@ public class ModCommandServiceImpl implements ModCommandService { return true; } - private void executeNextStep(@NotNull ActionContext context, @Nullable @NlsContexts.Command String name, boolean onTheFly, + private void executeNextStep(@NotNull ActionContext context, @Nullable @NlsContexts.Command String name, @Nullable Editor editor, boolean onTheFly, Callable supplier) { ReadAction.nonBlocking(supplier) .finishOnUiThread(ModalityState.defaultModalityState(), next -> { if (next == null) return; if (name != null) { - CommandProcessor.getInstance().executeCommand(context.project(), () -> doExecute(context, next, true), name, onTheFly); + CommandProcessor.getInstance().executeCommand(context.project(), () -> doExecute(context, next, editor, true), name, onTheFly); } else { - doExecute(context, next, onTheFly); + doExecute(context, next, editor, onTheFly); } }) .submit(AppExecutorUtil.getAppExecutorService()); @@ -355,9 +355,9 @@ public class ModCommandServiceImpl implements ModCommandService { return FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, file), true); } - private boolean executeComposite(@NotNull ActionContext context, ModCompositeCommand cmp, boolean onTheFly) { + private boolean executeComposite(@NotNull ActionContext context, ModCompositeCommand cmp, @Nullable Editor editor, boolean onTheFly) { for (ModCommand command : cmp.commands()) { - boolean status = doExecute(context, command, onTheFly); + boolean status = doExecute(context, command, editor, onTheFly); if (!status) { return false; } From 13fb47b4e7fb50e822a11339da9e28812f30cd0a Mon Sep 17 00:00:00 2001 From: Andrei Klunnyi Date: Mon, 3 Jul 2023 12:35:44 +0200 Subject: [PATCH 188/226] [kotlin] KTIJ-26111: UI freezes at long running scripting init ^KTIJ-26111 fixed GitOrigin-RevId: ddf6e53bacef12ed57bf13721bfd32f3d3bd90bf --- .../script/ucache/ScriptClassRootsUpdater.kt | 21 ++++++++++++++----- .../resources/META-INF/scripting-base.xml | 7 ++++--- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/plugins/kotlin/base/scripting/src/org/jetbrains/kotlin/idea/core/script/ucache/ScriptClassRootsUpdater.kt b/plugins/kotlin/base/scripting/src/org/jetbrains/kotlin/idea/core/script/ucache/ScriptClassRootsUpdater.kt index 3ca094e09de8..15952e52afea 100644 --- a/plugins/kotlin/base/scripting/src/org/jetbrains/kotlin/idea/core/script/ucache/ScriptClassRootsUpdater.kt +++ b/plugins/kotlin/base/scripting/src/org/jetbrains/kotlin/idea/core/script/ucache/ScriptClassRootsUpdater.kt @@ -43,6 +43,7 @@ import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference +import kotlin.system.measureTimeMillis /** * Holder for [ScriptClassRootsCache]. @@ -58,7 +59,7 @@ import java.util.concurrent.atomic.AtomicReference * Also analysis cache will be cleared and changed opened script files will be reanalyzed. */ -private const val INIT_TIMEOUT_REGISTRY_KEY = "kotlin.scripting.wait-init.timeout.sec" +private const val INIT_WAIT_ATTEMPTS_REGISTRY_KEY = "kotlin.scripting.wait-init.attempts.num" abstract class ScriptClassRootsUpdater( val project: Project, @@ -103,11 +104,21 @@ abstract class ScriptClassRootsUpdater( val classpathRoots: ScriptClassRootsCache get() { - val timeoutSec = Registry.intValue(INIT_TIMEOUT_REGISTRY_KEY, 5).toLong() - if (!cacheNotEmptyLatch.await(timeoutSec, TimeUnit.SECONDS)) { - scriptingWarnLog("Script configurations init timeout elapsed. " + - "Try increasing the value of registry key '${INIT_TIMEOUT_REGISTRY_KEY}'") + val timeoutMs = 500L + var attemptsLeft = Registry.intValue(INIT_WAIT_ATTEMPTS_REGISTRY_KEY, 10) + + val ms = measureTimeMillis { + while (!cacheNotEmptyLatch.await(timeoutMs, TimeUnit.MILLISECONDS) && attemptsLeft > 0) { + attemptsLeft-- + ProgressManager.checkCanceled() + } } + + if (attemptsLeft == 0) { + scriptingWarnLog("Couldn't load initial script cache state after $ms ms. In most cases we can cope with it. " + + "For others see registry key kotlin.scripting.wait-init.attempts.num.") + } + return cache.get() } diff --git a/plugins/kotlin/plugin/common/resources/META-INF/scripting-base.xml b/plugins/kotlin/plugin/common/resources/META-INF/scripting-base.xml index 7a67b9ba4624..1d7c3a6d181f 100644 --- a/plugins/kotlin/plugin/common/resources/META-INF/scripting-base.xml +++ b/plugins/kotlin/plugin/common/resources/META-INF/scripting-base.xml @@ -113,9 +113,10 @@ restartRequired="true"/> Date: Mon, 3 Jul 2023 13:55:49 +0200 Subject: [PATCH 189/226] IDEA-311403 New macOS project tabs: hide tab close icon ('x') when tab title is not hovered GitOrigin-RevId: a9b0ae2b05b24da03cf0f982fe18beff62d1f504 --- .../src/com/intellij/ui/mac/WindowTabsComponent.java | 11 ++++++++--- platform/util/resources/misc/registry.properties | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/mac/WindowTabsComponent.java b/platform/platform-impl/src/com/intellij/ui/mac/WindowTabsComponent.java index 74540ce85607..f161ff19901c 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/WindowTabsComponent.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/WindowTabsComponent.java @@ -14,6 +14,7 @@ import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.util.PopupUtil; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.IdeGlassPaneUtil; import com.intellij.openapi.wm.impl.IdeFrameImpl; import com.intellij.ui.*; @@ -188,14 +189,14 @@ public final class WindowTabsComponent extends JBTabsImpl { }, BorderLayout.WEST); myActionPanel.setBorder(JBUI.Borders.emptyLeft(6)); - myActionPanel.setVisible(false); + myActionPanel.setVisible(!showCloseActionOnHover()); } } @Override protected void setHovered(boolean value) { super.setHovered(value); - myActionPanel.setVisible(value || getInfo() == myTabs.getPopupInfo()); + myActionPanel.setVisible(!showCloseActionOnHover() || value || getInfo() == myTabs.getPopupInfo()); } @Override @@ -216,7 +217,7 @@ public final class WindowTabsComponent extends JBTabsImpl { private void handle() { popup.removePopupMenuListener(this); - myActionPanel.setVisible(isHovered()); + myActionPanel.setVisible(!showCloseActionOnHover() || isHovered()); } }); } @@ -234,6 +235,10 @@ public final class WindowTabsComponent extends JBTabsImpl { }; } + private static boolean showCloseActionOnHover() { + return Registry.is("ide.mac.os.wintabs.show.closeaction.on.hover", true); + } + @Override protected @NotNull TabPainterAdapter createTabPainterAdapter() { return new TabPainterAdapter() { diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index e61821372f84..8295859ddc1a 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -2184,6 +2184,9 @@ ide.mac.os.wintabs.version2=true ide.mac.os.wintabs.version2.description=Enable Mac OS project tabs for New UI ide.mac.os.wintabs.version2.restartRequired=true +ide.mac.os.wintabs.show.closeaction.on.hover=true +ide.mac.os.wintabs.show.closeaction.on.hover.description=Show close tab action only on tab hover + apple.awt.newFullScreeControls=true ea.enable.developers.list=true From bb303062f22e6f6de2dc28e9720cd9af9b232f92 Mon Sep 17 00:00:00 2001 From: Bart van Helvert Date: Mon, 3 Jul 2023 13:04:23 +0200 Subject: [PATCH 190/226] [kotlin] Remove unused import in K2 bindToElement #KTIJ-26105 GitOrigin-RevId: 3250414b54667c3130430117783f406171e0ae56 --- .../bindToElement/import/ChangeImports.kt | 8 ++++++++ .../bindToElement/import/ChangeImports.kt.after | 9 +++++++++ .../refactoring/bindToElement/import/bar/A.kt | 3 +++ .../refactoring/bindToElement/import/foo/A.kt | 3 +++ .../k2/refactoring/K2ReferenceMutateService.kt | 16 ++++++++++++++++ .../safeDelete/AbstractK2BindToElementTest.kt | 10 ++++++++++ .../safeDelete/K2BindToElementTestGenerated.java | 13 +++++++++++++ .../testGenerator/GenerateK2RefactoringsTests.kt | 1 + 8 files changed, 63 insertions(+) create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/bar/A.kt create mode 100644 plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/foo/A.kt diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt new file mode 100644 index 000000000000..04471fe7db6a --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt @@ -0,0 +1,8 @@ +// BIND_TO test.bar.A +package test + +import test.foo.A + +fun foo() { + val x = A() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt.after new file mode 100644 index 000000000000..da55454a82b4 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt.after @@ -0,0 +1,9 @@ +// BIND_TO test.bar.A +package test + + +import test.bar.A + +fun foo() { + val x = A() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/bar/A.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/bar/A.kt new file mode 100644 index 000000000000..a58cee7b163e --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/bar/A.kt @@ -0,0 +1,3 @@ +package test.bar + +class A { } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/foo/A.kt b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/foo/A.kt new file mode 100644 index 000000000000..5fe27344ee39 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/bindToElement/import/foo/A.kt @@ -0,0 +1,3 @@ +package test.foo + +class A { } \ No newline at end of file diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/K2ReferenceMutateService.kt b/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/K2ReferenceMutateService.kt index 6fcdbc6e67f2..61617d0a2dd9 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/K2ReferenceMutateService.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/K2ReferenceMutateService.kt @@ -29,6 +29,12 @@ internal class K2ReferenceMutateService : KtReferenceMutateServiceBase() { if (targetElement !is KtElement) operationNotSupportedInK2Error() // TODO fix reference shortener for non-Kotlin target elements val expression = simpleNameReference.expression if (fqName.isRoot) return expression + + val containingFile = expression.containingKtFile + val unusedImportsBeforeChange = analyze(containingFile) { // TODO improve this + analyseImports(containingFile) + }.unusedImports + val anchorElement = expression.parentOfTypes(KtTypeReference::class) ?: expression.topMostQualified() val newElement = when (anchorElement) { is KtTypeReference -> anchorElement.replaceWith(fqName) @@ -36,6 +42,16 @@ internal class K2ReferenceMutateService : KtReferenceMutateServiceBase() { is KtDotQualifiedExpression -> anchorElement.replaceWith(fqName) else -> return expression } ?: return expression + + + val unusedImportsAfterChange = analyze(containingFile) { + analyseImports(containingFile) + }.unusedImports + val importsToRemove = unusedImportsAfterChange - unusedImportsBeforeChange + importsToRemove.forEach { + it.delete() + } + val newShortenings = analyze(newElement) { collectPossibleReferenceShorteningsInElement(newElement) } return newShortenings.invokeShortening().firstOrNull() ?: newElement } diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/AbstractK2BindToElementTest.kt b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/AbstractK2BindToElementTest.kt index c62435ffbdef..32b6adacd8f0 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/AbstractK2BindToElementTest.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/AbstractK2BindToElementTest.kt @@ -4,6 +4,7 @@ package org.jetbrains.kotlin.idea.k2.refactoring.safeDelete import com.intellij.openapi.command.WriteCommandAction import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass +import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.parentOfType @@ -15,6 +16,7 @@ import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.ProjectDescriptorWithStdlibSources import org.jetbrains.kotlin.psi.KtSimpleNameExpression +import java.nio.file.Path abstract class AbstractK2BindToElementTest : KotlinLightCodeInsightFixtureTestCase() { override fun isFirPlugin() = true @@ -24,6 +26,7 @@ abstract class AbstractK2BindToElementTest : KotlinLightCodeInsightFixtureTestCa @OptIn(KtAllowAnalysisOnEdt::class) protected fun doTest(path: String) { val file = myFixture.configureByFile(path) + addAllFilesToProject(Path.of(path).parent) val elem = file.findElementAt(myFixture.caretOffset) ?: error("Couldn't find element at caret") val nameReference = elem.parentOfType(withSelf = true) ?: error("Element at caret isn't of type 'KtSimpleNameExpression'") @@ -36,6 +39,13 @@ abstract class AbstractK2BindToElementTest : KotlinLightCodeInsightFixtureTestCa myFixture.checkResultByFile("${myFixture.file.name}.after") } + private fun addAllFilesToProject(rootDir: Path) { + rootDir.toFile().listFiles()?.forEach { + if (it.isDirectory) myFixture.copyDirectoryToProject(it.name, it.name) + } + PsiDocumentManager.getInstance(myFixture.project).commitAllDocuments() + } + private fun findElementToBind(): PsiElement? { val classToBind = InTextDirectivesUtils.findStringWithPrefixes(file.text, BIND_TO) return if (classToBind != null) findClass(classToBind) else null diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/K2BindToElementTestGenerated.java b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/K2BindToElementTestGenerated.java index 8697aca27628..111b6ed38910 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/K2BindToElementTestGenerated.java +++ b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/safeDelete/K2BindToElementTestGenerated.java @@ -91,4 +91,17 @@ public abstract class K2BindToElementTestGenerated extends AbstractK2BindToEleme runTest("../../idea/tests/testData/refactoring/bindToElement/type/UnQualified.kt"); } } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../../idea/tests/testData/refactoring/bindToElement/import") + public static class Import extends AbstractK2BindToElementTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("ChangeImports.kt") + public void testChangeImports() throws Exception { + runTest("../../idea/tests/testData/refactoring/bindToElement/import/ChangeImports.kt"); + } + } } diff --git a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/GenerateK2RefactoringsTests.kt b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/GenerateK2RefactoringsTests.kt index 29ed58ba5cd1..4769c170dad7 100644 --- a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/GenerateK2RefactoringsTests.kt +++ b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/GenerateK2RefactoringsTests.kt @@ -34,6 +34,7 @@ internal fun MutableTWorkspace.generateK2RefactoringsTests() { model("refactoring/bindToElement/call") model("refactoring/bindToElement/callableReference") model("refactoring/bindToElement/type") + model("refactoring/bindToElement/import", isRecursive = false) } } From 1e4761a0a1481cbdf41f858dd627f04d8cacf45c Mon Sep 17 00:00:00 2001 From: Ruslan Cheremin Date: Mon, 3 Jul 2023 11:35:33 +0200 Subject: [PATCH 191/226] [core] IDEA-319737: disable regular VFS health-check in tests, log message polishing + Regular VFS HealthCheck is useless in tests (better run it explicitly at the end of test) -- disable it + A bit of polishing for orphan records logging GitOrigin-RevId: 598b30a6f7ea77985afb2d86f1e66f05d5f9e9b5 --- .../vfs/newvfs/persistent/VFSHealthChecker.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt index 2e5692d9a12c..a573fa94225d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VFSHealthChecker.kt @@ -39,7 +39,7 @@ import kotlin.time.toDuration object VFSHealthCheckerConstants { @JvmStatic val HEALTH_CHECKING_ENABLED = getBooleanProperty("vfs.health-check.enabled", - ApplicationManager.getApplication().isEAP) + ApplicationManager.getApplication().isEAP && !ApplicationManager.getApplication().isUnitTestMode) @JvmStatic val HEALTH_CHECKING_PERIOD_MS = getIntProperty("vfs.health-check.checking-period-ms", @@ -53,7 +53,10 @@ object VFSHealthCheckerConstants { 10.minutes.inWholeMilliseconds.toInt()) - /** May take quite a time, hence disabled by default */ + /** + * May slow down scanning significantly, hence dedicated property to control. + * Default: false, since orphan records appear to be quite common so far. + */ @JvmStatic val CHECK_ORPHAN_RECORDS = getBooleanProperty("vfs.health-check.check-orphan-records", false) @@ -265,12 +268,17 @@ class VFSHealthChecker(private val impl: FSRecordsImpl, if (checkForOrphanRecords) { if (BitUtil.isSet(parentFlags, CHILDREN_CACHED)) { try { - //MAYBE RC: use .listIdsUnchecked() method -- to not force VFS rebuild? + //MAYBE RC: use .listIdsUnchecked() method -- to not trigger VFS rebuild? val childrenOfParent = impl.listIds(parentId) if (childrenOfParent.indexOf(fileId) < 0) { inconsistentParentChildRelationships++ //MAYBE RC: dedicated counter? + val maxChildrenToLog = 32 + val childrenPrefix = if (childrenOfParent.size > maxChildrenToLog) + "first $maxChildrenToLog of ${childrenOfParent.size}: " + else + "" log.info("file[#$fileId]{$fileName}: record is orphan, " + - ".parent[#$parentId].children(first 64 of ${childrenOfParent.size}: ${childrenOfParent.take(64)}...) doesn't contain it!") + ".parent[#$parentId].children($childrenPrefix${childrenOfParent.joinToString(limit = maxChildrenToLog)}) doesn't contain it!") } } catch (e: Throwable) { From 4fd7ab1769fefc0f6749b57c8f8bb995e29f1efb Mon Sep 17 00:00:00 2001 From: Artem Khvastunov Date: Thu, 29 Jun 2023 17:25:20 +0200 Subject: [PATCH 192/226] IDEA-323982 add build originator to FUS statistics GitOrigin-RevId: 9031c45010971a2e8cabc0d24a911e6fe6aa4ad8 --- .../compiler/actions/BuildArtifactAction.java | 2 ++ .../compiler/actions/CompileActionBase.java | 4 +++- .../BuildArtifactsBeforeRunTaskProviderBase.kt | 3 ++- .../com/intellij/debugger/ui/HotSwapUIImpl.java | 11 ++++++++--- .../compiler/options/CompileStepBeforeRun.java | 2 ++ .../java/performancePlugin/BuildCommand.java | 3 +++ .../task/impl/ProjectTaskManagerImpl.java | 16 +++++++++++++++- .../ProjectTaskManagerStatisticsCollector.kt | 12 ++++++------ platform/smart-update/intellij.smart.update.iml | 2 +- .../com/intellij/smartUpdate/BuildProjectStep.kt | 2 ++ .../warmup/PlatformBuildWarmupSupport.kt | 2 ++ .../intellij/coverage/JavaCoverageEngine.java | 4 +++- .../idea/scratch/actions/RunScratchAction.kt | 4 +++- .../kotlin/console/ConsoleCompilerHelper.kt | 4 +++- 14 files changed, 55 insertions(+), 16 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/BuildArtifactAction.java b/java/compiler/impl/src/com/intellij/compiler/actions/BuildArtifactAction.java index 2dc5ca18fb49..74a8f332999c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/actions/BuildArtifactAction.java +++ b/java/compiler/impl/src/com/intellij/compiler/actions/BuildArtifactAction.java @@ -28,6 +28,7 @@ import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.impl.artifacts.ArtifactUtil; import com.intellij.packaging.impl.compiler.ArtifactsWorkspaceSettings; import com.intellij.task.ProjectTaskManager; +import com.intellij.task.impl.ProjectTaskManagerImpl; import com.intellij.ui.popup.list.ListPopupImpl; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.EmptyIcon; @@ -117,6 +118,7 @@ public final class BuildArtifactAction extends DumbAwareAction { } private static void doBuild(@NotNull Project project, final @NotNull List items, boolean rebuild) { + ProjectTaskManagerImpl.putBuildOriginator(project, BuildArtifactAction.class); final Artifact[] artifacts = getArtifacts(items, project); if (rebuild) { ProjectTaskManager.getInstance(project).rebuild(artifacts); diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/CompileActionBase.java b/java/compiler/impl/src/com/intellij/compiler/actions/CompileActionBase.java index 3a95bc371d30..496f3f9634bd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/actions/CompileActionBase.java +++ b/java/compiler/impl/src/com/intellij/compiler/actions/CompileActionBase.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler.actions; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; @@ -9,6 +9,7 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; +import com.intellij.task.impl.ProjectTaskManagerImpl; import org.jetbrains.annotations.NotNull; public abstract class CompileActionBase extends AnAction implements DumbAware { @@ -29,6 +30,7 @@ public abstract class CompileActionBase extends AnAction implements DumbAware { if (file != null && editor != null && !DumbService.getInstance(project).isDumb()) { DaemonCodeAnalyzer.getInstance(project).autoImportReferenceAtCursor(editor, file); //let autoimport complete } + ProjectTaskManagerImpl.putBuildOriginator(project, this.getClass()); doAction(e.getDataContext(), project); } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProviderBase.kt b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProviderBase.kt index 218f0434abbd..141178e81071 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProviderBase.kt +++ b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProviderBase.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.packaging.impl.run import com.intellij.execution.BeforeRunTaskProvider @@ -86,6 +86,7 @@ abstract class BuildArtifactsBeforeRunTaskProviderBase { if ((!taskResult.hasErrors() || ignoreErrors) && !taskResult.isAborted()) { result.set(Boolean.TRUE); diff --git a/java/performancePlugin/src/com/intellij/java/performancePlugin/BuildCommand.java b/java/performancePlugin/src/com/intellij/java/performancePlugin/BuildCommand.java index e008cfcc360d..b18b5b257626 100644 --- a/java/performancePlugin/src/com/intellij/java/performancePlugin/BuildCommand.java +++ b/java/performancePlugin/src/com/intellij/java/performancePlugin/BuildCommand.java @@ -1,3 +1,4 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.performancePlugin; import com.intellij.openapi.application.ApplicationManager; @@ -9,6 +10,7 @@ import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Ref; import com.intellij.task.ModuleBuildTask; import com.intellij.task.ProjectTaskManager; +import com.intellij.task.impl.ProjectTaskManagerImpl; import com.intellij.util.messages.MessageBusConnection; import com.jetbrains.performancePlugin.PerformanceTestSpan; import com.jetbrains.performancePlugin.PerformanceTestingBundle; @@ -71,6 +73,7 @@ public class BuildCommand extends AbstractCommand { }); ApplicationManager.getApplication().invokeLater(() -> { + ProjectTaskManagerImpl.putBuildOriginator(project, this.getClass()); ProjectTaskManager instance = ProjectTaskManager.getInstance(project); Promise promise = null; spanRef.set(span.startSpan()); diff --git a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java index a055c48552f6..ac42df5f9f02 100644 --- a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.task.impl; import com.intellij.execution.ExecutionException; @@ -17,6 +17,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderEnumerator; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectModelBuildableElement; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; @@ -55,6 +56,8 @@ import static java.util.stream.Collectors.groupingBy; */ public final class ProjectTaskManagerImpl extends ProjectTaskManager { private static final Logger LOG = Logger.getInstance(ProjectTaskManager.class); + private static final Key BUILD_ORIGINATOR_KEY = Key.create("project task build originator"); + private final ProjectTaskRunner myDummyTaskRunner = new DummyTaskRunner(); private final ProjectTaskListener myEventPublisher; private final List myListeners = new CopyOnWriteArrayList<>(); @@ -271,6 +274,11 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { if (modules.get() > 0) { fields.add(MODULES.with(modules.get())); } + String buildOriginator = BUILD_ORIGINATOR_KEY.get(myProject); + if (buildOriginator != null) { + myProject.putUserData(BUILD_ORIGINATOR_KEY, null); + fields.add(BUILD_ORIGINATOR.with(buildOriginator)); + } return BUILD_ACTIVITY.started(myProject, () -> fields); } @@ -306,6 +314,12 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { visitTasks(projectTask instanceof ProjectTaskList ? (ProjectTaskList)projectTask : Collections.singleton(projectTask), taskClassifier); } + public static void putBuildOriginator(@Nullable Project project, @NotNull Class clazz) { + if (BUILD_ORIGINATOR_KEY.get(project) == null) { + BUILD_ORIGINATOR_KEY.set(project, clazz.getName()); + } + } + @ApiStatus.Experimental public static @Nullable T waitForPromise(@NotNull Promise promise) { while (true) { diff --git a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt index b2dd6d3698cf..4637e90c3bcf 100644 --- a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt +++ b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt @@ -1,13 +1,10 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.task.impl import com.intellij.internal.statistic.IdeActivityDefinition import com.intellij.internal.statistic.collectors.fus.ClassNameRuleValidator import com.intellij.internal.statistic.eventLog.EventLogGroup -import com.intellij.internal.statistic.eventLog.events.BooleanEventField -import com.intellij.internal.statistic.eventLog.events.EventFields -import com.intellij.internal.statistic.eventLog.events.IntEventField -import com.intellij.internal.statistic.eventLog.events.StringListEventField +import com.intellij.internal.statistic.eventLog.events.* import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector class ProjectTaskManagerStatisticsCollector : CounterUsagesCollector() { @@ -23,12 +20,15 @@ class ProjectTaskManagerStatisticsCollector : CounterUsagesCollector() { @JvmField val INCREMENTAL: BooleanEventField = EventFields.Boolean("incremental") + @JvmField + val BUILD_ORIGINATOR: StringEventField = EventFields.StringValidatedByCustomRule("build_originator", ClassNameRuleValidator::class.java) + @JvmField val HAS_ERRORS: BooleanEventField = EventFields.Boolean("has_errors") @JvmField val BUILD_ACTIVITY: IdeActivityDefinition = GROUP.registerIdeActivity(null, - startEventAdditionalFields = arrayOf(TASK_RUNNER, EventFields.PluginInfo, MODULES, INCREMENTAL), + startEventAdditionalFields = arrayOf(TASK_RUNNER, EventFields.PluginInfo, MODULES, INCREMENTAL, BUILD_ORIGINATOR), finishEventAdditionalFields = arrayOf(HAS_ERRORS)) } diff --git a/platform/smart-update/intellij.smart.update.iml b/platform/smart-update/intellij.smart.update.iml index e4d06c974403..8a2a53783c5e 100644 --- a/platform/smart-update/intellij.smart.update.iml +++ b/platform/smart-update/intellij.smart.update.iml @@ -11,7 +11,7 @@ - + diff --git a/platform/smart-update/src/com/intellij/smartUpdate/BuildProjectStep.kt b/platform/smart-update/src/com/intellij/smartUpdate/BuildProjectStep.kt index c240ab807b5b..1271270eaba5 100644 --- a/platform/smart-update/src/com/intellij/smartUpdate/BuildProjectStep.kt +++ b/platform/smart-update/src/com/intellij/smartUpdate/BuildProjectStep.kt @@ -3,6 +3,7 @@ package com.intellij.smartUpdate import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.Project import com.intellij.task.ProjectTaskManager +import com.intellij.task.impl.ProjectTaskManagerImpl const val BUILD_PROJECT = "build.project" @@ -12,6 +13,7 @@ class BuildProjectStep: SmartUpdateStep { override fun performUpdateStep(project: Project, e: AnActionEvent?, onSuccess: () -> Unit) { val start = System.currentTimeMillis() + ProjectTaskManagerImpl.putBuildOriginator(project, this.javaClass) ProjectTaskManager.getInstance(project).buildAllModules().onSuccess { SmartUpdateUsagesCollector.logBuild(System.currentTimeMillis() - start, true) onSuccess.invoke() diff --git a/platform/warmup/src/com/intellij/warmup/PlatformBuildWarmupSupport.kt b/platform/warmup/src/com/intellij/warmup/PlatformBuildWarmupSupport.kt index 4f9059c84b20..4beedc390ae7 100644 --- a/platform/warmup/src/com/intellij/warmup/PlatformBuildWarmupSupport.kt +++ b/platform/warmup/src/com/intellij/warmup/PlatformBuildWarmupSupport.kt @@ -3,6 +3,7 @@ package com.intellij.warmup import com.intellij.openapi.project.Project import com.intellij.task.ProjectTaskManager +import com.intellij.task.impl.ProjectTaskManagerImpl import org.jetbrains.concurrency.asDeferred internal class PlatformBuildWarmupSupport(val project: Project) : ProjectBuildWarmupSupport { @@ -13,6 +14,7 @@ internal class PlatformBuildWarmupSupport(val project: Project) : ProjectBuildWa } override suspend fun buildProjectWithStatus(rebuild: Boolean): WarmupBuildStatus.InvocationStatus { + ProjectTaskManagerImpl.putBuildOriginator(project, this.javaClass) val projectTaskManager = ProjectTaskManager.getInstance(project) val result = (if (rebuild) projectTaskManager.rebuildAllModules() else projectTaskManager.buildAllModules()).asDeferred().await() diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java index 19463b46ed47..2db04ade1582 100644 --- a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java +++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.coverage; import com.intellij.CommonBundle; @@ -58,6 +58,7 @@ import com.intellij.rt.coverage.data.JumpData; import com.intellij.rt.coverage.data.LineData; import com.intellij.rt.coverage.data.SwitchData; import com.intellij.task.ProjectTaskManager; +import com.intellij.task.impl.ProjectTaskManagerImpl; import com.intellij.testIntegration.TestFramework; import com.intellij.util.containers.ContainerUtil; import jetbrains.coverage.report.ReportGenerationFailedException; @@ -359,6 +360,7 @@ public class JavaCoverageEngine extends CoverageEngine { JavaCoverageBundle.message("project.class.files.are.out.of.date"), NotificationType.INFORMATION); notification.addAction(NotificationAction.createSimpleExpiring(JavaCoverageBundle.message("coverage.recompile"), () -> { + ProjectTaskManagerImpl.putBuildOriginator(project, this.getClass()); ProjectTaskManager taskManager = ProjectTaskManager.getInstance(project); Promise promise = taskManager.buildAllModules(); promise.onSuccess(result -> ApplicationManager.getApplication().invokeLater(() -> { diff --git a/plugins/kotlin/jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt b/plugins/kotlin/jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt index 952489164ef9..06e805723880 100644 --- a/plugins/kotlin/jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt +++ b/plugins/kotlin/jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.scratch.actions @@ -8,6 +8,7 @@ import com.intellij.openapi.keymap.KeymapManager import com.intellij.openapi.keymap.KeymapUtil import com.intellij.openapi.project.DumbService import com.intellij.task.ProjectTaskManager +import com.intellij.task.impl.ProjectTaskManagerImpl import org.jetbrains.kotlin.idea.KotlinJvmBundle import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.configuration.CompositeScriptConfigurationManager @@ -64,6 +65,7 @@ class RunScratchAction : ScratchAction( log.printDebugMessage("Run Action: module = ${module?.name}") if (!isAutoRun && module != null && isMakeBeforeRun) { + ProjectTaskManagerImpl.putBuildOriginator(project, this.javaClass) ProjectTaskManager.getInstance(project).build(module).onSuccess { executionResult -> if (executionResult.isAborted || executionResult.hasErrors()) { executor.errorOccurs(KotlinJvmBundle.message("there.were.compilation.errors.in.module.0", module.name)) diff --git a/plugins/kotlin/repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt b/plugins/kotlin/repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt index c39c45eab70a..4553d1219e8c 100644 --- a/plugins/kotlin/repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt +++ b/plugins/kotlin/repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.console @@ -9,6 +9,7 @@ import com.intellij.openapi.compiler.CompilerManager import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.task.ProjectTaskManager +import com.intellij.task.impl.ProjectTaskManagerImpl class ConsoleCompilerHelper( private val project: Project, @@ -25,6 +26,7 @@ class ConsoleCompilerHelper( fun compileModule() { if (RunContentManager.getInstance(project).removeRunContent(executor, contentDescriptor)) { + ProjectTaskManagerImpl.putBuildOriginator(project, this.javaClass) ProjectTaskManager.getInstance(project).build(module).onSuccess { if (!module.isDisposed) { KotlinConsoleKeeper.getInstance(project).run(module, previousCompilationFailed = it.hasErrors()) From 1631715fd9de87a501c330da39a67ff3d41f41f8 Mon Sep 17 00:00:00 2001 From: Artem Khvastunov Date: Thu, 29 Jun 2023 17:32:23 +0200 Subject: [PATCH 193/226] IDEA-323982 duplicate data in build finished event It'd make it easier to access the data via UI. GitOrigin-RevId: 921de12722e10e58c251dc49b7ee9d29cee79b74 --- .../task/impl/ProjectTaskManagerImpl.java | 21 ++++++++++--------- .../ProjectTaskManagerStatisticsCollector.kt | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java index ac42df5f9f02..92fa56fc3b82 100644 --- a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java @@ -186,7 +186,7 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { }); - StructuredIdeActivity activity = reportBuildStart(projectTask, toRun); + Pair>> activity = reportBuildStart(projectTask, toRun); myEventPublisher.started(context); Runnable runnable = () -> { @@ -196,14 +196,14 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { } catch (ExecutionException e) { sendAbortedEmptyResult(context, new ResultConsumer(promiseResult)); - activity.finished(); + activity.first.finished(() -> activity.second); return; } } if (toRun.isEmpty()) { sendSuccessEmptyResult(context, new ResultConsumer(promiseResult)); - activity.finished(); + activity.first.finished(() -> activity.second); return; } @@ -242,9 +242,8 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { return promiseResult; } - @NotNull - private StructuredIdeActivity reportBuildStart(@NotNull ProjectTask projectTask, - List>> toRun) { + private Pair>> reportBuildStart(@NotNull ProjectTask projectTask, + List>> toRun) { Ref incremental = new Ref<>(null); AtomicInteger modules = new AtomicInteger(0); visitTask(projectTask, tasks -> { @@ -279,7 +278,7 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { myProject.putUserData(BUILD_ORIGINATOR_KEY, null); fields.add(BUILD_ORIGINATOR.with(buildOriginator)); } - return BUILD_ACTIVITY.started(myProject, () -> fields); + return Pair.create(BUILD_ACTIVITY.started(myProject, () -> fields), fields); } private List>> groupByRunner(@NotNull ProjectTask projectTask) { @@ -442,7 +441,7 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { private final ProjectTaskContext myContext; private final ResultConsumer myResultConsumer; private final AtomicInteger myProgressCounter; - private final StructuredIdeActivity myActivity; + private final Pair>> myActivity; private final AtomicBoolean myErrorsFlag; private final AtomicBoolean myAbortedFlag; private final Map myTasksState = new ConcurrentHashMap<>(); @@ -450,7 +449,7 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { private ProjectTaskResultsAggregator(@NotNull ProjectTaskContext context, @NotNull ResultConsumer resultConsumer, int expectedResults, - @NotNull StructuredIdeActivity activity) { + Pair>> activity) { myContext = context; myResultConsumer = resultConsumer; myProgressCounter = new AtomicInteger(expectedResults); @@ -487,7 +486,9 @@ public final class ProjectTaskManagerImpl extends ProjectTaskManager { myResultConsumer.accept(new MyResult(myContext, myTasksState, myAbortedFlag.get(), myErrorsFlag.get())); } finally { - myActivity.finished(() -> List.of(HAS_ERRORS.with(myErrorsFlag.get()))); + List> events = new ArrayList<>(myActivity.second); + events.add(HAS_ERRORS.with(myErrorsFlag.get())); + myActivity.first.finished(() -> events); } } } diff --git a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt index 4637e90c3bcf..f749e0fda768 100644 --- a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt +++ b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt @@ -29,7 +29,7 @@ class ProjectTaskManagerStatisticsCollector : CounterUsagesCollector() { @JvmField val BUILD_ACTIVITY: IdeActivityDefinition = GROUP.registerIdeActivity(null, startEventAdditionalFields = arrayOf(TASK_RUNNER, EventFields.PluginInfo, MODULES, INCREMENTAL, BUILD_ORIGINATOR), - finishEventAdditionalFields = arrayOf(HAS_ERRORS)) + finishEventAdditionalFields = arrayOf(TASK_RUNNER, MODULES, INCREMENTAL, BUILD_ORIGINATOR, HAS_ERRORS)) } override fun getGroup(): EventLogGroup { From bff43da650d0d8f1ae914079cffd68b27006680e Mon Sep 17 00:00:00 2001 From: Artem Khvastunov Date: Thu, 29 Jun 2023 17:34:57 +0200 Subject: [PATCH 194/226] IDEA-323982 increase collector version GitOrigin-RevId: 18de35d16b9e62e82f13255addc6fa42897a5578 --- .../intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt index f749e0fda768..236696973d44 100644 --- a/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt +++ b/platform/lang-impl/src/com/intellij/task/impl/ProjectTaskManagerStatisticsCollector.kt @@ -9,7 +9,7 @@ import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesColle class ProjectTaskManagerStatisticsCollector : CounterUsagesCollector() { companion object { - val GROUP: EventLogGroup = EventLogGroup("build", 6) + val GROUP: EventLogGroup = EventLogGroup("build", 7) @JvmField val TASK_RUNNER: StringListEventField = EventFields.StringListValidatedByCustomRule("task_runner_class", ClassNameRuleValidator::class.java) From b4cb4b1a440a50de4ae51d31b87036d9aa6b0e64 Mon Sep 17 00:00:00 2001 From: Piotr Tomiak Date: Mon, 3 Jul 2023 11:47:43 +0200 Subject: [PATCH 195/226] WEB-61784 WEB-61785 Support Svelte expressions within and