diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index b709ac255dd..0c9fdb15a8a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -481,7 +481,7 @@ public interface Errors { DiagnosticFactory1 UNINITIALIZED_PARAMETER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 UNUSED_VARIABLE = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); - DiagnosticFactory1 UNUSED_PARAMETER = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); + DiagnosticFactory1 UNUSED_PARAMETER = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); DiagnosticFactory1 ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.java index ae9e71ab143..d99ed320f93 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.java @@ -48,6 +48,6 @@ public class DuplicateJvmSignatureAnnotator implements Annotator { Diagnostics diagnostics = AsJavaPackage.getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope); if (diagnostics == null) return; - JetPsiChecker.annotateElement(element, holder, diagnostics); + new JetPsiChecker().annotateElement(element, holder, diagnostics); } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/JetPsiChecker.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/JetPsiChecker.kt index beb635067d3..d25e5d0d923 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/JetPsiChecker.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/JetPsiChecker.kt @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.* import org.jetbrains.kotlin.idea.quickfix.QuickFixes import kotlin.platform.platformStatic import org.jetbrains.kotlin.idea.kdoc.KDocHighlightingVisitor +import org.jetbrains.kotlin.psi.JetParameter public open class JetPsiChecker : Annotator, HighlightRangeExtension { @@ -71,7 +72,18 @@ public open class JetPsiChecker : Annotator, HighlightRangeExtension { return file is JetFile } - private class ElementAnnotator(private val element: PsiElement, private val holder: AnnotationHolder) { + open protected fun shouldSuppressUnusedParameter(parameter: JetParameter): Boolean = false + + fun annotateElement(element: PsiElement, holder: AnnotationHolder, diagnostics: Diagnostics) { + if (ProjectRootsUtil.isInProjectSource(element) || element.getContainingFile() is JetCodeFragment) { + val elementAnnotator = ElementAnnotator(element, holder) + for (diagnostic in diagnostics.forElement(element)) { + elementAnnotator.registerDiagnosticAnnotations(diagnostic) + } + } + } + + private inner class ElementAnnotator(private val element: PsiElement, private val holder: AnnotationHolder) { private var isMarkedWithRedeclaration = false fun registerDiagnosticAnnotations(diagnostic: Diagnostic) { @@ -130,6 +142,9 @@ public open class JetPsiChecker : Annotator, HighlightRangeExtension { } } Severity.WARNING -> { + if (factory == Errors.UNUSED_PARAMETER && shouldSuppressUnusedParameter(diagnostic.getPsiElement() as JetParameter)) { + return + } for (textRange in textRanges) { val annotation = holder.createWarningAnnotation(textRange, getDefaultMessage(diagnostic)) setUpAnnotation(diagnostic, annotation, if (factory in Errors.UNUSED_ELEMENT_DIAGNOSTICS) @@ -227,14 +242,5 @@ public open class JetPsiChecker : Annotator, HighlightRangeExtension { DeprecatedAnnotationVisitor(holder, bindingContext) ) - platformStatic fun annotateElement(element: PsiElement, holder: AnnotationHolder, diagnostics: Diagnostics) { - if (ProjectRootsUtil.isInProjectSource(element) || element.getContainingFile() is JetCodeFragment) { - val elementAnnotator = ElementAnnotator(element, holder) - for (diagnostic in diagnostics.forElement(element)) { - elementAnnotator.registerDiagnosticAnnotations(diagnostic) - } - } - } } - } diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/JetPsiCheckerAndHighlightingUpdater.java b/idea/src/org/jetbrains/kotlin/idea/highlighter/JetPsiCheckerAndHighlightingUpdater.java index 9fcf0b7d702..3b1daae1589 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/JetPsiCheckerAndHighlightingUpdater.java +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/JetPsiCheckerAndHighlightingUpdater.java @@ -20,7 +20,10 @@ import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection; import org.jetbrains.kotlin.psi.JetFile; +import org.jetbrains.kotlin.psi.JetNamedFunction; +import org.jetbrains.kotlin.psi.JetParameter; public class JetPsiCheckerAndHighlightingUpdater extends JetPsiChecker { @Override @@ -37,4 +40,14 @@ public class JetPsiCheckerAndHighlightingUpdater extends JetPsiChecker { throw e; } } + + @Override + protected boolean shouldSuppressUnusedParameter(@NotNull JetParameter parameter) { + PsiElement grandParent = parameter.getParent().getParent(); + if (grandParent instanceof JetNamedFunction) { + JetNamedFunction function = (JetNamedFunction) grandParent; + return UnusedSymbolInspection.Default.isEntryPoint(function); + } + return false; + } } diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt index e7a1def3b1a..2df0c100097 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt @@ -72,7 +72,23 @@ import java.awt.GridBagLayout import javax.swing.JPanel public class UnusedSymbolInspection : AbstractKotlinInspection() { - private val javaInspection = UnusedDeclarationInspection() + class object { + private val javaInspection = UnusedDeclarationInspection() + + public fun isEntryPoint(declaration: JetNamedDeclaration): Boolean { + // TODO Workaround for EA-64030 - IOE: PsiJavaParserFacadeImpl.createAnnotationFromText + // This should be fixed on IDEA side: ClsAnnotation should not throw exceptions when annotation class has Java keyword + if (declaration.getAnnotationEntries().any { it.getTypeReference().getText().endsWith("native") }) return false + if (ProjectStructureUtil.isJsKotlinModule(declaration.getContainingJetFile())) return false + + val lightElement: PsiElement? = when (declaration) { + is JetClassOrObject -> declaration.toLightClass() + is JetNamedFunction -> LightClassUtil.getLightClassMethod(declaration) + else -> return false + } + return lightElement != null && javaInspection.isEntryPoint(lightElement) + } + } override fun runForWholeFile() = true @@ -130,20 +146,6 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() { } } - private fun isEntryPoint(declaration: JetNamedDeclaration): Boolean { - // TODO Workaround for EA-64030 - IOE: PsiJavaParserFacadeImpl.createAnnotationFromText - // This should be fixed on IDEA side: ClsAnnotation should not throw exceptions when annotation class has Java keyword - if (declaration.getAnnotationEntries().any { it.getTypeReference().getText().endsWith("native") }) return false - if (ProjectStructureUtil.isJsKotlinModule(declaration.getContainingJetFile())) return false - - val lightElement: PsiElement? = when (declaration) { - is JetClassOrObject -> declaration.toLightClass() - is JetNamedFunction -> LightClassUtil.getLightClassMethod(declaration) - else -> return false - } - return lightElement != null && javaInspection.isEntryPoint(lightElement) - } - private fun classOrObjectHasTextUsages(classOrObject: JetClassOrObject): Boolean { var hasTextUsages = false diff --git a/idea/testData/checker/custom/noUnusedParameterWhenCustom.kt b/idea/testData/checker/custom/noUnusedParameterWhenCustom.kt new file mode 100644 index 00000000000..39555d10041 --- /dev/null +++ b/idea/testData/checker/custom/noUnusedParameterWhenCustom.kt @@ -0,0 +1,11 @@ +annotation class MyTestAnnotation + +fun unused(p: Int) { + +} + +[MyTestAnnotation] +fun unusedButAnnotated(p: Int) { + +} + diff --git a/idea/tests/org/jetbrains/kotlin/checkers/JetPsiCheckerCustomTest.kt b/idea/tests/org/jetbrains/kotlin/checkers/JetPsiCheckerCustomTest.kt new file mode 100644 index 00000000000..4fe4247271f --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/checkers/JetPsiCheckerCustomTest.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2015 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. + */ + +package org.jetbrains.kotlin.checkers + +import com.intellij.codeInspection.ex.EntryPointsManagerBase + +public class JetPsiCheckerCustomTest : AbstractJetPsiCheckerTest() { + public fun testNoUnusedParameterWhenCustom() { + val testAnnotation = "MyTestAnnotation" + EntryPointsManagerBase.getInstance(getProject()).ADDITIONAL_ANNOTATIONS.add(testAnnotation) + try { + doTest("idea/testData/checker/custom/NoUnusedParameterWhenCustom.kt") + } + finally { + EntryPointsManagerBase.getInstance(getProject()).ADDITIONAL_ANNOTATIONS.remove(testAnnotation) + } + } +} \ No newline at end of file