Allow to suppress kotlin inspections with Suppress() annotation

This commit is contained in:
Nikolay Krasko
2015-12-11 20:13:19 +03:00
committed by Nikolay Krasko
parent ef265e23f8
commit 36210f0a27
14 changed files with 161 additions and 11 deletions
@@ -20,36 +20,44 @@ import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.util.containers.SLRUCache
import org.jetbrains.kotlin.analyzer.EmptyResolverForProject
import org.jetbrains.kotlin.container.getService
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.psi.KtAnnotated
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.utils.keysToMap
internal val LOG = Logger.getInstance(javaClass<KotlinCacheService>())
internal val LOG = Logger.getInstance(KotlinCacheService::class.java)
public class KotlinCacheService(val project: Project) {
companion object {
@JvmStatic
public fun getInstance(project: Project): KotlinCacheService = ServiceManager.getService(project, javaClass<KotlinCacheService>())!!
public fun getInstance(project: Project): KotlinCacheService = ServiceManager.getService(project, KotlinCacheService::class.java)!!
}
public fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade {
return getFacadeToAnalyzeFiles(elements.map { it.getContainingKtFile() })
}
public fun getSuppressionCache(): KotlinSuppressCache = kotlinSuppressCache.value
private val globalFacadesPerPlatform = listOf(JvmPlatform, JsPlatform).keysToMap { platform -> GlobalFacade(platform) }
private inner class GlobalFacade(platform: TargetPlatform) {
@@ -147,6 +155,22 @@ public class KotlinCacheService(val project: Project) {
}
}
private val kotlinSuppressCache: CachedValue<KotlinSuppressCache> = CachedValuesManager.getManager(project).createCachedValue({
CachedValueProvider.Result<KotlinSuppressCache>(object : KotlinSuppressCache() {
override fun getSuppressionAnnotations(annotated: KtAnnotated): List<AnnotationDescriptor> {
val context = annotated.analyze(BodyResolveMode.PARTIAL)
val annotatedDescriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, annotated)
if (annotatedDescriptor != null) {
return annotatedDescriptor.annotations.toList()
}
else {
return annotated.annotationEntries.map { context.get(BindingContext.ANNOTATION, it) }.filterNotNull()
}
}
}, LibraryModificationTracker.getInstance(project), PsiModificationTracker.MODIFICATION_COUNT)
}, false)
private val syntheticFileCachesLock = Any()
private val slruCacheProvider = CachedValueProvider {
@@ -16,12 +16,15 @@
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.CustomSuppressableInspectionTool
import com.intellij.psi.PsiElement
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInsight.daemon.HighlightDisplayKey
import com.intellij.codeInspection.CustomSuppressableInspectionTool
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.SuppressIntentionAction
import com.intellij.codeInspection.SuppressManager
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.idea.caches.resolve.KotlinCacheService
public abstract class AbstractKotlinInspection: LocalInspectionTool(), CustomSuppressableInspectionTool {
public override fun getSuppressActions(element: PsiElement?): Array<SuppressIntentionAction>? {
@@ -29,6 +32,30 @@ public abstract class AbstractKotlinInspection: LocalInspectionTool(), CustomSup
}
public override fun isSuppressedFor(element: PsiElement): Boolean {
return SuppressManager.getInstance()!!.isSuppressedFor(element, getID())
if (SuppressManager.getInstance()!!.isSuppressedFor(element, getID())) {
return true
}
val project = element.project
if (KotlinCacheService.getInstance(project).getSuppressionCache().isSuppressed(element, this.shortName, toSeverity(defaultLevel))) {
return true
}
return false
}
public fun toSeverity(highlightDisplayLevel: HighlightDisplayLevel): Severity {
return when (highlightDisplayLevel) {
HighlightDisplayLevel.DO_NOT_SHOW -> Severity.INFO
HighlightDisplayLevel.WARNING,
HighlightDisplayLevel.WEAK_WARNING -> Severity.WARNING
HighlightDisplayLevel.ERROR,
HighlightDisplayLevel.GENERIC_SERVER_ERROR_OR_WARNING,
HighlightDisplayLevel.NON_SWITCHABLE_ERROR -> Severity.ERROR
else -> Severity.ERROR
}
}
}
@@ -91,7 +91,9 @@ public abstract class SelfTargetingIntention<TElement : KtElement>(
val inspection = findInspection(javaClass) ?: return false
val key = HighlightDisplayKey.find(inspection.shortName)
if (!InspectionProjectProfileManager.getInstance(project).getInspectionProfile(target).isToolEnabled(key)) return false
if (!InspectionProjectProfileManager.getInstance(project).getInspectionProfile(target).isToolEnabled(key)) {
return false
}
return inspection.intentions.single { it.intention.javaClass == javaClass }.additionalChecker(target)
}
@@ -1,8 +1,21 @@
class Klass {
fun unused() {
fun unusedFun() {
}
@Suppress("UnusedSymbol")
fun unusedNoWarn() {
}
}
@Suppress("UnusedSymbol")
class OtherKlass {
fun unusedNoWarn() {
}
}
fun main(args: Array<String>) {
Klass()
OtherKlass()
}
@@ -10,7 +10,7 @@
<problem>
<file>topLevelOnlyInImport.kt</file>
<line>5</line>
<line>6</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/topLevelOnlyInImport.kt" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
@@ -2,4 +2,16 @@ fun outer() {
fun local() {
}
@Suppress("UnusedSymbol")
fun localNoWarn() {
}
}
@Suppress("UnusedSymbol")
fun otherFun() {
fun localNoWarn() {
}
}
@@ -3,6 +3,9 @@ class Klass {
fun f() {
}
@Suppress("UnusedSymbol")
fun fNoWarn() {}
val p = 5
}
@@ -16,9 +19,21 @@ class Klass {
fun f() {
}
@Suppress("UnusedSymbol")
fun fNoWarn() {}
val p = 5
}
fun localObject3() = @Suppress("UnusedSymbol") object {
fun fNoWarn() {}
}
@Suppress("UnusedSymbol")
private val localObject4 = object {
fun fNoWarn() {}
}
init {
localObject2().f()
localObject2().p
@@ -39,5 +54,5 @@ class Klass {
}
fun main(args: Array<String>) {
Klass()
Klass().localObject3()
}
@@ -14,9 +14,17 @@ fun main(args: Array<String>) {
fun f() {
}
@Suppress("UnusedSymbol")
fun fNoWarn() {}
val p = 5
}
@Suppress("UnusedSymbol")
fun localObject3() = object {
fun fNoWarn() {}
}
localObject2().f()
localObject2().p
@@ -3,10 +3,25 @@ fun main(args: Array<String>) {
fun f() {
}
@Suppress("UnusedSymbol")
fun fNoWarn() {}
val p = 5
}
@Suppress("UnusedSymbol")
class OtherClass {
fun fNoWarn() {}
}
LocalClass().f()
LocalClass().p
}
@Suppress("UnusedSymbol")
fun other() {
class OtherClass {
fun fNoWarn() {}
}
}
@@ -1,7 +1,11 @@
package foo
import foo.onlyInImport
import foo.onlyInImportNoWarn
fun onlyInImport() {
}
@Suppress("UnusedSymbol")
fun onlyInImportNoWarn() {}
@@ -1,3 +1,6 @@
fun unused() {
fun unusedFun() {
}
@Suppress("UnusedSymbol")
fun unusedNoWarn() {}
@@ -1,3 +1,8 @@
fun usedOnlyRecursively() {
usedOnlyRecursively()
}
@Suppress("UnusedSymbol")
fun usedOnlyRecursivelyNoWarn() {
usedOnlyRecursivelyNoWarn()
}
@@ -7,3 +7,14 @@ fun test() {
i
}
}
fun withSuppression() {
class Test{
operator fun get(a: Int, b: Int, fn: (i: Int) -> Int) : Int = 0
}
val test = Test()
@Suppress("ReplaceGetOrSet")
test.get(1, 2) { i -> i }
}
@@ -7,3 +7,14 @@ fun test() {
i
}]
}
fun withSuppression() {
class Test{
operator fun get(a: Int, b: Int, fn: (i: Int) -> Int) : Int = 0
}
val test = Test()
@Suppress("ReplaceGetOrSet")
test.get(1, 2) { i -> i }
}