diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index b0662bd435f..0c968e96d01 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -671,8 +671,18 @@ class ControlFlowInformationProvider private constructor( val mainFunctionDetector = MainFunctionDetector(trace.bindingContext, languageVersionSettings) val isMain = owner is KtNamedFunction && mainFunctionDetector.isMain(owner) val functionName = functionDescriptor.name - if (isMain && !languageVersionSettings.supportsFeature(LanguageFeature.WarningOnMainUnusedParameter) - || functionDescriptor.isOverridableOrOverrides + if (isMain) { + when { + !languageVersionSettings.supportsFeature(LanguageFeature.ExtendedMainConvention) -> { + return + } + !languageVersionSettings.supportsFeature(LanguageFeature.WarningOnMainUnusedParameter) -> { + trace.record(UNUSED_MAIN_PARAMETER, element) + return + } + } + } + if (functionDescriptor.isOverridableOrOverrides || owner.hasModifier(KtTokens.OVERRIDE_KEYWORD) || OperatorNameConventions.GET_VALUE == functionName || OperatorNameConventions.SET_VALUE == functionName diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 51496fae653..371a2801419 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -103,6 +103,7 @@ public interface BindingContext { WritableSlice DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice(); WritableSlice BOUND_INITIALIZER_VALUE = Slices.createSimpleSlice(); WritableSlice LEAKING_THIS = Slices.createSimpleSlice(); + WritableSlice UNUSED_MAIN_PARAMETER = Slices.createSimpleSlice(); /** * A qualifier corresponds to a receiver expression (if any). For 'A.B' qualifier is recorded for 'A'. diff --git a/idea/resources/inspectionDescriptions/UnusedMainParameter.html b/idea/resources/inspectionDescriptions/UnusedMainParameter.html new file mode 100644 index 00000000000..0975f311a5e --- /dev/null +++ b/idea/resources/inspectionDescriptions/UnusedMainParameter.html @@ -0,0 +1,5 @@ + + +This inspection reports an unused main function parameter which is not necessary since Kotlin 1.3. + + diff --git a/idea/src/META-INF/plugin-common.xml b/idea/src/META-INF/plugin-common.xml index 0f6accf2392..6c6f3723a53 100644 --- a/idea/src/META-INF/plugin-common.xml +++ b/idea/src/META-INF/plugin-common.xml @@ -3075,6 +3075,15 @@ language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedMainParameterInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedMainParameterInspection.kt new file mode 100644 index 00000000000..4e9c44aeb97 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedMainParameterInspection.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-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/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.inspections + +import com.intellij.codeInspection.IntentionWrapper +import com.intellij.codeInspection.LocalInspectionToolSession +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent +import org.jetbrains.kotlin.idea.quickfix.RemoveUnusedFunctionParameterFix +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.psi.parameterVisitor +import org.jetbrains.kotlin.resolve.BindingContext.UNUSED_MAIN_PARAMETER + +class UnusedMainParameterInspection : AbstractKotlinInspection() { + + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = + parameterVisitor(fun(parameter: KtParameter) { + val function = parameter.ownerFunction as? KtNamedFunction ?: return + if (function.name != "main") return + val context = function.analyzeWithContent() + if (context[UNUSED_MAIN_PARAMETER, parameter] == true) { + holder.registerProblem( + parameter, + "Since Kotlin 1.3 main parameter is not necessary", + ProblemHighlightType.LIKE_UNUSED_SYMBOL, + IntentionWrapper(RemoveUnusedFunctionParameterFix(parameter), parameter.containingFile) + ) + } + }) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedMainParameter/.inspection b/idea/testData/inspectionsLocal/unusedMainParameter/.inspection new file mode 100644 index 00000000000..07508cc81ce --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedMainParameter/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.UnusedMainParameterInspection \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedMainParameter/future.kt b/idea/testData/inspectionsLocal/unusedMainParameter/future.kt new file mode 100644 index 00000000000..b4d5e298495 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedMainParameter/future.kt @@ -0,0 +1,6 @@ +// PROBLEM: none +// LANGUAGE_VERSION: 1.4 + +fun main(args: Array) { + +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedMainParameter/legacy.kt b/idea/testData/inspectionsLocal/unusedMainParameter/legacy.kt new file mode 100644 index 00000000000..21f7fe3e3ca --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedMainParameter/legacy.kt @@ -0,0 +1,6 @@ +// PROBLEM: none +// LANGUAGE_VERSION: 1.2 + +fun main(args: Array) { + +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedMainParameter/simple.kt b/idea/testData/inspectionsLocal/unusedMainParameter/simple.kt new file mode 100644 index 00000000000..c2a4c0037e0 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedMainParameter/simple.kt @@ -0,0 +1,5 @@ +// LANGUAGE_VERSION: 1.3 + +fun main(args: Array) { + +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedMainParameter/simple.kt.after b/idea/testData/inspectionsLocal/unusedMainParameter/simple.kt.after new file mode 100644 index 00000000000..556461dfbfe --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedMainParameter/simple.kt.after @@ -0,0 +1,5 @@ +// LANGUAGE_VERSION: 1.3 + +fun main() { + +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index a055bbf5613..292ee595071 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -6468,6 +6468,34 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/unusedMainParameter") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class UnusedMainParameter extends AbstractLocalInspectionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInUnusedMainParameter() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/unusedMainParameter"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("future.kt") + public void testFuture() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedMainParameter/future.kt"); + } + + @TestMetadata("legacy.kt") + public void testLegacy() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedMainParameter/legacy.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedMainParameter/simple.kt"); + } + } + @TestMetadata("idea/testData/inspectionsLocal/unusedReceiverParameter") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)