mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-07 05:09:37 +07:00
[kotlin] Run Kotlin JVM tests on both K1 and K2 frontend
#IDEA-354810 Fixed (cherry picked from commit d29d3256472dfe368161335732ded20ae95cf34e) IJ-MR-140910 GitOrigin-RevId: 0a9b3cae7aab473f732012ad91b4e67f97ff8697
This commit is contained in:
committed by
intellij-monorepo-bot
parent
db79e0d621
commit
72b748d5e0
@@ -0,0 +1,109 @@
|
||||
// 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.
|
||||
package com.intellij.codeInspection.tests.kotlin;
|
||||
|
||||
import com.intellij.codeInspection.blockingCallsDetection.BlockingMethodInNonBlockingContextInspection;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider;
|
||||
|
||||
import static com.intellij.codeInspection.blockingCallsDetection.BlockingMethodInNonBlockingContextInspection.DEFAULT_BLOCKING_ANNOTATIONS;
|
||||
import static com.intellij.codeInspection.blockingCallsDetection.BlockingMethodInNonBlockingContextInspection.DEFAULT_NONBLOCKING_ANNOTATIONS;
|
||||
|
||||
public abstract class KotlinBlockingCallDetectionTest extends JavaCodeInsightFixtureTestCase implements KotlinPluginModeProvider {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
BlockingMethodInNonBlockingContextInspection myInspection = new BlockingMethodInNonBlockingContextInspection();
|
||||
myInspection.myBlockingAnnotations = DEFAULT_BLOCKING_ANNOTATIONS;
|
||||
myInspection.myNonBlockingAnnotations = DEFAULT_NONBLOCKING_ANNOTATIONS;
|
||||
myFixture.enableInspections(myInspection);
|
||||
}
|
||||
|
||||
public void testKotlinAnnotationDetection() {
|
||||
myFixture.addClass("package org.jetbrains.annotations;\n" +
|
||||
"public @interface Blocking {}");
|
||||
myFixture.addClass("package org.jetbrains.annotations;\n" +
|
||||
"public @interface NonBlocking {}");
|
||||
myFixture.addFileToProject("/TestKotlinAnnotationDetection.kt",
|
||||
"""
|
||||
import org.jetbrains.annotations.Blocking
|
||||
import org.jetbrains.annotations.NonBlocking
|
||||
@NonBlocking
|
||||
fun nonBlockingFunction() {
|
||||
<warning descr="Possibly blocking call in non-blocking context could lead to thread starvation">blockingFunction</warning>();
|
||||
}
|
||||
@Blocking
|
||||
fun blockingFunction() {}""");
|
||||
|
||||
myFixture.testHighlighting(true, false, true, "TestKotlinAnnotationDetection.kt");
|
||||
}
|
||||
|
||||
public void testKotlinThrowsTypeDetection() {
|
||||
myFixture.addClass("package org.jetbrains.annotations;\n" +
|
||||
"public @interface NonBlocking {}");
|
||||
|
||||
myFixture.configureByText("/TestKotlinThrowsTypeDetection.kt",
|
||||
"""
|
||||
import org.jetbrains.annotations.NonBlocking
|
||||
import java.net.URL
|
||||
|
||||
@NonBlocking
|
||||
fun nonBlockingFunction() {
|
||||
Thread.<warning descr="Possibly blocking call in non-blocking context could lead to thread starvation">sleep</warning>(111);
|
||||
\s
|
||||
URL("https://example.com")
|
||||
}""");
|
||||
|
||||
myFixture.checkHighlighting(true, false, true);
|
||||
}
|
||||
|
||||
public void testDelegatingConstructor() {
|
||||
myFixture.addClass("package org.jetbrains.annotations;\n" +
|
||||
"public @interface Blocking {}");
|
||||
myFixture.addClass("package org.jetbrains.annotations;\n" +
|
||||
"public @interface NonBlocking {}");
|
||||
|
||||
myFixture.addClass("""
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
public class BlockingCtrClass {
|
||||
@Blocking
|
||||
BlockingCtrClass() {
|
||||
}
|
||||
|
||||
public static class Intermediate extends BlockingCtrClass {}
|
||||
}
|
||||
"""
|
||||
);
|
||||
|
||||
myFixture.configureByText("file.kt",
|
||||
"""
|
||||
import org.jetbrains.annotations.*
|
||||
|
||||
class NonBlockingCtrClass : BlockingCtrClass {
|
||||
@NonBlocking
|
||||
<warning descr="Possibly blocking call from implicit constructor call in non-blocking context could lead to thread starvation">constructor</warning>() {}
|
||||
}
|
||||
|
||||
class NonBlockingCtrClassWithIntermediate : BlockingCtrClass.Intermediate {
|
||||
@NonBlocking
|
||||
<warning descr="Possibly blocking call from implicit constructor call in non-blocking context could lead to thread starvation">constructor</warning>() {}
|
||||
}
|
||||
|
||||
class NonBlockingCtrClassExplicit @NonBlocking constructor() : <warning descr="Possibly blocking call in non-blocking context could lead to thread starvation">BlockingCtrClass</warning>()
|
||||
|
||||
class NonBlockingCtrClassExplicit2 : BlockingCtrClass {
|
||||
@NonBlocking
|
||||
constructor() : <warning descr="Possibly blocking call in non-blocking context could lead to thread starvation">super</warning>()
|
||||
}
|
||||
|
||||
open class KotlinBlockingCtr @Blocking constructor()
|
||||
|
||||
class NonBlockingCtr : KotlinBlockingCtr {
|
||||
@NonBlocking
|
||||
<warning descr="Possibly blocking call from implicit constructor call in non-blocking context could lead to thread starvation">constructor</warning>() {}
|
||||
}
|
||||
""");
|
||||
|
||||
myFixture.testHighlighting(true, false, true, "file.kt");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.CallMatcherTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import com.siyeh.ig.callMatcher.CallMatcher
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinCallMatcherTest : CallMatcherTestBase(), KotlinPluginModeProvider {
|
||||
fun testInstanceMethodCall() {
|
||||
checkMatchCall(JvmLanguage.KOTLIN, CallMatcher.instanceCall("Foo", "bar").parameterCount(0), """
|
||||
class Foo { fun bar() { } }
|
||||
|
||||
fun main() { Foo().bar() }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun testMultipleArgumentsCall() {
|
||||
checkMatchCall(JvmLanguage.KOTLIN, CallMatcher.instanceCall("Foo", "bar").parameterCount(3), """
|
||||
class Foo { fun bar(x: Int, y: Int, z: Int) { } }
|
||||
|
||||
fun main() { Foo().bar(0, 0, 0) }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun testMultipleArgumentsCallDefaultArg() {
|
||||
checkMatchCall(JvmLanguage.KOTLIN, CallMatcher.instanceCall("Foo", "bar").parameterCount(3), """
|
||||
class Foo { fun bar(x: Int, y: Int, z: Int = 0) { } }
|
||||
|
||||
fun main() { Foo().bar(0, 0) }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun testMultipleArgumentTypes() {
|
||||
checkMatchCall(JvmLanguage.KOTLIN, CallMatcher.instanceCall("Foo", "bar").parameterTypes("int", "long", "double"), """
|
||||
class Foo { fun bar(x: Int, y: Long, z: Double) { } }
|
||||
|
||||
fun main() { Foo().bar(0, 0L, 0.0) }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun testInstanceMethodReference() {
|
||||
checkMatchCallableReference(JvmLanguage.KOTLIN, CallMatcher.instanceCall("java.lang.String", "plus").parameterCount(1), """
|
||||
class Foo { fun bar(arg: String.(String) -> String) { } }
|
||||
|
||||
class Main { fun main() { Foo().bar(String::plus) } }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun testMethodReferenceArgumentTypes() {
|
||||
checkMatchCallableReference(JvmLanguage.KOTLIN, CallMatcher.instanceCall("java.lang.String", "plus").parameterTypes("java.lang.Object"), """
|
||||
class Foo { fun bar(arg: String.(String) -> String) { } }
|
||||
|
||||
class Main { fun main() { Foo().bar(String::plus) } }
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.DependencyInspectionTestBase
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinDependencyInspectionTest : DependencyInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test illegal imported dependency Java API`() = dependencyViolationTest(javaFooFile, "ImportClientJava.kt", """
|
||||
package pkg.client
|
||||
|
||||
import <error descr="Dependency rule 'Deny usages of scope 'JavaFoo' in scope 'ImportClientJava'.' is violated">pkg.api.JavaFoo</error>
|
||||
|
||||
fun main() {
|
||||
<error descr="Dependency rule 'Deny usages of scope 'JavaFoo' in scope 'ImportClientJava'.' is violated">JavaFoo()</error>
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
fun `test illegal imported dependency Kotlin API`() = dependencyViolationTest(kotlinFooFile, "ImportClientKotlin.kt", """
|
||||
package pkg.client
|
||||
|
||||
import <error descr="Dependency rule 'Deny usages of scope 'KotlinFoo' in scope 'ImportClientKotlin'.' is violated">pkg.api.KotlinFoo</error>
|
||||
|
||||
fun main() {
|
||||
<error descr="Dependency rule 'Deny usages of scope 'KotlinFoo' in scope 'ImportClientKotlin'.' is violated">KotlinFoo()</error>
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
fun `test illegal imported dependency skip imports`() = dependencyViolationTest(kotlinFooFile, "ImportClientKotlin.kt", """
|
||||
package pkg.client
|
||||
|
||||
import pkg.api.KotlinFoo
|
||||
|
||||
fun main() {
|
||||
<error descr="Dependency rule 'Deny usages of scope 'KotlinFoo' in scope 'ImportClientKotlin'.' is violated">KotlinFoo()</error>
|
||||
}
|
||||
""".trimIndent(), skipImports = true)
|
||||
|
||||
fun `test illegal imported dependency Kotlin API in Java`() = dependencyViolationTest(kotlinFooFile, "ImportClientKotlin.java", """
|
||||
package pkg.client;
|
||||
|
||||
import <error descr="Dependency rule 'Deny usages of scope 'KotlinFoo' in scope 'ImportClientKotlin'.' is violated">pkg.api.KotlinFoo</error>;
|
||||
|
||||
class Client {
|
||||
public static void main(String[] args) {
|
||||
new <error descr="Dependency rule 'Deny usages of scope 'KotlinFoo' in scope 'ImportClientKotlin'.' is violated">KotlinFoo</error>();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
fun `test illegal fully qualified dependency Java API`() = dependencyViolationTest(javaFooFile, "FqClientJava.kt", """
|
||||
package pkg.client
|
||||
|
||||
fun main() {
|
||||
<error descr="Dependency rule 'Deny usages of scope 'JavaFoo' in scope 'FqClientJava'.' is violated">pkg.api.JavaFoo()</error>
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
fun `test illegal fully qualified dependency Kotlin API`() = dependencyViolationTest(kotlinFooFile, "FqClientKotlin.kt", """
|
||||
package pkg.client
|
||||
|
||||
fun main() {
|
||||
<error descr="Dependency rule 'Deny usages of scope 'KotlinFoo' in scope 'FqClientKotlin'.' is violated">pkg.api.KotlinFoo()</error>
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
fun `test illegal fully qualified dependency Kotlin API in Java`() = dependencyViolationTest(kotlinFooFile, "FqClientKotlin.java", """
|
||||
package pkg.client;
|
||||
|
||||
class Client {
|
||||
public static void main(String[] args) {
|
||||
new <error descr="Dependency rule 'Deny usages of scope 'KotlinFoo' in scope 'FqClientKotlin'.' is violated">pkg.api.KotlinFoo</error>();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.codeInspection.emptyMethod.EmptyMethodInspection
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.jvm.analysis.testFramework.JvmInspectionTestBase
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
private const val inspectionPath = "/codeInspection/emptyMethod"
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData$inspectionPath")
|
||||
abstract class KotlinEmptyMethodInspectionTest : JvmInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override var inspection = EmptyMethodInspection()
|
||||
|
||||
override fun getBasePath() = KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + inspectionPath
|
||||
|
||||
fun `test basic`() {
|
||||
myFixture.testInspection("basic", GlobalInspectionToolWrapper(inspection))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.JavaApiUsageInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinJavaApiUsageInspectionTest : JavaApiUsageInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test constructor`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_4)
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
fun foo() {
|
||||
throw <error descr="Usage of API documented as @since 1.5+">IllegalArgumentException</error>("", RuntimeException());
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test ignored`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
myFixture.addClass("""
|
||||
package java.awt.geom;
|
||||
|
||||
public class GeneralPath {
|
||||
public void moveTo(int x, int y) { }
|
||||
}
|
||||
""".trimIndent())
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.awt.geom.GeneralPath
|
||||
|
||||
fun foo() {
|
||||
val path = GeneralPath()
|
||||
path.moveTo(0, 0)
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test qualified reference`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
fun main() {
|
||||
<error descr="Usage of API documented as @since 1.7+">StandardCharsets</error>.UTF_8
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test reference in callable reference`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
val withErrorMessage = "\"default charset \${<error descr=\"Usage of API documented as @since 1.7+\">StandardCharsets</error>.UTF_8}\"::toString"
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
fun main() {
|
||||
${withErrorMessage}
|
||||
}
|
||||
""".trimIndent())
|
||||
""::toString
|
||||
}
|
||||
|
||||
fun `test annotation`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
@file:Suppress("UNUSED_PARAMETER")
|
||||
|
||||
class Annotation {
|
||||
@<error descr="Usage of API documented as @since 1.7+">SafeVarargs</error>
|
||||
fun foo(vararg ls: List<String>) { }
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test override annotation`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
import java.util.Map
|
||||
|
||||
abstract class OverrideAnnotation : Map<String, String> {
|
||||
override fun <error descr="Usage of API documented as @since 1.8+">getOrDefault</error>(key: Any?, defaultValue: String?): String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test default methods`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNUSED_VARIABLE")
|
||||
import java.util.Iterator
|
||||
|
||||
class <error descr="Default method 'remove' is not overridden. It would cause compilation problems with JDK 6">DefaultMethods</error> : Iterator<String> {
|
||||
override fun hasNext(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun next(): String {
|
||||
return ""
|
||||
}
|
||||
|
||||
class T : Iterator<String> {
|
||||
override fun hasNext(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun next(): String {
|
||||
return ""
|
||||
}
|
||||
|
||||
override fun remove() { }
|
||||
}
|
||||
|
||||
init {
|
||||
val it = <error descr="Default method 'remove' is not overridden. It would cause compilation problems with JDK 6">object</error> : Iterator<String> {
|
||||
override fun hasNext(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun next(): String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test single method multiple overrides`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class CustomList : java.util.AbstractList<Int>() {
|
||||
override val size: Int = 0
|
||||
|
||||
override fun get(index: Int): Int = 0
|
||||
|
||||
override fun <error descr="Usage of API documented as @since 1.8+">spliterator</error>(): java.util.<error descr="Usage of API documented as @since 1.8+">Spliterator</error><Int> =
|
||||
java.util.<error descr="Usage of API documented as @since 1.8+">Spliterators</error>.spliterator(this, 0)
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test raw inherit from newly generified`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
myFixture.addClass("""
|
||||
package javax.swing;
|
||||
|
||||
public class AbstractListModel<K> {}
|
||||
""".trimIndent())
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class RawInheritFromNewlyGenerified {
|
||||
private lateinit var myModel: AbstractCCM<String>
|
||||
}
|
||||
|
||||
abstract class AbstractCCM<T> : javax.swing.AbstractListModel<String>() { }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test generified`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_6)
|
||||
myFixture.addClass("""
|
||||
package javax.swing;
|
||||
|
||||
public interface ListModel<E> { }
|
||||
""".trimIndent())
|
||||
myFixture.addClass("""
|
||||
package javax.swing;
|
||||
|
||||
public class AbstractListModel<K> implements ListModel<E> { }
|
||||
""".trimIndent())
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import javax.swing.AbstractListModel
|
||||
|
||||
abstract class AbstractCCM<T> : <error descr="Usage of generified after 1.6 API which would cause compilation problems with JDK 6">AbstractListModel</error><T>() { }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test no highlighting in kdoc`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_1_7)
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class Javadoc {
|
||||
/**
|
||||
* [java.util.function.Predicate]
|
||||
*/
|
||||
fun test() {
|
||||
return
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.codeInspection.deprecation.MarkedForRemovalInspection
|
||||
import com.intellij.jvm.analysis.testFramework.JvmInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinMarkedForRemovalInspectionTest : JvmInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test highlighted as deprecated for removal`() {
|
||||
myFixture.addClass("""
|
||||
package test;
|
||||
@Deprecated(forRemoval = true)
|
||||
class MyTest {}
|
||||
""".trimIndent())
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
package test
|
||||
fun main() {
|
||||
<error descr="'test.MyTest' is deprecated and marked for removal"><warning descr="[DEPRECATION] 'MyTest' is deprecated. Deprecated in Java">MyTest</warning></error>()
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
override val inspection = MarkedForRemovalInspection()
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.MigrationTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import com.intellij.refactoring.migration.MigrationMapEntry
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinMigrationTest : MigrationTestBase(), KotlinPluginModeProvider {
|
||||
fun `test package`() {
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
package p1
|
||||
|
||||
import qqq.AAA
|
||||
|
||||
class C {
|
||||
val a = AAA()
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
package p1
|
||||
|
||||
import jetbrains.test.AAA
|
||||
|
||||
class C {
|
||||
val a = AAA()
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("qqq", "jetbrains.test", MigrationMapEntry.PACKAGE, true)
|
||||
)
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
package p1
|
||||
|
||||
import qqq.*
|
||||
|
||||
class C {
|
||||
val a = qqq.AAA()
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
package p1
|
||||
|
||||
import jetbrains.test.*
|
||||
|
||||
class C {
|
||||
val a = jetbrains.test.AAA()
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("qqq", "jetbrains.test", MigrationMapEntry.PACKAGE, true)
|
||||
)
|
||||
}
|
||||
|
||||
fun `test package migration with non existing package`() {
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
package p1
|
||||
|
||||
import qqq.AAA
|
||||
|
||||
class C {
|
||||
val a = AAA()
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
package p1
|
||||
|
||||
import zzz.bbb.AAA
|
||||
|
||||
class C {
|
||||
val a = AAA()
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("qqq", "zzz.bbb", MigrationMapEntry.PACKAGE, true)
|
||||
)
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
package p1
|
||||
|
||||
import qqq.*
|
||||
|
||||
class C {
|
||||
val a = qqq.AAA()
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
package p1
|
||||
|
||||
import zzz.bbb.*
|
||||
|
||||
class C {
|
||||
val a = zzz.bbb.AAA()
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("qqq", "zzz.bbb", MigrationMapEntry.PACKAGE, true)
|
||||
)
|
||||
}
|
||||
|
||||
fun `test two classes`() {
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
class A {}
|
||||
class A1 {}
|
||||
|
||||
class B {}
|
||||
class B1 {}
|
||||
|
||||
public class Test {
|
||||
val a: A
|
||||
val b: B
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
class A {}
|
||||
class A1 {}
|
||||
|
||||
class B {}
|
||||
class B1 {}
|
||||
|
||||
public class Test {
|
||||
val a: A1
|
||||
val b: B1
|
||||
}
|
||||
""".trimIndent(),
|
||||
MigrationMapEntry("A", "A1", MigrationMapEntry.CLASS, true),
|
||||
MigrationMapEntry("B", "B1", MigrationMapEntry.CLASS, true)
|
||||
)
|
||||
}
|
||||
|
||||
fun `test two non existent classes`() {
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
package p1
|
||||
|
||||
import qqq.aaa.XXX
|
||||
|
||||
class C {
|
||||
val you = XXX()
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
package p1
|
||||
|
||||
import zzz.bbb.QQQ
|
||||
|
||||
class C {
|
||||
val you = QQQ()
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("qqq.aaa.XXX", "zzz.bbb.QQQ", MigrationMapEntry.CLASS, false)
|
||||
)
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
package p1
|
||||
|
||||
import qqq.aaa.*
|
||||
|
||||
class C1 {
|
||||
val you = XXX()
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
package p1
|
||||
|
||||
import qqq.aaa.*
|
||||
import zzz.bbb.QQQ
|
||||
|
||||
class C1 {
|
||||
val you = QQQ()
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("qqq.aaa.XXX", "zzz.bbb.QQQ", MigrationMapEntry.CLASS, false)
|
||||
)
|
||||
}
|
||||
|
||||
fun `test non existing class and non existing package`() {
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
package p1
|
||||
|
||||
import qqq.aaa.XXX
|
||||
|
||||
class C {
|
||||
val you = XXX()
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
package p1
|
||||
|
||||
import java.lang.String
|
||||
|
||||
class C {
|
||||
val you = String()
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("qqq.aaa.XXX", "java.lang.String", MigrationMapEntry.CLASS, false)
|
||||
)
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
package p1
|
||||
|
||||
import qqq.aaa.*
|
||||
|
||||
class C1 {
|
||||
val you = XXX()
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
package p1
|
||||
|
||||
import java.lang.String
|
||||
|
||||
class C1 {
|
||||
val you = String()
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("qqq.aaa.XXX", "java.lang.String", MigrationMapEntry.CLASS, false)
|
||||
)
|
||||
}
|
||||
|
||||
fun `test same short name class`() {
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
import aaa.*
|
||||
|
||||
public class C {
|
||||
@Test
|
||||
fun foo() { }
|
||||
|
||||
@Test
|
||||
fun bar() { }
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
import aaa.*
|
||||
import bbb.Test
|
||||
|
||||
public class C {
|
||||
@Test
|
||||
fun foo() { }
|
||||
|
||||
@Test
|
||||
fun bar() { }
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("aaa.Test", "bbb.Test", MigrationMapEntry.CLASS, false)
|
||||
)
|
||||
migrationTest(JvmLanguage.KOTLIN, before = """
|
||||
import aaa.Test
|
||||
|
||||
public class C1 {
|
||||
@Test
|
||||
fun foo() { }
|
||||
|
||||
@Test
|
||||
fun bar() { }
|
||||
}
|
||||
""".trimIndent(), after = """
|
||||
import bbb.Test
|
||||
|
||||
public class C1 {
|
||||
@Test
|
||||
fun foo() { }
|
||||
|
||||
@Test
|
||||
fun bar() { }
|
||||
}
|
||||
""".trimIndent(), MigrationMapEntry("aaa.Test", "bbb.Test", MigrationMapEntry.CLASS, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.jvm.analysis.internal.testFramework.MissingDeprecatedAnnotationOnScheduledForRemovalApiInspectionTestBase
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
private const val inspectionPath = "/codeInspection/missingDeprecatedAnnotationOnScheduledForRemovalApi"
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData$inspectionPath")
|
||||
abstract class KotlinMissingDeprecatedAnnotationOnScheduledForRemovalApiInspectionTest : MissingDeprecatedAnnotationOnScheduledForRemovalApiInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override fun getBasePath() = KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + inspectionPath
|
||||
|
||||
fun `test missing @Deprecated on @ScheduledForRemoval APIs`() {
|
||||
myFixture.testHighlighting("missingDeprecatedAnnotations.kt")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.MustAlreadyBeRemovedApiInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinMustAlreadyBeRemovedApiInspectionTest : MustAlreadyBeRemovedApiInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test APIs must have been removed`() {
|
||||
inspection.currentVersion = "3.0"
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
|
||||
@Deprecated("")
|
||||
class <error descr="API must have been removed in version 2.0 but the current version is 3.0">Warnings</error> {
|
||||
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
|
||||
@Deprecated("")
|
||||
var <error descr="API must have been removed in version 2.0 but the current version is 3.0">field</error>: String? = null
|
||||
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
|
||||
@Deprecated("")
|
||||
fun <error descr="API must have been removed in version 2.0 but the current version is 3.0">method</error>() {
|
||||
}
|
||||
}
|
||||
|
||||
//No warnings should be produced.
|
||||
|
||||
@Deprecated("")
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "5.0")
|
||||
class NoWarnings {
|
||||
|
||||
@Deprecated("")
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "5.0")
|
||||
var field: String? = null
|
||||
|
||||
@Deprecated("")
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "5.0")
|
||||
fun method() {
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.codeInspection.NonExtendableApiUsageInspection
|
||||
import com.intellij.jvm.analysis.testFramework.JvmInspectionTestBase
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
@TestDataPath("/testData/codeInspection/nonExtendableApiUsage")
|
||||
abstract class KotlinNonExtendableApiUsageInspectionTest : JvmInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override val inspection = NonExtendableApiUsageInspection()
|
||||
|
||||
override fun getProjectDescriptor() = object : ProjectDescriptor(LanguageLevel.HIGHEST) {
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
super.configureModule(module, model, contentEntry)
|
||||
PsiTestUtil.addProjectLibrary(model, "annotations", listOf(PathUtil.getJarPathForClass(ApiStatus.NonExtendable::class.java)))
|
||||
PsiTestUtil.addProjectLibrary(model, "library", listOf(testDataPath))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBasePath() = "/jvm/jvm-analysis-kotlin-tests-shared/testData/codeInspection/nonExtendableApiUsage"
|
||||
|
||||
fun `test java extensions`() {
|
||||
myFixture.testHighlighting("plugin/javaExtensions.java")
|
||||
}
|
||||
|
||||
fun `test kotlin extensions`() {
|
||||
myFixture.allowTreeAccessForAllFiles()
|
||||
myFixture.testHighlighting("plugin/kotlinExtensions.kt")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.intellij.codeInspection.tests.kotlin;
|
||||
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
import com.intellij.util.PathUtil;
|
||||
import kotlin.KotlinVersion;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider;
|
||||
import org.jetbrains.uast.ULiteralExpression;
|
||||
import org.junit.Assume;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.codeInspection.NonNlsUastUtil.isNonNlsStringLiteral;
|
||||
import static com.intellij.jvm.analysis.internal.testFramework.JvmAnalysisTestsUastUtil.getUElementsOfTypeFromFile;
|
||||
|
||||
@TestDataPath("$CONTENT_ROOT/testData/codeInspection/nonNls")
|
||||
public abstract class KotlinNonNlsUastUtilTest extends JavaCodeInsightFixtureTestCase implements KotlinPluginModeProvider {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Assume.assumeTrue(KotlinVersion.CURRENT.isAtLeast(1, 2, 60));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + "/codeInspection/nonNls";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PathManager.getCommunityHomePath().replace(File.separatorChar, '/') + getBasePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) {
|
||||
moduleBuilder.addLibrary("annotations", PathUtil.getJarPathForClass(NonNls.class));
|
||||
}
|
||||
|
||||
public void testNonNlsStringLiterals() {
|
||||
PsiFile file = myFixture.configureByFile("NonNlsStringLiteral.kt");
|
||||
Set<ULiteralExpression> expressions = getUElementsOfTypeFromFile(file, ULiteralExpression.class);
|
||||
assertSize(20, expressions); // multiline string literal is processed as 4 string literals
|
||||
expressions.forEach(expression -> assertTrue("\"" + expression.getSourcePsi().getText() + "\" should be a NonNls StringLiteral",
|
||||
isNonNlsStringLiteral(expression)));
|
||||
}
|
||||
|
||||
public void testPlainStringLiterals() {
|
||||
PsiFile file = myFixture.configureByFile("PlainStringLiteral.kt");
|
||||
Set<ULiteralExpression> expressions = getUElementsOfTypeFromFile(file, ULiteralExpression.class);
|
||||
assertSize(9, expressions);
|
||||
expressions.forEach(expression -> assertFalse(isNonNlsStringLiteral(expression)));
|
||||
}
|
||||
|
||||
public void testLiteralsInNonNlsClass() {
|
||||
PsiFile file = myFixture.configureByFile("LiteralsInNonNlsClass.kt");
|
||||
Set<ULiteralExpression> expressions = getUElementsOfTypeFromFile(file, ULiteralExpression.class);
|
||||
assertSize(8, expressions);
|
||||
expressions.forEach(expression -> assertTrue(isNonNlsStringLiteral(expression)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.ObsoleteApiUsageInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinObsoleteApiUsageInspectionTest : ObsoleteApiUsageInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test direct usage`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class B {
|
||||
fun f(a: A) {
|
||||
a.<warning descr="Obsolete API is used">f</warning>();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test override`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class C : A() {
|
||||
override fun <warning descr="Obsolete API is used">f</warning>() { }
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.ApiStatus.Obsolete
|
||||
class D : A() {
|
||||
override fun <warning descr="Obsolete API is used">f</warning>() { }
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test generic reference`() {
|
||||
myFixture.addClass("@org.jetbrains.annotations.ApiStatus.Obsolete public interface I<T> {}")
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class U {
|
||||
fun u(i: <warning descr="Obsolete API is used">I</warning><Int>) = i
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry
|
||||
import com.intellij.codeInspection.OverrideOnlyInspection
|
||||
import com.intellij.jvm.analysis.testFramework.JvmInspectionTestBase
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
@TestDataPath("/testData/codeInspection/overrideOnly")
|
||||
abstract class KotlinOverrideOnlyInspectionTest : JvmInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override val inspection: InspectionProfileEntry = OverrideOnlyInspection()
|
||||
|
||||
override fun getProjectDescriptor() = object : ProjectDescriptor(LanguageLevel.HIGHEST) {
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
super.configureModule(module, model, contentEntry)
|
||||
PsiTestUtil.addProjectLibrary(model, "annotations", listOf(PathUtil.getJarPathForClass(ApiStatus.OverrideOnly::class.java)))
|
||||
PsiTestUtil.addProjectLibrary(model, "library", listOf(testDataPath))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBasePath() = "/jvm/jvm-analysis-kotlin-tests-shared/testData/codeInspection/overrideOnly"
|
||||
|
||||
fun `test java invocations`() {
|
||||
myFixture.testHighlighting("plugin/JavaCode.java")
|
||||
}
|
||||
|
||||
fun `test kotlin invocations`() {
|
||||
myFixture.allowTreeAccessForAllFiles()
|
||||
myFixture.testHighlighting("plugin/KotlinCode.kt")
|
||||
}
|
||||
|
||||
fun `test java delegation`() {
|
||||
myFixture.testHighlighting("plugin/DelegateJavaCode.java")
|
||||
}
|
||||
|
||||
fun `test kotlin delegation`() {
|
||||
myFixture.allowTreeAccessForAllFiles()
|
||||
myFixture.testHighlighting("plugin/DelegateKotlinCode.kt")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.analysis.AnalysisScope
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper
|
||||
import com.intellij.codeInspection.java19modules.Java9RedundantRequiresStatementInspection
|
||||
import com.intellij.java.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase
|
||||
import com.intellij.java.testFramework.fixtures.MultiModuleJava9ProjectDescriptor
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.testFramework.InspectionTestUtil
|
||||
import com.intellij.testFramework.createGlobalContextForTool
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
import java.io.File
|
||||
|
||||
abstract class KotlinRedundantRequiresStatementTest : LightJava9ModulesCodeInsightFixtureTestCase(), KotlinPluginModeProvider {
|
||||
fun testStdlib() {
|
||||
val mainText = """
|
||||
package org.example.main
|
||||
class Main {
|
||||
fun main() {}
|
||||
}""".trimIndent()
|
||||
addFile("org.example.main/Main.kt", mainText)
|
||||
addFile("module-info.java", "module MAIN { requires kotlin.stdlib; }", MultiModuleJava9ProjectDescriptor.ModuleDescriptor.MAIN)
|
||||
|
||||
val toolWrapper = GlobalInspectionToolWrapper(Java9RedundantRequiresStatementInspection())
|
||||
val scope = AnalysisScope(project)
|
||||
val globalContext = createGlobalContextForTool(scope, project, listOf(toolWrapper))
|
||||
InspectionTestUtil.runTool(toolWrapper, scope, globalContext)
|
||||
InspectionTestUtil.compareToolResults(globalContext, toolWrapper, true, testDataPath + getTestName(true))
|
||||
}
|
||||
|
||||
override fun getBasePath(): String {
|
||||
return KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + "/codeInspection/redundantRequires/"
|
||||
}
|
||||
|
||||
override fun getTestDataPath(): String {
|
||||
return PathManager.getCommunityHomePath().replace(File.separatorChar, '/') + basePath
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.SameParameterValueInspectionTestBase
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinSameParameterValueGlobalInspectionTest : SameParameterValueInspectionTestBase(false), KotlinPluginModeProvider {
|
||||
fun testEntryPoint() {
|
||||
doHighlightTest(runDeadCodeFirst = true)
|
||||
}
|
||||
|
||||
fun testMethodWithSuper() {
|
||||
doHighlightTest()
|
||||
}
|
||||
|
||||
fun testVarargs() {
|
||||
doHighlightTest()
|
||||
}
|
||||
|
||||
fun testNamedArg() {
|
||||
doHighlightTest()
|
||||
}
|
||||
|
||||
fun testNegativeDouble() {
|
||||
doHighlightTest()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.SameParameterValueInspectionTestBase
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinSameParameterValueLocalInspectionTest : SameParameterValueInspectionTestBase(true), KotlinPluginModeProvider {
|
||||
fun testEntryPoint() {
|
||||
doHighlightTest(runDeadCodeFirst = true)
|
||||
}
|
||||
|
||||
fun testMethodWithSuper() {
|
||||
doHighlightTest()
|
||||
}
|
||||
|
||||
fun testVarargs() {
|
||||
doHighlightTest()
|
||||
}
|
||||
|
||||
fun testNamedArg() {
|
||||
doHighlightTest()
|
||||
}
|
||||
|
||||
fun testNegativeDouble() {
|
||||
doHighlightTest()
|
||||
}
|
||||
|
||||
fun testReceiver() {
|
||||
doHighlightTest()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.intellij.codeInspection.tests.kotlin;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInspection.sameReturnValue.SameReturnValueInspection;
|
||||
import com.intellij.testFramework.JavaInspectionTestCase;
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider;
|
||||
|
||||
public abstract class KotlinSameReturnValueGlobalInspectionTest extends JavaInspectionTestCase implements KotlinPluginModeProvider {
|
||||
private final SameReturnValueInspection myGlobalTool = new SameReturnValueInspection();
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/inspection/jvm";
|
||||
}
|
||||
|
||||
private String getGlobalTestDir() {
|
||||
return "sameReturnValue/" + getTestName(true);
|
||||
}
|
||||
|
||||
public void testJava() {
|
||||
doTest(getGlobalTestDir(), myGlobalTool);
|
||||
}
|
||||
|
||||
public void testKotlin() {
|
||||
doTest(getGlobalTestDir(), myGlobalTool);
|
||||
}
|
||||
|
||||
public void testMixed() {
|
||||
doTest(getGlobalTestDir(), myGlobalTool);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.intellij.codeInspection.tests.kotlin;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInspection.sameReturnValue.SameReturnValueInspection;
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider;
|
||||
|
||||
public abstract class KotlinSameReturnValueLocalInspectionTest extends LightJavaCodeInsightFixtureTestCase implements KotlinPluginModeProvider {
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/inspection/sameReturnValue/";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.enableInspections(new SameReturnValueInspection().getSharedLocalInspectionTool());
|
||||
}
|
||||
|
||||
public void testJava() {
|
||||
myFixture.testHighlighting(getTestName(false) + ".java");
|
||||
}
|
||||
|
||||
public void testKotlin() {
|
||||
myFixture.testHighlighting(getTestName(false) + ".kt");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.SerializableHasSerialVersionUidFieldInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.IdeaTestUtil
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinSerializableHasSerialVersionUidFieldInspectionTest : SerializableHasSerialVersionUidFieldInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test highlighting`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.io.Serializable
|
||||
|
||||
class <warning descr="'Foo' does not define a 'serialVersionUID' field">Foo</warning> : Serializable { }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test quickfix`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_11)
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
import java.io.Serializable
|
||||
|
||||
class Fo<caret>o : Serializable { }
|
||||
""".trimIndent(), """
|
||||
import java.io.Serializable
|
||||
|
||||
class Foo : Serializable {
|
||||
companion object {
|
||||
private const val serialVersionUID: Long = 7429157667498829299L
|
||||
}
|
||||
}
|
||||
""".trimIndent(), "Add 'const val' property 'serialVersionUID' to 'Foo'")
|
||||
}
|
||||
|
||||
fun `test quickfix companion exists`() {
|
||||
myFixture.setLanguageLevel(LanguageLevel.JDK_11)
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
import java.io.Serializable
|
||||
|
||||
class Fo<caret>o : Serializable {
|
||||
companion object {
|
||||
val bar = 0
|
||||
}
|
||||
}
|
||||
""".trimIndent(), """
|
||||
import java.io.Serializable
|
||||
|
||||
class Foo : Serializable {
|
||||
companion object {
|
||||
private const val serialVersionUID: Long = -7315889077010185135L
|
||||
val bar = 0
|
||||
}
|
||||
}
|
||||
""".trimIndent(), "Add 'const val' property 'serialVersionUID' to 'Foo'")
|
||||
}
|
||||
|
||||
fun `test quickfix @Serial annotation`() {
|
||||
IdeaTestUtil.withLevel(module, LanguageLevel.JDK_14) {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
import java.io.Serializable
|
||||
|
||||
class Fo<caret>o : Serializable { }
|
||||
""".trimIndent(), """
|
||||
import java.io.Serial
|
||||
import java.io.Serializable
|
||||
|
||||
class Foo : Serializable {
|
||||
companion object {
|
||||
@Serial
|
||||
private const val serialVersionUID: Long = 7429157667498829299L
|
||||
}
|
||||
}
|
||||
""".trimIndent(), "Add 'const val' property 'serialVersionUID' to 'Foo'")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.SuppressionAnnotationInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinSuppressionAnnotationInspectionTest : SuppressionAnnotationInspectionTestBase(), KotlinPluginModeProvider {
|
||||
|
||||
fun `test highlighting`() {
|
||||
inspection.myAllowedSuppressions.add("FreeSpeech")
|
||||
myFixture.testHighlighting(
|
||||
JvmLanguage.KOTLIN,
|
||||
"""
|
||||
@<warning descr="Annotation suppresses 'ALL' and 'SuppressionAnnotation'">Suppress</warning>("ALL", "SuppressionAnnotation")
|
||||
class A {
|
||||
@<warning descr="Annotation suppresses 'PublicField'">Suppress</warning>("PublicField")
|
||||
var s: String? = null
|
||||
@<warning descr="Annotation suppresses">Suppress</warning>
|
||||
var t: String? = null
|
||||
|
||||
fun foo() {
|
||||
<warning descr="Comment suppresses 'HardCodedStringLiteral'">//noinspection HardCodedStringLiteral</warning>
|
||||
any("hello")
|
||||
<warning descr="Comment suppresses">// noinspection</warning>
|
||||
any()
|
||||
}
|
||||
|
||||
@Suppress("FreeSpeech")
|
||||
fun bar() {
|
||||
// noinspection FreeSpeech
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
private fun any(s: String? = null): String? = s
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test quickfix - remove annotation`() {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Supp<caret>ress("PublicField", "HardCodedStringLiteral")
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), """
|
||||
class A {
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "Remove '@Suppress' annotation", testPreview = true)
|
||||
}
|
||||
|
||||
fun `test quickfix - remove comment`() {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
//noinspection PublicField, Hard<caret>CodedStringLiteral
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), """
|
||||
class A {
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "Remove //noinspection", testPreview = true)
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Supp<caret>ress("PublicField")
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation when array form used`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Supp<caret>ress(["PublicField"])
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from annotation when explicit attribute name exists`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Supp<caret>ress(names = "PublicField")
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Supp<caret>ress("PublicField", "HardCodedStringLiteral")
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when array form used`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Supp<caret>ress(["PublicField", "HardCodedStringLiteral"])
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when explicit attribute name exists`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
@Supp<caret>ress(names = ["PublicField", "HardCodedStringLiteral"])
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from annotation when constants used`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
object Constants {
|
||||
const val PUBLIC_FIELD = "PublicField"
|
||||
const val HARD_CODED_STRING_LITERAL = "HardCodedStringLiteral"
|
||||
}
|
||||
|
||||
class A {
|
||||
@Supp<caret>ress([Constants.PUBLIC_FIELD, Constants.HARD_CODED_STRING_LITERAL])
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow a single suppression from comment`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
//noinspection Public<caret>Field
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField")
|
||||
}
|
||||
|
||||
fun `test quickfix - allow multiple suppressions from comment`() {
|
||||
testAllowSuppressionQuickFix(JvmLanguage.KOTLIN, """
|
||||
class A {
|
||||
//noinspection Public<caret>Field, Hard<caret>CodedStringLiteral
|
||||
var s: String = "test"
|
||||
}
|
||||
""".trimIndent(), "PublicField", "HardCodedStringLiteral")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import com.siyeh.ig.dependency.SuspiciousPackagePrivateAccessInspectionTestCase
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/codeInspection/suspiciousPackagePrivateAccess")
|
||||
abstract class KotlinSuspiciousPackagePrivateAccessInspectionTest : SuspiciousPackagePrivateAccessInspectionTestCase("kt"), KotlinPluginModeProvider {
|
||||
fun testAccessingPackagePrivateMembers() {
|
||||
doTestWithDependency()
|
||||
}
|
||||
|
||||
fun testAccessingProtectedMembers() {
|
||||
doTestWithDependency()
|
||||
}
|
||||
|
||||
fun testAccessingProtectedMembersFromKotlin() {
|
||||
doTestWithDependency()
|
||||
}
|
||||
|
||||
fun testOverridePackagePrivateMethod() {
|
||||
doTestWithDependency()
|
||||
}
|
||||
|
||||
override fun getBasePath() = "${KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH}/codeInspection/suspiciousPackagePrivateAccess"
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.SystemGetPropertyInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinSystemGetPropertyInspectionTest : SystemGetPropertyInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test highlighting`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
fun foo() {
|
||||
System.<warning descr="Call 'getProperty' can be simplified for 'file.separator'">getProperty</warning>("file.separator")
|
||||
System.<warning descr="Call 'getProperty' can be simplified for 'path.separator'">getProperty</warning>("path.separator")
|
||||
System.<warning descr="Call 'getProperty' can be simplified for 'line.separator'">getProperty</warning>("line.separator")
|
||||
System.<warning descr="Call 'getProperty' can be simplified for 'file.encoding'">getProperty</warning>("file.encoding")
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test quickfix file-separator`() {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
fun foo() {
|
||||
System.getPrope<caret>rty("file.separator")
|
||||
}
|
||||
""".trimIndent(), """
|
||||
import java.nio.file.FileSystems
|
||||
|
||||
fun foo() {
|
||||
FileSystems.getDefault().getSeparator()
|
||||
}
|
||||
""".trimIndent(), "Replace with 'java.nio.file.FileSystems.getDefault().getSeparator()'", true)
|
||||
}
|
||||
|
||||
fun `test quickfix path-separator`() {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
fun foo() {
|
||||
System.getPrope<caret>rty("path.separator")
|
||||
}
|
||||
""".trimIndent(), """
|
||||
import java.io.File
|
||||
|
||||
fun foo() {
|
||||
File.pathSeparator
|
||||
}
|
||||
""".trimIndent(), "Replace with 'java.io.File.pathSeparator'", true)
|
||||
}
|
||||
|
||||
fun `test quickfix line-separator`() {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
fun foo() {
|
||||
System.getPrope<caret>rty("line.separator")
|
||||
}
|
||||
""".trimIndent(), """
|
||||
fun foo() {
|
||||
System.lineSeparator()
|
||||
}
|
||||
""".trimIndent(), "Replace with 'java.lang.System.lineSeparator()'", true)
|
||||
}
|
||||
|
||||
fun `test quickfix file-encoding`() {
|
||||
myFixture.testQuickFix(JvmLanguage.KOTLIN, """
|
||||
fun foo() {
|
||||
System.getPrope<caret>rty("file.encoding")
|
||||
}
|
||||
""".trimIndent(), """
|
||||
import java.nio.charset.Charset
|
||||
|
||||
fun foo() {
|
||||
Charset.defaultCharset().displayName()
|
||||
}
|
||||
""".trimIndent(), "Replace with 'java.nio.charset.Charset.defaultCharset().displayName()'", true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.jvm.analysis.internal.testFramework.ThreadRunInspectionTestBase
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
private const val inspectionPath = "/codeInspection/threadrun"
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData$inspectionPath")
|
||||
abstract class KotlinThreadRunInspectionTest : ThreadRunInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override fun getBasePath() = KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + inspectionPath
|
||||
|
||||
fun `test highlighting`() {
|
||||
myFixture.testHighlighting("ThreadRunTest.kt")
|
||||
}
|
||||
|
||||
fun `test no highlighting super`() {
|
||||
myFixture.testHighlighting("ThreadRunSuperTest.kt")
|
||||
}
|
||||
|
||||
fun `test quickfix`() {
|
||||
myFixture.testQuickFix("ThreadRunQfTest.kt")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
// 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.
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.UnstableApiUsageInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinUnstableApiUsageInspectionTest : UnstableApiUsageInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test kotlin unstable api usages`() {
|
||||
inspection.myIgnoreInsideImports = false
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
@file:Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", "UNUSED_VALUE", "UNUSED_PARAMETER", "UNUSED_VARIABLE")
|
||||
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.ClassWithExperimentalTypeInSignature' is unstable because its signature references unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">ClassWithExperimentalTypeInSignature</warning>
|
||||
import experimental.pkg.OwnerOfMembersWithExperimentalTypesInSignature
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>.<warning descr="'NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</warning>
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>.<warning descr="'staticNonAnnotatedMethodInAnnotatedClass()' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">staticNonAnnotatedMethodInAnnotatedClass</warning>
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>.<warning descr="'ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is marked unstable with @ApiStatus.Experimental">ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</warning>
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>.<warning descr="'staticAnnotatedMethodInAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">staticAnnotatedMethodInAnnotatedClass</warning>
|
||||
|
||||
import experimental.pkg.NonAnnotatedClass
|
||||
import experimental.pkg.NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS
|
||||
import experimental.pkg.NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass
|
||||
import experimental.pkg.NonAnnotatedClass.<warning descr="'ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS' is marked unstable with @ApiStatus.Experimental">ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS</warning>
|
||||
import experimental.pkg.NonAnnotatedClass.<warning descr="'staticAnnotatedMethodInNonAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">staticAnnotatedMethodInNonAnnotatedClass</warning>
|
||||
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedEnum' is marked unstable with @ApiStatus.Experimental">AnnotatedEnum</warning>
|
||||
import experimental.pkg.NonAnnotatedEnum
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedEnum' is marked unstable with @ApiStatus.Experimental">AnnotatedEnum</warning>.<warning descr="'NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is declared in unstable enum 'experimental.pkg.AnnotatedEnum' marked with @ApiStatus.Experimental">NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM</warning>
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedEnum' is marked unstable with @ApiStatus.Experimental">AnnotatedEnum</warning>.<warning descr="'ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is marked unstable with @ApiStatus.Experimental">ANNOTATED_VALUE_IN_ANNOTATED_ENUM</warning>
|
||||
import experimental.pkg.NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM
|
||||
import experimental.pkg.NonAnnotatedEnum.<warning descr="'ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM' is marked unstable with @ApiStatus.Experimental">ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM</warning>
|
||||
|
||||
import experimental.pkg.<warning descr="'experimental.pkg.AnnotatedAnnotation' is marked unstable with @ApiStatus.Experimental">AnnotatedAnnotation</warning>
|
||||
import experimental.pkg.NonAnnotatedAnnotation
|
||||
|
||||
import experimental.<warning descr="'experimental.annotatedPkg' is marked unstable with @ApiStatus.Experimental">annotatedPkg</warning>.<warning descr="'experimental.annotatedPkg.ClassInAnnotatedPkg' is declared in unstable package 'experimental.annotatedPkg' marked with @ApiStatus.Experimental">ClassInAnnotatedPkg</warning>
|
||||
|
||||
class UnstableElementsTest {
|
||||
fun test() {
|
||||
var s = <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>.<warning descr="'NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</warning>
|
||||
<warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>.<warning descr="'staticNonAnnotatedMethodInAnnotatedClass()' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">staticNonAnnotatedMethodInAnnotatedClass</warning>()
|
||||
val annotatedClassInstanceViaNonAnnotatedConstructor : <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning> = <warning descr="'AnnotatedClass()' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental"><warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning></warning>()
|
||||
s = annotatedClassInstanceViaNonAnnotatedConstructor.<warning descr="'nonAnnotatedFieldInAnnotatedClass' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">nonAnnotatedFieldInAnnotatedClass</warning>
|
||||
annotatedClassInstanceViaNonAnnotatedConstructor.<warning descr="'nonAnnotatedMethodInAnnotatedClass()' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">nonAnnotatedMethodInAnnotatedClass</warning>()
|
||||
s = <warning descr="'NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</warning>
|
||||
<warning descr="'staticNonAnnotatedMethodInAnnotatedClass()' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">staticNonAnnotatedMethodInAnnotatedClass</warning>()
|
||||
|
||||
s = <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>.<warning descr="'ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is marked unstable with @ApiStatus.Experimental">ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</warning>
|
||||
<warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>.<warning descr="'staticAnnotatedMethodInAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">staticAnnotatedMethodInAnnotatedClass</warning>()
|
||||
val annotatedClassInstanceViaAnnotatedConstructor : <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning> = <warning descr="'AnnotatedClass(java.lang.String)' is marked unstable with @ApiStatus.Experimental"><warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning></warning>("")
|
||||
s = annotatedClassInstanceViaAnnotatedConstructor.<warning descr="'annotatedFieldInAnnotatedClass' is marked unstable with @ApiStatus.Experimental">annotatedFieldInAnnotatedClass</warning>
|
||||
annotatedClassInstanceViaAnnotatedConstructor.<warning descr="'annotatedMethodInAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">annotatedMethodInAnnotatedClass</warning>()
|
||||
s = <warning descr="'ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is marked unstable with @ApiStatus.Experimental">ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</warning>
|
||||
<warning descr="'staticAnnotatedMethodInAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">staticAnnotatedMethodInAnnotatedClass</warning>()
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
s = NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS
|
||||
NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass()
|
||||
val nonAnnotatedClassInstanceViaNonAnnotatedConstructor = NonAnnotatedClass()
|
||||
s = nonAnnotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedFieldInNonAnnotatedClass
|
||||
nonAnnotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedMethodInNonAnnotatedClass()
|
||||
s = NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS
|
||||
staticNonAnnotatedMethodInNonAnnotatedClass()
|
||||
|
||||
s = NonAnnotatedClass.<warning descr="'ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS' is marked unstable with @ApiStatus.Experimental">ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS</warning>
|
||||
NonAnnotatedClass.<warning descr="'staticAnnotatedMethodInNonAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">staticAnnotatedMethodInNonAnnotatedClass</warning>()
|
||||
val nonAnnotatedClassInstanceViaAnnotatedConstructor = <warning descr="'NonAnnotatedClass(java.lang.String)' is marked unstable with @ApiStatus.Experimental">NonAnnotatedClass</warning>("")
|
||||
s = nonAnnotatedClassInstanceViaAnnotatedConstructor.<warning descr="'annotatedFieldInNonAnnotatedClass' is marked unstable with @ApiStatus.Experimental">annotatedFieldInNonAnnotatedClass</warning>
|
||||
nonAnnotatedClassInstanceViaAnnotatedConstructor.<warning descr="'annotatedMethodInNonAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">annotatedMethodInNonAnnotatedClass</warning>()
|
||||
s = <warning descr="'ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS' is marked unstable with @ApiStatus.Experimental">ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS</warning>
|
||||
<warning descr="'staticAnnotatedMethodInNonAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">staticAnnotatedMethodInNonAnnotatedClass</warning>()
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
var nonAnnotatedValueInAnnotatedEnum : <warning descr="'experimental.pkg.AnnotatedEnum' is marked unstable with @ApiStatus.Experimental">AnnotatedEnum</warning> = <warning descr="'experimental.pkg.AnnotatedEnum' is marked unstable with @ApiStatus.Experimental">AnnotatedEnum</warning>.<warning descr="'NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is declared in unstable enum 'experimental.pkg.AnnotatedEnum' marked with @ApiStatus.Experimental">NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM</warning>
|
||||
nonAnnotatedValueInAnnotatedEnum = <warning descr="'NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is declared in unstable enum 'experimental.pkg.AnnotatedEnum' marked with @ApiStatus.Experimental">NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM</warning>
|
||||
var annotatedValueInAnnotatedEnum : <warning descr="'experimental.pkg.AnnotatedEnum' is marked unstable with @ApiStatus.Experimental">AnnotatedEnum</warning> = <warning descr="'experimental.pkg.AnnotatedEnum' is marked unstable with @ApiStatus.Experimental">AnnotatedEnum</warning>.<warning descr="'ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is marked unstable with @ApiStatus.Experimental">ANNOTATED_VALUE_IN_ANNOTATED_ENUM</warning>
|
||||
annotatedValueInAnnotatedEnum = <warning descr="'ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is marked unstable with @ApiStatus.Experimental">ANNOTATED_VALUE_IN_ANNOTATED_ENUM</warning>
|
||||
|
||||
var nonAnnotatedValueInNonAnnotatedEnum = NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM
|
||||
nonAnnotatedValueInNonAnnotatedEnum = NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM
|
||||
var annotatedValueInNonAnnotatedEnum = NonAnnotatedEnum.<warning descr="'ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM' is marked unstable with @ApiStatus.Experimental">ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM</warning>
|
||||
annotatedValueInNonAnnotatedEnum = <warning descr="'ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM' is marked unstable with @ApiStatus.Experimental">ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM</warning>
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
@<warning descr="'experimental.pkg.AnnotatedAnnotation' is marked unstable with @ApiStatus.Experimental">AnnotatedAnnotation</warning> class C1
|
||||
@<warning descr="'experimental.pkg.AnnotatedAnnotation' is marked unstable with @ApiStatus.Experimental">AnnotatedAnnotation</warning>(<warning descr="'nonAnnotatedAttributeInAnnotatedAnnotation' is declared in unstable annotation 'experimental.pkg.AnnotatedAnnotation' marked with @ApiStatus.Experimental">nonAnnotatedAttributeInAnnotatedAnnotation</warning> = "123") class C2
|
||||
@<warning descr="'experimental.pkg.AnnotatedAnnotation' is marked unstable with @ApiStatus.Experimental">AnnotatedAnnotation</warning>(<warning descr="'annotatedAttributeInAnnotatedAnnotation' is marked unstable with @ApiStatus.Experimental">annotatedAttributeInAnnotatedAnnotation</warning> = "123") class C3
|
||||
@NonAnnotatedAnnotation class C4
|
||||
@NonAnnotatedAnnotation(nonAnnotatedAttributeInNonAnnotatedAnnotation = "123") class C5
|
||||
@NonAnnotatedAnnotation(<warning descr="'annotatedAttributeInNonAnnotatedAnnotation' is marked unstable with @ApiStatus.Experimental">annotatedAttributeInNonAnnotatedAnnotation</warning> = "123") class C6
|
||||
}
|
||||
}
|
||||
|
||||
open class DirectOverrideAnnotatedMethod : NonAnnotatedClass() {
|
||||
override fun <warning descr="Overridden method 'annotatedMethodInNonAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">annotatedMethodInNonAnnotatedClass</warning>() {}
|
||||
}
|
||||
|
||||
//No warning should be produced.
|
||||
class IndirectOverrideAnnotatedMethod : DirectOverrideAnnotatedMethod() {
|
||||
override fun annotatedMethodInNonAnnotatedClass() {}
|
||||
}
|
||||
|
||||
class DirectOverrideNonAnnotatedMethodInAnnotatedClass : <warning descr="'AnnotatedClass()' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental"><warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning></warning>() {
|
||||
override fun <warning descr="Overridden method 'nonAnnotatedMethodInAnnotatedClass()' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">nonAnnotatedMethodInAnnotatedClass</warning>() {}
|
||||
}
|
||||
|
||||
class DirectOverrideAnnotatedMethodInAnnotatedClass : <warning descr="'AnnotatedClass()' is declared in unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental"><warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning></warning>() {
|
||||
override fun <warning descr="Overridden method 'annotatedMethodInAnnotatedClass()' is marked unstable with @ApiStatus.Experimental">annotatedMethodInAnnotatedClass</warning>() {}
|
||||
}
|
||||
|
||||
class WarningsOfExperimentalTypesInSignature {
|
||||
fun classUsage() {
|
||||
experimental.pkg.<warning descr="'experimental.pkg.ClassWithExperimentalTypeInSignature' is unstable because its signature references unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">ClassWithExperimentalTypeInSignature</warning><<warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>>()
|
||||
}
|
||||
|
||||
fun membersUsages(owner: OwnerOfMembersWithExperimentalTypesInSignature) {
|
||||
val field = owner.<warning descr="'field' is unstable because its signature references unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">field</warning>
|
||||
owner.<warning descr="'parameterType(experimental.pkg.AnnotatedClass)' is unstable because its signature references unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">parameterType</warning>(null)
|
||||
owner.<warning descr="'returnType()' is unstable because its signature references unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">returnType</warning>()
|
||||
|
||||
val fieldPkg = owner.<warning descr="'field' is unstable because its signature references unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">field</warning>
|
||||
owner.<warning descr="'parameterTypePkg(experimental.annotatedPkg.ClassInAnnotatedPkg)' is unstable because its signature references unstable class 'experimental.annotatedPkg.ClassInAnnotatedPkg' marked with @ApiStatus.Experimental">parameterTypePkg</warning>(null)
|
||||
owner.<warning descr="'returnTypePkg()' is unstable because its signature references unstable class 'experimental.pkg.AnnotatedClass' marked with @ApiStatus.Experimental">returnTypePkg</warning>()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test kotlin no warnings on access to members of the same file`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
@file:Suppress("UNUSED_PARAMETER")
|
||||
|
||||
package test;
|
||||
|
||||
import experimental.pkg.AnnotatedClass;
|
||||
|
||||
class NoWarningsMembersOfTheSameFile {
|
||||
companion object {
|
||||
private var staticField: <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>? = null;
|
||||
private fun staticReturnType(): <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>? { return null; }
|
||||
private fun staticParamType(param: <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>?) { }
|
||||
}
|
||||
private var field: <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>? = null;
|
||||
private fun returnType(): <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>? { return null; }
|
||||
private fun paramType(param: <warning descr="'experimental.pkg.AnnotatedClass' is marked unstable with @ApiStatus.Experimental">AnnotatedClass</warning>?) { }
|
||||
|
||||
fun testNoWarningsProducedForMembersOfTheSameClass() {
|
||||
field?.toString();
|
||||
staticField?.toString();
|
||||
returnType();
|
||||
paramType(null);
|
||||
staticReturnType();
|
||||
staticParamType(null)
|
||||
}
|
||||
|
||||
private inner class InnerClass {
|
||||
fun testNoWarningsProducedForMembersEnclosingClass() {
|
||||
field.toString();
|
||||
staticField.toString();
|
||||
returnType();
|
||||
paramType(null);
|
||||
staticReturnType();
|
||||
staticParamType(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test kotlin do not report unstable api usages inside import statements`() {
|
||||
inspection.myIgnoreInsideImports = true
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import experimental.pkg.AnnotatedClass
|
||||
import experimental.pkg.AnnotatedClass.NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS
|
||||
import experimental.pkg.AnnotatedClass.staticNonAnnotatedMethodInAnnotatedClass
|
||||
import experimental.pkg.AnnotatedClass.ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS
|
||||
import experimental.pkg.AnnotatedClass.staticAnnotatedMethodInAnnotatedClass
|
||||
|
||||
import experimental.pkg.NonAnnotatedClass
|
||||
import experimental.pkg.NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS
|
||||
import experimental.pkg.NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass
|
||||
import experimental.pkg.NonAnnotatedClass.ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS
|
||||
import experimental.pkg.NonAnnotatedClass.staticAnnotatedMethodInNonAnnotatedClass
|
||||
|
||||
import experimental.pkg.AnnotatedEnum
|
||||
import experimental.pkg.NonAnnotatedEnum
|
||||
import experimental.pkg.AnnotatedEnum.NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM
|
||||
import experimental.pkg.AnnotatedEnum.ANNOTATED_VALUE_IN_ANNOTATED_ENUM
|
||||
import experimental.pkg.NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM
|
||||
import experimental.pkg.NonAnnotatedEnum.ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM
|
||||
|
||||
import experimental.pkg.AnnotatedAnnotation
|
||||
import experimental.pkg.NonAnnotatedAnnotation
|
||||
|
||||
import experimental.annotatedPkg.ClassInAnnotatedPkg
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test Kotlin scheduled for removal`() {
|
||||
inspection.myIgnoreInsideImports = false
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
@file:Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", "UNUSED_VALUE", "UNUSED_PARAMETER", "UNUSED_VARIABLE")
|
||||
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.ClassWithScheduledForRemovalTypeInSignature' is scheduled for removal because its signature references class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">ClassWithScheduledForRemovalTypeInSignature</error>
|
||||
import scheduledForRemoval.pkg.OwnerOfMembersWithScheduledForRemovalTypesInSignature
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>.<error descr="'NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</error>
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>.<error descr="'staticNonAnnotatedMethodInAnnotatedClass()' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">staticNonAnnotatedMethodInAnnotatedClass</error>
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>.<error descr="'ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is scheduled for removal in version 123.456">ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</error>
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>.<error descr="'staticAnnotatedMethodInAnnotatedClass()' is scheduled for removal in version 123.456">staticAnnotatedMethodInAnnotatedClass</error>
|
||||
|
||||
import scheduledForRemoval.pkg.NonAnnotatedClass
|
||||
import scheduledForRemoval.pkg.NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS
|
||||
import scheduledForRemoval.pkg.NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass
|
||||
import scheduledForRemoval.pkg.NonAnnotatedClass.<error descr="'ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS' is scheduled for removal in version 123.456">ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS</error>
|
||||
import scheduledForRemoval.pkg.NonAnnotatedClass.<error descr="'staticAnnotatedMethodInNonAnnotatedClass()' is scheduled for removal in version 123.456">staticAnnotatedMethodInNonAnnotatedClass</error>
|
||||
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedEnum' is scheduled for removal in version 123.456">AnnotatedEnum</error>
|
||||
import scheduledForRemoval.pkg.NonAnnotatedEnum
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedEnum' is scheduled for removal in version 123.456">AnnotatedEnum</error>.<error descr="'NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is declared in enum 'scheduledForRemoval.pkg.AnnotatedEnum' scheduled for removal in version 123.456">NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM</error>
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedEnum' is scheduled for removal in version 123.456">AnnotatedEnum</error>.<error descr="'ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is scheduled for removal in version 123.456">ANNOTATED_VALUE_IN_ANNOTATED_ENUM</error>
|
||||
import scheduledForRemoval.pkg.NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM
|
||||
import scheduledForRemoval.pkg.NonAnnotatedEnum.<error descr="'ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM' is scheduled for removal in version 123.456">ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM</error>
|
||||
|
||||
import scheduledForRemoval.pkg.<error descr="'scheduledForRemoval.pkg.AnnotatedAnnotation' is scheduled for removal in version 123.456">AnnotatedAnnotation</error>
|
||||
import scheduledForRemoval.pkg.NonAnnotatedAnnotation
|
||||
|
||||
import scheduledForRemoval.<error descr="'scheduledForRemoval.annotatedPkg' is scheduled for removal in version 123.456">annotatedPkg</error>.<error descr="'scheduledForRemoval.annotatedPkg.ClassInAnnotatedPkg' is declared in package 'scheduledForRemoval.annotatedPkg' scheduled for removal in version 123.456">ClassInAnnotatedPkg</error>
|
||||
|
||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", "UNUSED_VALUE")
|
||||
class ScheduledForRemovalElementsTest {
|
||||
fun test() {
|
||||
var s = <error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>.<error descr="'NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</error>
|
||||
<error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>.<error descr="'staticNonAnnotatedMethodInAnnotatedClass()' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">staticNonAnnotatedMethodInAnnotatedClass</error>()
|
||||
val annotatedClassInstanceViaNonAnnotatedConstructor : <error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error> = <error descr="'AnnotatedClass()' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456"><error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error></error>()
|
||||
s = annotatedClassInstanceViaNonAnnotatedConstructor.<error descr="'nonAnnotatedFieldInAnnotatedClass' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">nonAnnotatedFieldInAnnotatedClass</error>
|
||||
annotatedClassInstanceViaNonAnnotatedConstructor.<error descr="'nonAnnotatedMethodInAnnotatedClass()' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">nonAnnotatedMethodInAnnotatedClass</error>()
|
||||
s = <error descr="'NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</error>
|
||||
<error descr="'staticNonAnnotatedMethodInAnnotatedClass()' is declared in class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">staticNonAnnotatedMethodInAnnotatedClass</error>()
|
||||
|
||||
s = <error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>.<error descr="'ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is scheduled for removal in version 123.456">ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</error>
|
||||
<error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>.<error descr="'staticAnnotatedMethodInAnnotatedClass()' is scheduled for removal in version 123.456">staticAnnotatedMethodInAnnotatedClass</error>()
|
||||
val annotatedClassInstanceViaAnnotatedConstructor : <error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error> = <error descr="'AnnotatedClass(java.lang.String)' is scheduled for removal in version 123.456"><error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error></error>("")
|
||||
s = annotatedClassInstanceViaAnnotatedConstructor.<error descr="'annotatedFieldInAnnotatedClass' is scheduled for removal in version 123.456">annotatedFieldInAnnotatedClass</error>
|
||||
annotatedClassInstanceViaAnnotatedConstructor.<error descr="'annotatedMethodInAnnotatedClass()' is scheduled for removal in version 123.456">annotatedMethodInAnnotatedClass</error>()
|
||||
s = <error descr="'ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS' is scheduled for removal in version 123.456">ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS</error>
|
||||
<error descr="'staticAnnotatedMethodInAnnotatedClass()' is scheduled for removal in version 123.456">staticAnnotatedMethodInAnnotatedClass</error>()
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
s = NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS
|
||||
NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass()
|
||||
val nonAnnotatedClassInstanceViaNonAnnotatedConstructor = NonAnnotatedClass()
|
||||
s = nonAnnotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedFieldInNonAnnotatedClass
|
||||
nonAnnotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedMethodInNonAnnotatedClass()
|
||||
s = NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS
|
||||
staticNonAnnotatedMethodInNonAnnotatedClass()
|
||||
|
||||
s = NonAnnotatedClass.<error descr="'ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS' is scheduled for removal in version 123.456">ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS</error>
|
||||
NonAnnotatedClass.<error descr="'staticAnnotatedMethodInNonAnnotatedClass()' is scheduled for removal in version 123.456">staticAnnotatedMethodInNonAnnotatedClass</error>()
|
||||
val nonAnnotatedClassInstanceViaAnnotatedConstructor = <error descr="'NonAnnotatedClass(java.lang.String)' is scheduled for removal in version 123.456">NonAnnotatedClass</error>("")
|
||||
s = nonAnnotatedClassInstanceViaAnnotatedConstructor.<error descr="'annotatedFieldInNonAnnotatedClass' is scheduled for removal in version 123.456">annotatedFieldInNonAnnotatedClass</error>
|
||||
nonAnnotatedClassInstanceViaAnnotatedConstructor.<error descr="'annotatedMethodInNonAnnotatedClass()' is scheduled for removal in version 123.456">annotatedMethodInNonAnnotatedClass</error>()
|
||||
s = <error descr="'ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS' is scheduled for removal in version 123.456">ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS</error>
|
||||
<error descr="'staticAnnotatedMethodInNonAnnotatedClass()' is scheduled for removal in version 123.456">staticAnnotatedMethodInNonAnnotatedClass</error>()
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
var nonAnnotatedValueInAnnotatedEnum : <error descr="'scheduledForRemoval.pkg.AnnotatedEnum' is scheduled for removal in version 123.456">AnnotatedEnum</error> = <error descr="'scheduledForRemoval.pkg.AnnotatedEnum' is scheduled for removal in version 123.456">AnnotatedEnum</error>.<error descr="'NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is declared in enum 'scheduledForRemoval.pkg.AnnotatedEnum' scheduled for removal in version 123.456">NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM</error>
|
||||
nonAnnotatedValueInAnnotatedEnum = <error descr="'NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is declared in enum 'scheduledForRemoval.pkg.AnnotatedEnum' scheduled for removal in version 123.456">NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM</error>
|
||||
var annotatedValueInAnnotatedEnum : <error descr="'scheduledForRemoval.pkg.AnnotatedEnum' is scheduled for removal in version 123.456">AnnotatedEnum</error> = <error descr="'scheduledForRemoval.pkg.AnnotatedEnum' is scheduled for removal in version 123.456">AnnotatedEnum</error>.<error descr="'ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is scheduled for removal in version 123.456">ANNOTATED_VALUE_IN_ANNOTATED_ENUM</error>
|
||||
annotatedValueInAnnotatedEnum = <error descr="'ANNOTATED_VALUE_IN_ANNOTATED_ENUM' is scheduled for removal in version 123.456">ANNOTATED_VALUE_IN_ANNOTATED_ENUM</error>
|
||||
|
||||
var nonAnnotatedValueInNonAnnotatedEnum = NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM
|
||||
nonAnnotatedValueInNonAnnotatedEnum = NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM
|
||||
var annotatedValueInNonAnnotatedEnum = NonAnnotatedEnum.<error descr="'ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM' is scheduled for removal in version 123.456">ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM</error>
|
||||
annotatedValueInNonAnnotatedEnum = <error descr="'ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM' is scheduled for removal in version 123.456">ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM</error>
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
@<error descr="'scheduledForRemoval.pkg.AnnotatedAnnotation' is scheduled for removal in version 123.456">AnnotatedAnnotation</error> class C1
|
||||
@<error descr="'scheduledForRemoval.pkg.AnnotatedAnnotation' is scheduled for removal in version 123.456">AnnotatedAnnotation</error>(<error descr="'nonAnnotatedAttributeInAnnotatedAnnotation' is declared in annotation 'scheduledForRemoval.pkg.AnnotatedAnnotation' scheduled for removal in version 123.456">nonAnnotatedAttributeInAnnotatedAnnotation</error> = "123") class C2
|
||||
@<error descr="'scheduledForRemoval.pkg.AnnotatedAnnotation' is scheduled for removal in version 123.456">AnnotatedAnnotation</error>(<error descr="'annotatedAttributeInAnnotatedAnnotation' is scheduled for removal in version 123.456">annotatedAttributeInAnnotatedAnnotation</error> = "123") class C3
|
||||
@NonAnnotatedAnnotation class C4
|
||||
@NonAnnotatedAnnotation(nonAnnotatedAttributeInNonAnnotatedAnnotation = "123") class C5
|
||||
@NonAnnotatedAnnotation(<error descr="'annotatedAttributeInNonAnnotatedAnnotation' is scheduled for removal in version 123.456">annotatedAttributeInNonAnnotatedAnnotation</error> = "123") class C6
|
||||
}
|
||||
}
|
||||
|
||||
open class DirectOverrideAnnotatedMethod : NonAnnotatedClass() {
|
||||
override fun <error descr="Overridden method 'annotatedMethodInNonAnnotatedClass()' is scheduled for removal in version 123.456">annotatedMethodInNonAnnotatedClass</error>() {}
|
||||
}
|
||||
|
||||
//No warning should be produced.
|
||||
class IndirectOverrideAnnotatedMethod : DirectOverrideAnnotatedMethod() {
|
||||
override fun annotatedMethodInNonAnnotatedClass() {}
|
||||
}
|
||||
|
||||
class WarningsOfScheduledForRemovalTypesInSignature {
|
||||
fun classUsage() {
|
||||
<error descr="'scheduledForRemoval.pkg.ClassWithScheduledForRemovalTypeInSignature' is scheduled for removal because its signature references class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">ClassWithScheduledForRemovalTypeInSignature</error><<error descr="'scheduledForRemoval.pkg.AnnotatedClass' is scheduled for removal in version 123.456">AnnotatedClass</error>>()
|
||||
}
|
||||
|
||||
fun membersUsages(owner: OwnerOfMembersWithScheduledForRemovalTypesInSignature) {
|
||||
val field = owner.<error descr="'field' is scheduled for removal because its signature references class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">field</error>
|
||||
owner.<error descr="'parameterType(scheduledForRemoval.pkg.AnnotatedClass)' is scheduled for removal because its signature references class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">parameterType</error>(null)
|
||||
owner.<error descr="'returnType()' is scheduled for removal because its signature references class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">returnType</error>()
|
||||
|
||||
val fieldPkg = owner.<error descr="'field' is scheduled for removal because its signature references class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">field</error>
|
||||
owner.<error descr="'parameterTypePkg(scheduledForRemoval.annotatedPkg.ClassInAnnotatedPkg)' is scheduled for removal because its signature references class 'scheduledForRemoval.annotatedPkg.ClassInAnnotatedPkg' scheduled for removal in version 123.456">parameterTypePkg</error>(null)
|
||||
owner.<error descr="'returnTypePkg()' is scheduled for removal because its signature references class 'scheduledForRemoval.pkg.AnnotatedClass' scheduled for removal in version 123.456">returnTypePkg</error>()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.codeInspection.UnstableTypeUsedInSignatureInspection
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
import java.io.File
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/codeInspection/unstableTypeUsedInSignature")
|
||||
abstract class KotlinUnstableTypeUsedInSignatureTest : JavaCodeInsightFixtureTestCase(), KotlinPluginModeProvider {
|
||||
|
||||
override fun getBasePath() = KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + "/codeInspection/unstableTypeUsedInSignature"
|
||||
|
||||
override fun getTestDataPath(): String = PathManager.getCommunityHomePath().replace(File.separatorChar, '/') + basePath
|
||||
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
val inspection = UnstableTypeUsedInSignatureInspection()
|
||||
inspection.unstableApiAnnotations.clear()
|
||||
inspection.unstableApiAnnotations.add(ApiStatus.Experimental::class.java.canonicalName)
|
||||
myFixture.enableInspections(inspection)
|
||||
configureAnnotatedFiles()
|
||||
}
|
||||
|
||||
private fun configureAnnotatedFiles() {
|
||||
listOf(
|
||||
"experimentalPackage/ClassInExperimentalPackage.java",
|
||||
"experimentalPackage/package-info.java",
|
||||
"experimentalPackage/NoWarnings.java",
|
||||
"test/ExperimentalClass.java"
|
||||
).forEach { myFixture.copyFileToProject(it) }
|
||||
}
|
||||
|
||||
override fun tuneFixture(moduleBuilder: JavaModuleFixtureBuilder<*>) {
|
||||
moduleBuilder.addLibrary("util", PathUtil.getJarPathForClass(ApiStatus.Experimental::class.java))
|
||||
}
|
||||
|
||||
fun `test kotlin missing unstable annotation`() {
|
||||
myFixture.testHighlighting("UnstableTypeUsedInSignature.kt")
|
||||
myFixture.testHighlighting("UnstableTypeUsedInTypeParameter.kt")
|
||||
}
|
||||
|
||||
fun `test java missing unstable annotation`() {
|
||||
myFixture.testHighlighting("UnstableTypeUsedInSignature.java")
|
||||
myFixture.testHighlighting("UnstableTypeUsedInTypeParameter.java")
|
||||
}
|
||||
|
||||
fun `test java no extra warnings are produced`() {
|
||||
myFixture.testHighlighting("noWarnings/NoWarningsAlreadyMarked.java")
|
||||
myFixture.testHighlighting("noWarnings/NoWarningsInaccessible.java")
|
||||
myFixture.testHighlighting("noWarnings/NoWarningsMembersAlreadyMarked.java")
|
||||
}
|
||||
|
||||
fun `test kotlin no extra warnings are produced`() {
|
||||
myFixture.testHighlighting("noWarnings/NoWarningsAlreadyMarked.kt")
|
||||
myFixture.testHighlighting("noWarnings/NoWarningsInaccessible.kt")
|
||||
}
|
||||
|
||||
fun `test no warnings produced in experimental package`() {
|
||||
myFixture.testHighlighting("experimentalPackage/NoWarnings.java")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.intellij.codeInspection.tests.kotlin;
|
||||
|
||||
import com.intellij.java.codeInspection.AbstractUnusedDeclarationTest;
|
||||
import com.intellij.java.codeInspection.UnusedDeclarationInspectionTest;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider;
|
||||
|
||||
public abstract class KotlinUnusedDeclarationTest extends AbstractUnusedDeclarationTest implements KotlinPluginModeProvider {
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PathManagerEx.getTestDataPath(UnusedDeclarationInspectionTest.class) + "/inspection/jvm";
|
||||
}
|
||||
|
||||
public void testSingleton() {
|
||||
myTool.ADD_NONJAVA_TO_ENTRIES = false;
|
||||
doTest();
|
||||
}
|
||||
|
||||
//TODO
|
||||
public void testDefaultConstructor() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReferenceFromSuperTypeList() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testImplementedInterface() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReachableFromMain() {
|
||||
myTool.ADD_MAINS_TO_ENTRIES = true;
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testMutableCalls() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testOverridingProperty() {
|
||||
myTool.getSharedLocalInspectionTool().PARAMETER = true;
|
||||
myTool.getSharedLocalInspectionTool().LOCAL_VARIABLE = false;
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testPrimaryConstructor() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPrimaryConstructor2() {
|
||||
myTool.getSharedLocalInspectionTool().PARAMETER = true;
|
||||
myTool.getSharedLocalInspectionTool().LOCAL_VARIABLE = false;
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testReceiverParameter() {
|
||||
myTool.getSharedLocalInspectionTool().PARAMETER = true;
|
||||
myTool.getSharedLocalInspectionTool().LOCAL_VARIABLE = false;
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testOperatorInWhen() {
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testCallableParameter() {
|
||||
myTool.getSharedLocalInspectionTool().PARAMETER = true;
|
||||
myTool.getSharedLocalInspectionTool().LOCAL_VARIABLE = false;
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testCallableProperty() {
|
||||
myTool.getSharedLocalInspectionTool().FIELD = true;
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testUsagesInCallableReceiver() {
|
||||
myTool.getSharedLocalInspectionTool().PARAMETER = true;
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testUsagesInClassLiteral() {
|
||||
myTool.getSharedLocalInspectionTool().PARAMETER = true;
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testMainParameter() {
|
||||
myTool.getSharedLocalInspectionTool().PARAMETER = true;
|
||||
myTool.getSharedLocalInspectionTool().LOCAL_VARIABLE = false;
|
||||
doTest("deadCode/" + getTestName(true), myToolWrapper);
|
||||
}
|
||||
|
||||
public void testStaticMethods() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testChainOfCalls() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReachableFromFieldInitializer() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReachableFromFieldArrayInitializer() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testJunitEntryPoint() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testConstructorCalls() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPropertyReference() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReferenceInLambda() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNonJvmReferences() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
//TODO uast kotlin enum support
|
||||
public void _testEnumInstantiation() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void _testEnumValues() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testUsagesInAnonymous() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testClassLiteralRef() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTopLevelFunction() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.intellij.codeInspection.tests.kotlin;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInspection.unusedReturnValue.UnusedReturnValue;
|
||||
import com.intellij.testFramework.JavaInspectionTestCase;
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider;
|
||||
|
||||
public abstract class KotlinUnusedReturnValueInspectionKtTest extends JavaInspectionTestCase implements KotlinPluginModeProvider {
|
||||
private final UnusedReturnValue myGlobalTool = new UnusedReturnValue();
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/inspection/jvm";
|
||||
}
|
||||
|
||||
private String getGlobalTestDir() {
|
||||
return "unusedReturnValue/" + getTestName(true);
|
||||
}
|
||||
|
||||
public void testUsedPropertyBySimpleName() {
|
||||
doTest(getGlobalTestDir(), myGlobalTool);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.deadCode
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.deadCode.AssertJImplicitUsageProviderTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinAssertJImplicitUsageProviderTest : AssertJImplicitUsageProviderTestBase(), KotlinPluginModeProvider {
|
||||
fun `test inject soft assertion implicit usage provider`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
@org.junit.jupiter.api.extension.ExtendWith(org.assertj.core.api.junit.jupiter.SoftAssertionsExtension::class)
|
||||
class TestClass {
|
||||
@org.assertj.core.api.junit.jupiter.InjectSoftAssertions
|
||||
private lateinit var softAssertions: org.assertj.core.api.SoftAssertions
|
||||
|
||||
@org.junit.jupiter.api.Test
|
||||
fun doSomething() {
|
||||
softAssertions.assertThat("string").isEqualTo("string")
|
||||
}
|
||||
}
|
||||
""".trimIndent(), fileName = "TestClass")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.deadCode
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.deadCode.EasyMockImplicitUsageProviderTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinEasyMockImplicitUsageProviderTest : EasyMockImplicitUsageProviderTestBase(), KotlinPluginModeProvider {
|
||||
fun `test implicit usage for mocked field`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class MyEasyMockTest {
|
||||
@org.easymock.Mock
|
||||
private lateinit var myFoo: String
|
||||
|
||||
init {
|
||||
System.out.println(myFoo)
|
||||
}
|
||||
|
||||
@org.junit.Test
|
||||
fun testName() { }
|
||||
}
|
||||
""".trimIndent(), fileName = "MyEasyMockTest")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.deadCode
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.deadCode.MockitoImplicitUsageProviderTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinMockitoImplicitUsageProviderTest : MockitoImplicitUsageProviderTestBase(), KotlinPluginModeProvider {
|
||||
fun `test implicit usage for mocked field`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class MyMockitoTest {
|
||||
@org.mockito.Mock
|
||||
private lateinit var myFoo: String
|
||||
|
||||
init {
|
||||
System.out.println(myFoo)
|
||||
}
|
||||
|
||||
@org.junit.Test
|
||||
fun testName() { }
|
||||
}
|
||||
""".trimIndent(), fileName = "MyMockitoTest")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.logging
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle
|
||||
import com.intellij.jvm.analysis.internal.testFramework.logging.LoggingConditionDisagreesWithLogLevelStatementInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinLoggingConditionDisagreesWithLogLevelStatementInspectionTest : LoggingConditionDisagreesWithLogLevelStatementInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n() {
|
||||
if (LOG.isInfoEnabled) {
|
||||
LOG.info("nothing to report")
|
||||
}
|
||||
if (LOG.<warning descr="Level of condition 'INFO' does not match level of logging call 'WARN'">isInfoEnabled</warning>) {
|
||||
LOG.warn("test")
|
||||
}
|
||||
if (LOG.<warning descr="Level of condition 'INFO' does not match level of logging call 'WARN'">isInfoEnabled</warning>()) {
|
||||
LOG.warn("test")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test log4j2`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
internal class Y {
|
||||
fun m() {
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn("test")
|
||||
}
|
||||
if (LOG.isWarnEnabled ) {
|
||||
LOG.warn("test")
|
||||
}
|
||||
if (LOG.<warning descr="Level of condition 'INFO' does not match level of logging call 'WARN'">isInfoEnabled</warning> ) {
|
||||
LOG.warn("test")
|
||||
}
|
||||
if (LOG.<warning descr="Level of condition 'INFO' does not match level of logging call 'WARN'">isInfoEnabled</warning>()) {
|
||||
LOG.warn("test")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOG = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test several logs`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal object X {
|
||||
private val logger = LoggerFactory.getLogger()
|
||||
fun test1() {
|
||||
if (logger.isDebugEnabled) {
|
||||
try {
|
||||
something()
|
||||
logger.debug("a")
|
||||
} catch (e: Exception) {
|
||||
logger.error("a")
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
try {
|
||||
something()
|
||||
logger.debug("a")
|
||||
} catch (e: Exception) {
|
||||
logger.error("a")
|
||||
}
|
||||
}
|
||||
if (logger.<warning descr="Level of condition 'INFO' does not match level of logging call 'DEBUG'"><warning descr="Level of condition 'INFO' does not match level of logging call 'ERROR'">isInfoEnabled</warning></warning>) {
|
||||
try {
|
||||
something()
|
||||
logger.debug("a")
|
||||
} catch (e: Exception) {
|
||||
logger.error("a")
|
||||
}
|
||||
}
|
||||
if (logger.<warning descr="Level of condition 'INFO' does not match level of logging call 'DEBUG'"><warning descr="Level of condition 'INFO' does not match level of logging call 'ERROR'">isInfoEnabled</warning></warning>()) {
|
||||
try {
|
||||
something()
|
||||
logger.debug("a")
|
||||
} catch (e: Exception) {
|
||||
logger.error("a")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun something() {}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test java util logging`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.util.logging.Level
|
||||
import java.util.logging.Logger
|
||||
|
||||
val LOG = Logger.getLogger("")
|
||||
|
||||
internal class Loggers {
|
||||
fun method() {
|
||||
if (LOG.<warning descr="Level of condition 'FINE' does not match level of logging call 'WARNING'">isLoggable</warning>(Level.FINE)) {
|
||||
LOG.warning("test")
|
||||
}
|
||||
if (LOG.isLoggable(Level.WARNING)) {
|
||||
LOG.warning("not error")
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test fixes slf4j change guards`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal object Slf4J {
|
||||
private val log: Logger = LoggerFactory.getLogger(Slf4J::class.java)
|
||||
|
||||
private fun request1(i: String) {
|
||||
val msg = "log messages2: {}"
|
||||
if (log.isDeb<caret>ugEnabled) {
|
||||
log.info(msg, i)
|
||||
}
|
||||
}
|
||||
}""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal object Slf4J {
|
||||
private val log: Logger = LoggerFactory.getLogger(Slf4J::class.java)
|
||||
|
||||
private fun request1(i: String) {
|
||||
val msg = "log messages2: {}"
|
||||
if (log.isInfoEnabled) {
|
||||
log.info(msg, i)
|
||||
}
|
||||
}
|
||||
}""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.logging.condition.disagrees.with.log.statement.fix.name", 0)
|
||||
)
|
||||
}
|
||||
|
||||
fun `test fixes slf4j change guards as methods`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal object Slf4J {
|
||||
private val log: Logger = LoggerFactory.getLogger(Slf4J::class.java)
|
||||
|
||||
private fun request1(i: String) {
|
||||
val msg = "log messages2: {}"
|
||||
if (log.isDeb<caret>ugEnabled()) {
|
||||
log.info(msg, i)
|
||||
}
|
||||
}
|
||||
}""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal object Slf4J {
|
||||
private val log: Logger = LoggerFactory.getLogger(Slf4J::class.java)
|
||||
|
||||
private fun request1(i: String) {
|
||||
val msg = "log messages2: {}"
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(msg, i)
|
||||
}
|
||||
}
|
||||
}""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.logging.condition.disagrees.with.log.statement.fix.name", 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.logging
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle
|
||||
import com.intellij.jvm.analysis.internal.testFramework.logging.LoggingGuardedByConditionInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinLoggingGuardedByConditionInspectionTest : LoggingGuardedByConditionInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<warning descr="Logging call guarded by log condition">isDebugEnabled</warning>) {
|
||||
LOG.debug("test" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test log4j2`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<warning descr="Logging call guarded by log condition">isDebugEnabled()</warning>) {
|
||||
LOG.debug("test1" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOG: Logger = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test several calls slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<warning descr="Logging call guarded by log condition">isDebugEnabled</warning>) {
|
||||
LOG.debug("test1" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test several different calls slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<warning descr="Logging call guarded by log condition">isDebugEnabled</warning>) {
|
||||
LOG.info("test1" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test several calls with another call slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<warning descr="Logging call guarded by log condition">isDebugEnabled</warning>) {
|
||||
LOG.debug("test1" + arg)
|
||||
arg.toString()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test several calls with another call slf4j showOnlyIfFixPossible`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("test1" + arg)
|
||||
arg.toString()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test slf4j fix`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<caret>isDebugEnabled) {
|
||||
LOG.debug("test" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
LOG.debug("test" + arg)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.log.guarded.fix.family.name")
|
||||
)
|
||||
}
|
||||
|
||||
fun `test slf4j without block fix`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<caret>isDebugEnabled)
|
||||
LOG.debug("test" + arg)
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
LOG.debug("test" + arg)
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.log.guarded.fix.family.name")
|
||||
)
|
||||
}
|
||||
|
||||
fun `test several calls slf4j fix`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<caret>isDebugEnabled) {
|
||||
LOG.debug("test1" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
LOG.debug("test1" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.log.guarded.fix.family.name")
|
||||
)
|
||||
}
|
||||
|
||||
fun `test slf4j with comment fix`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.<caret>isDebugEnabled) {//comment1
|
||||
//comment2
|
||||
LOG.debug("test" + arg)
|
||||
//comment3
|
||||
|
||||
//comment4
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
//comment1
|
||||
//comment2
|
||||
LOG.debug("test" + arg)
|
||||
//comment3
|
||||
|
||||
//comment4
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.log.guarded.fix.family.name")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.logging
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.logging.LoggingPlaceholderCountMatchesArgumentCountInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinLoggingPlaceholderCountMatchesArgumentCountInspectionLog4J2Test : LoggingPlaceholderCountMatchesArgumentCountInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test log4j2 with text variables`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
|
||||
|
||||
internal class Logging {
|
||||
fun m(i: Int) {
|
||||
val text = "test {}{}{}"
|
||||
LOG.info( <warning descr="Fewer arguments provided (1) than placeholders specified (3)">text</warning> , i)
|
||||
val text2 = "test "
|
||||
LOG.fatal( <warning descr="More arguments provided (1) than placeholders specified (0)">text2</warning> , i)
|
||||
LOG.fatal( <warning descr="Fewer arguments provided (1) than placeholders specified (6)">text + text</warning> , i)
|
||||
LOG.fatal( <warning descr="Fewer arguments provided (1) than placeholders specified (18)">text + text + text + text + text + text</warning> , i)
|
||||
LOG.info( <warning descr="More arguments provided (1) than placeholders specified (0)">FINAL_TEXT</warning> , i)
|
||||
val sum = "first {}" + "second {}" + 1
|
||||
LOG.info( <warning descr="Fewer arguments provided (1) than placeholders specified (2)">sum</warning> , i)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FINAL_TEXT = "const"
|
||||
private val LOG = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test log4j2`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.*;
|
||||
private val logger = LogManager.getLogger();
|
||||
private val brackets: String = "{}"
|
||||
fun foo() {
|
||||
logger?.debug(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.debug(<warning descr="More arguments provided (2) than placeholders specified (1)">"test " + brackets</warning>, 1, 2) //warn
|
||||
logger?.debug("test {}" + brackets, 1, 2)
|
||||
logger?.debug(<warning descr="Fewer arguments provided (1) than placeholders specified (3)">"test {} {} {}"</warning>, 1, Exception()) //warn
|
||||
logger?.debug(<warning descr="More arguments provided (1) than placeholders specified (0)">"test"</warning>, 1, Exception()) //warn
|
||||
logger?.debug(<warning descr="Fewer arguments provided (0) than placeholders specified (1)">"test {}"</warning>, Exception()) //warn
|
||||
logger?.debug("test {} {}", 1, 2, Exception())
|
||||
logger?.debug("test {} {}", 1, Exception())
|
||||
logger?.debug(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.debug("test {} {}", 1, 2, Exception())
|
||||
logger?.debug(<warning descr="More arguments provided (2) than placeholders specified (1)">"test {}"</warning>, 1, 2) //warn
|
||||
logger?.error(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.fatal(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.info(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.trace(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.warn(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.info("test {} {}", {}, {}, {RuntimeException()})
|
||||
logger?.info("test {} {}", {}, {RuntimeException()})
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test log4j2 builder`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.*;
|
||||
private val logger = LogManager.getLogger();
|
||||
private val brackets: String = "{}"
|
||||
fun foo() {
|
||||
logger?.atDebug()?.log(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.atDebug()?.log("test {} {}", 1, 2)
|
||||
logger?.atDebug()?.log(<warning descr="More arguments provided (2) than placeholders specified (0)">"test"</warning>, 1, Exception()) //warn
|
||||
logger?.atDebug()?.log(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, Exception()) //warn
|
||||
logger?.atDebug()?.log("test {} {} {}", 1, 2, Exception())
|
||||
logger?.atDebug()?.log(<warning descr="More arguments provided (3) than placeholders specified (2)">"test {} {}"</warning>, 1, 2, Exception()) //warn
|
||||
logger?.atDebug()?.log("test {}", Exception())
|
||||
logger?.atDebug()?.log(<warning descr="More arguments provided (1) than placeholders specified (0)">"test"</warning>, Exception()) //warn
|
||||
}
|
||||
|
||||
internal class Logging {
|
||||
fun m(i: Int) {
|
||||
LOG.atInfo().log( <warning descr="Fewer arguments provided (1) than placeholders specified (3)">"test? {}{}{}"</warning> , i)
|
||||
LOG.atFatal().log( <warning descr="More arguments provided (2) than placeholders specified (0)">"test "</warning> , i, i)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test log4j2LogBuilder 2`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.util.Supplier
|
||||
|
||||
internal class Logging {
|
||||
fun m(i: Int) {
|
||||
LOG.atInfo().log( <warning descr="Fewer arguments provided (1) than placeholders specified (3)">"test? {}{}{}"</warning> , i)
|
||||
LOG.atFatal().log( <warning descr="More arguments provided (2) than placeholders specified (0)">"test "</warning> , i, i)
|
||||
LOG.atError().log( <warning descr="More arguments provided (1) than placeholders specified (0)">"test? "</warning> , Supplier<Any> { "" })
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test formatted log4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.*;
|
||||
private val LOG: Logger = LogManager.getFormatterLogger()
|
||||
fun m() {
|
||||
try {
|
||||
throw RuntimeException()
|
||||
} catch (t: Throwable) {
|
||||
val LOG2: Logger = LogManager.getFormatterLogger()
|
||||
LOG.info("My %s text", "test", t)
|
||||
LOG.info( <warning descr="Illegal format string specifier">"My %i text"</warning> , "test")
|
||||
LOG.info( <warning descr="More arguments provided (2) than placeholders specified (1)">"My %s text"</warning> , "test1", "test2")
|
||||
LOG2.info("My %s text, %s", "test1") //skip because LOG2 is not final
|
||||
LogManager.getFormatterLogger().info( <warning descr="Fewer arguments provided (1) than placeholders specified (2)">"My %s text, %s"</warning> , "test1")
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test Log4j2 with exception in suppliers`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.util.Supplier
|
||||
|
||||
internal class Logging {
|
||||
fun m() {
|
||||
try {
|
||||
throw java.lang.RuntimeException()
|
||||
} catch (t: IllegalArgumentException) {
|
||||
LOG.info( <warning descr="More arguments provided (3) than placeholders specified (1)">"test {}"</warning> , Supplier<Any> { "test" }, Supplier<Any> { "test" }, Supplier<Any> { t })
|
||||
} catch (t: IllegalStateException) {
|
||||
LOG.info(<warning descr="More arguments provided (3) than placeholders specified (1)">"test {}"</warning>, Supplier<Any> { "test" }, Supplier<Any> { "test" }, Supplier<Any> { t })
|
||||
} catch (t: Throwable) {
|
||||
LOG.info("test {}", Supplier<Any> { "test" }, Supplier<Any> { t })
|
||||
LOG.info( <warning descr="More arguments provided (3) than placeholders specified (1)">"test {}"</warning> , Supplier<Any> { "test" }, Supplier<Any> { "test" }, Supplier<Any> { t })
|
||||
val s = Supplier { t }
|
||||
LOG.info("test {}", Supplier<Any> { "test" }, s)
|
||||
val s2: Supplier<*> = Supplier<Any> { t }
|
||||
LOG.info("test {}", Supplier<Any> { "test" }, s2)
|
||||
val s3: Supplier<*> = Supplier { t }
|
||||
LOG.info("test {}", Supplier<Any> { "test" }, s3)
|
||||
LOG.info("test {}", Supplier<Any> { "test" }, Supplier<Any> { RuntimeException() })
|
||||
LOG.info("test {}", Supplier<Any> { "test" })
|
||||
LOG.info(<warning descr="More arguments provided (2) than placeholders specified (1)">"test {}"</warning>, {""}, {" "})
|
||||
LOG.info("test {}", {""}, {RuntimeException()})
|
||||
val function: () -> String = { "RuntimeException()" }
|
||||
LOG.info(<warning descr="More arguments provided (2) than placeholders specified (1)">"test {}"</warning>, {""}, function)
|
||||
val function2: () -> RuntimeException = { RuntimeException() }
|
||||
LOG.info("test {}", {""}, function2)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
|
||||
fun `test error type`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
|
||||
class Log4j {
|
||||
fun m() {
|
||||
var e = <error descr="[UNRESOLVED_REFERENCE] Unresolved reference: Ce">Ce</error>;
|
||||
LOG.error(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"1 {} {} {}"</warning> , <error descr="[DEBUG] Resolved to error element">e</error>, <error descr="[DEBUG] Resolved to error element">e</error>)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOG = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test formatted log4j with partial known strings`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
|
||||
internal object Logging {
|
||||
private val logger = LogManager.getFormatterLogger()
|
||||
fun test(t: String) {
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (at least 1)">"%s" + t + 1 + "%s "</warning> )
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (at least 2)">"%s %s" + t + 1</warning> )
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (2)">"%s %s"</warning>, 1)
|
||||
logger.atDebug().log("%s t", 1)
|
||||
val logBuilder = logger.atDebug()
|
||||
logBuilder.log(<warning descr="More arguments provided (2) than placeholders specified (0)">"%s t"</warning>, 1, 2)
|
||||
logger.info(<warning descr="More arguments provided (2) than placeholders specified (1)">"%s t"</warning>, 2, 2)
|
||||
logger.info("%s t", 2)
|
||||
logger.info(<warning descr="More arguments provided (2) than placeholders specified (1)">"%s t"</warning>, 2, 3)
|
||||
}
|
||||
}
|
||||
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test log4j with partial known strings`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
|
||||
internal object Logging {
|
||||
private val logger = LogManager.getLogger()
|
||||
fun test(t: String) {
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (at least 2)">"{}" + t + 1 + "{}"</warning> )
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (at least 2)">"{}" + t + 1 + "{}"</warning> , RuntimeException())
|
||||
logger.info( <warning descr="Fewer arguments provided (1) than placeholders specified (at least 3)">"{} {}" + t + 1 + "{}"</warning> , 1, RuntimeException())
|
||||
logger.info("{}" + t + 1 + "{}", 1, RuntimeException())
|
||||
logger.info("{}" + t + 1 + "{}", 1, 1)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.logging
|
||||
|
||||
import com.intellij.codeInspection.logging.LoggingPlaceholderCountMatchesArgumentCountInspection
|
||||
import com.intellij.jvm.analysis.internal.testFramework.logging.LoggingPlaceholderCountMatchesArgumentCountInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinLoggingPlaceholderCountMatchesArgumentCountInspectionPlaceholderNumberTest : LoggingPlaceholderCountMatchesArgumentCountInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test many variables`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
var LOGGER = LoggerFactory.getLogger()
|
||||
fun m() {
|
||||
val a1 = " {} " +" s"
|
||||
val a2 = a1 + a1 + a1 + a1 + a1 + a1 + a1 + a1 + a1
|
||||
LOGGER.info( <warning descr="Fewer arguments provided (1) than placeholders specified (at least 3)">"abd"+a2</warning> , 1)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test variables`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
private const val con = "{}"
|
||||
|
||||
internal class X {
|
||||
var logger = LoggerFactory.getLogger()
|
||||
private var con2 = "{}"
|
||||
|
||||
private fun slf4jVariable3(number: String) {
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">number + "1 {} {}"</warning>, 1) //warn
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">number + "1 {} {}"</warning>, 1) //warn
|
||||
var t = "{}"
|
||||
logger.info(con2 + t + "1", 1)
|
||||
logger.info(con2 + t + "1", 1)
|
||||
}
|
||||
|
||||
private fun slf4jVariable(number: String) {
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">number + "1 {} {}"</warning>, 1) //warn
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">number + "1 {} {}"</warning>, 1) //warn
|
||||
var t = "{}"
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (2)">con + t + "1"</warning>, 1) //warn
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (2)">con + t + "1"</warning>, 1) //warn
|
||||
}
|
||||
|
||||
private fun slf4jVariable2(number: String) {
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">number + "1 {} {}"</warning>, 1) //warn
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">number + "1 {} {}"</warning>, 1) //warn
|
||||
var t = "{}"
|
||||
logger.info(con + t + "1", 1)
|
||||
t = "1"
|
||||
logger.info(con + t + "1", 1)
|
||||
}
|
||||
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test fewer and more placeholders`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.*;
|
||||
internal class X {
|
||||
fun foo() {
|
||||
val logger = LoggerFactory.getLogger()
|
||||
logger.info( <warning descr="Fewer arguments provided (1) than placeholders specified (2)">"string {}{}"</warning> , 1)
|
||||
logger.info( <warning descr="More arguments provided (1) than placeholders specified (0)">"string"</warning> , 1)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test escaping`() {
|
||||
inspection.slf4jToLog4J2Type = LoggingPlaceholderCountMatchesArgumentCountInspection.Slf4jToLog4J2Type.NO
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
|
||||
internal class X {
|
||||
var LOG = LoggerFactory.getLogger()
|
||||
fun m() {
|
||||
LOG.info("Created key {}\\\\{}", 1, 2)
|
||||
LOG.info( <warning descr="More arguments provided (2) than placeholders specified (1)">"Created key {}\\{}"</warning> , 1, 2)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test non constant string`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
val LOG = LoggerFactory.getLogger()
|
||||
fun m() {
|
||||
LOG.info( <warning descr="Fewer arguments provided (0) than placeholders specified (4)">S + "{}" + (1 + 2) + '{' + '}' + S</warning> )
|
||||
LOG.info( <warning descr="Fewer arguments provided (0) than placeholders specified (1)">message</warning> )
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val message = "HELLO {}"
|
||||
private const val S = "{}"
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test 1 exception and several placeholder`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun foo() {
|
||||
val e = RuntimeException()
|
||||
LoggerFactory.getLogger().info( <warning descr="Fewer arguments provided (0) than placeholders specified (1)">"this: {}"</warning> , e)
|
||||
LoggerFactory.getLogger().info("1: {} e: {}", 1, e)
|
||||
LoggerFactory.getLogger().info( <warning descr="Fewer arguments provided (1) than placeholders specified (3)">"1: {} {} {}"</warning> , 1, e)
|
||||
val logger = LoggerFactory.getLogger()
|
||||
logger.info("string {}", 1)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test throwable`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun foo() {
|
||||
val logger = LoggerFactory.getLogger()
|
||||
logger.info("string {}", 1, RuntimeException())
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test multi catch`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun multiCatch() {
|
||||
try {
|
||||
method()
|
||||
} catch (e: FirstException) {
|
||||
logger.info("failed with first or second", e)
|
||||
} catch (e: SecondException) {
|
||||
logger.info("failed with first or second", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun method() {
|
||||
}
|
||||
|
||||
class FirstException : Exception()
|
||||
class SecondException : Exception()
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test no slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
internal class FalsePositiveSLF4J {
|
||||
fun method(definitelyNotSLF4J: DefinitelyNotSLF4J) {
|
||||
definitelyNotSLF4J.info("not a trace message", "not a trace parameter")
|
||||
}
|
||||
|
||||
interface DefinitelyNotSLF4J {
|
||||
fun info(firstParameter: String?, secondParameter: Any?)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test array argument`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
var LOG = LoggerFactory.getLogger()
|
||||
fun m(a: String, b: Int, c: Any) {
|
||||
LOG.info("test {} for test {} in test {}", *arrayOf(a, b, c))
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test uncountable array`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
var LOG = LoggerFactory.getLogger()
|
||||
fun m(objects: Array<Any?>) {
|
||||
LOG.info("test {} test text {} text {}", *objects)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.logging
|
||||
|
||||
import com.intellij.codeInspection.logging.LoggingPlaceholderCountMatchesArgumentCountInspection
|
||||
import com.intellij.jvm.analysis.internal.testFramework.logging.LoggingPlaceholderCountMatchesArgumentCountInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinLoggingPlaceholderCountMatchesArgumentCountInspectionSlf4JTest : LoggingPlaceholderCountMatchesArgumentCountInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test slf4j disable slf4jToLog4J2Type`() {
|
||||
inspection.slf4jToLog4J2Type = LoggingPlaceholderCountMatchesArgumentCountInspection.Slf4jToLog4J2Type.NO
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun foo(s: String) {
|
||||
val logger = LoggerFactory.getLogger()
|
||||
logger.info( <warning descr="Fewer arguments provided (1) than placeholders specified (2)">"string {} {}"</warning> , 1, RuntimeException())
|
||||
logger.info(<warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">s + "string {} {}"</warning> , 1, RuntimeException())
|
||||
logger.info(s + "string {} {}" , 1, 2)
|
||||
logger.atError().log( <warning descr="Fewer arguments provided (0) than placeholders specified (1)">"{}"</warning> , RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log( <warning descr="Fewer arguments provided (1) than placeholders specified (2)">"{} {}"</warning> , 1, RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log("{}", 1, RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log(s + "{}", 1, RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log(s + "{}", 1, 2)
|
||||
LoggerFactory.getLogger().atError().log(<warning descr="More arguments provided (1) than placeholders specified (0)">""</warning>, 1, RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log(<warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">s + "{} {} {}"</warning>, 1, RuntimeException("test"))
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test slf4j auto slf4jToLog4J2Type`() {
|
||||
inspection.slf4jToLog4J2Type = LoggingPlaceholderCountMatchesArgumentCountInspection.Slf4jToLog4J2Type.AUTO
|
||||
myFixture.addClass("""
|
||||
package org.apache.logging.slf4j;
|
||||
public interface Log4jLogger {
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun foo() {
|
||||
val logger = LoggerFactory.getLogger()
|
||||
logger.info("string {} {}", 1, RuntimeException())
|
||||
logger.atError().log("{}", RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log("{} {}", 1, RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log( <warning descr="More arguments provided (2) than placeholders specified (1)">"{}"</warning> , 1, RuntimeException("test"))
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test slf4j`() {
|
||||
inspection.slf4jToLog4J2Type = LoggingPlaceholderCountMatchesArgumentCountInspection.Slf4jToLog4J2Type.NO
|
||||
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.*;
|
||||
|
||||
private val logger: Logger? = null
|
||||
private val brackets: String = "{}"
|
||||
|
||||
fun foo() {
|
||||
logger?.debug(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.debug("test {} {}", *arrayOf(1, 2))
|
||||
logger?.debug("test {} {}", *arrayOf(1, 2, Exception()))
|
||||
logger?.debug(<warning descr="More arguments provided (2) than placeholders specified (1)">"test " + brackets</warning>, 1, 2) //warn
|
||||
logger?.debug("test {}" + brackets, 1, 2)
|
||||
logger?.debug("test {} {}", 1, 2)
|
||||
logger?.debug(<warning descr="Fewer arguments provided (1) than placeholders specified (2)">"test {} \\{} {}"</warning>, 1) //warn
|
||||
logger?.debug("test {} \\{} {}", 1, 2)
|
||||
logger?.debug(<warning descr="Fewer arguments provided (1) than placeholders specified (2)">"test {} {}"</warning>, 1, Exception()) //warn
|
||||
logger?.debug("test {} {}", 1, 2, Exception())
|
||||
logger?.debug(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.debug(<warning descr="More arguments provided (2) than placeholders specified (1)">"test {}"</warning>, 1, 2) //warn
|
||||
logger?.error(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.info(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.trace(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
logger?.warn(<warning descr="Fewer arguments provided (2) than placeholders specified (3)">"test {} {} {}"</warning>, 1, 2) //warn
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test slf4j with partial known strings`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.util.*
|
||||
|
||||
internal class X {
|
||||
var logger = LoggerFactory.getLogger()
|
||||
fun m(t: String) {
|
||||
logger.info("{} {}", 1, 2)
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (at least 2)">"{}" + t + 1 + "{}"</warning> )
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (at least 1)">"{}" + t + 1</warning> )
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (at least 1)">"{}${'$'}t{}"</warning> )
|
||||
logger.info("{}${'$'}t{}", 1, 2)
|
||||
logger.info("{}${'$'}t{}", 1, 2, 3)
|
||||
val temp1 = "{} {}${'$'}t"
|
||||
var temp = "{} {}${'$'}t"
|
||||
logger.info( <warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">temp1</warning> , 1)
|
||||
logger.info(temp, 1, 2, 3)
|
||||
logger.info(logText, 1, 2, 3)
|
||||
logger.info( <warning descr="Fewer arguments provided (1) than placeholders specified (at least 2)">logText</warning> , 1)
|
||||
logger.info( <warning descr="Fewer arguments provided (1) than placeholders specified (at least 3)">logText2</warning> , 1)
|
||||
logger.info( <warning descr="Fewer arguments provided (1) than placeholders specified (3)">logText3</warning> , 1)
|
||||
temp = "{}${'$'}t"
|
||||
logger.info(temp, 1)
|
||||
}
|
||||
|
||||
fun m(i: Int, s: String) {
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (1)">"test1 {}"</warning> )
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (at least 1)">"test1 {}${'$'}s"</warning> )
|
||||
logger.info( <warning descr="Fewer arguments provided (0) than placeholders specified (1)">"test1 {}${'$'}i"</warning> )
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private val logText = "{} {}" + something
|
||||
private val logText2 = "{} {}" + 1 + "{}" + something
|
||||
private const val logText3 = "{} {}" + 1 + "{}"
|
||||
private val something: String
|
||||
get() = if (Random().nextBoolean()) "{}" else ""
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test slf4j builder`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.slf4j.spi.LoggingEventBuilder
|
||||
|
||||
fun foo() {
|
||||
LoggerFactory.getLogger().atError().log("{}", RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log("{} {}", 1, RuntimeException("test"))
|
||||
LoggerFactory.getLogger().atError().log( <warning descr="More arguments provided (2) than placeholders specified (1)">"{}"</warning> , 1, RuntimeException("test"))
|
||||
logger2.atError().log(<warning descr="Fewer arguments provided (1) than placeholders specified (2)">"{} {}"</warning>, 1)
|
||||
|
||||
val loggingEventBuilder = logger2.atError()
|
||||
loggingEventBuilder
|
||||
.log("{} {}", 2) //skip, because it can be complex cases
|
||||
|
||||
logger2.atError()
|
||||
.log(<warning descr="Fewer arguments provided (1) than placeholders specified (2)">"{} {}"</warning>, 2) //warn
|
||||
|
||||
logger2.atError()
|
||||
.addArgument("s")
|
||||
.addKeyValue("1", "1")
|
||||
.log("{} {}", 2)
|
||||
|
||||
logger2.atError()
|
||||
.setMessage(<warning descr="Fewer arguments provided (0) than placeholders specified (2)">"{} {}"</warning>)
|
||||
.log()
|
||||
|
||||
logger2.atError()
|
||||
.addArgument("")
|
||||
.addArgument("")
|
||||
.setMessage("{} {}")
|
||||
.log()
|
||||
}
|
||||
|
||||
private val logger2 = LoggerFactory.getLogger()
|
||||
private val builder: LoggingEventBuilder = logger2.atError()
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.logging
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.logging.LoggingSimilarMessageInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinLoggingSimilarMessageInspectionTest : LoggingSimilarMessageInspectionTestBase(), KotlinPluginModeProvider {
|
||||
|
||||
fun `test equals log4j2`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
|
||||
internal class Logging {
|
||||
private val logger: Logger = LogManager.getLogger()
|
||||
|
||||
private fun request1(i: String) {
|
||||
val msg = "log messages: {}"
|
||||
logger.<weak_warning descr="Similar log messages">info(msg, i)</weak_warning>
|
||||
}
|
||||
|
||||
private fun request2(i: Int) {
|
||||
val msg = "log messages: {}"
|
||||
logger.<weak_warning descr="Similar log messages">info(msg, i)</weak_warning>
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test equals slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class Logging {
|
||||
private val LOG: Logger = LoggerFactory.getLogger(Logging::class.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: java">java</error>)
|
||||
|
||||
private fun request1(i: String) {
|
||||
val msg = "log messages: {}"
|
||||
LOG.<weak_warning descr="Similar log messages">info(msg, i)</weak_warning>
|
||||
LOG.info("1" + msg, i)
|
||||
}
|
||||
|
||||
private fun request2(i: Int) {
|
||||
val msg = "log messages: {}"
|
||||
LOG.<weak_warning descr="Similar log messages">info(msg, i)</weak_warning>
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test setMessage slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class Logging {
|
||||
private val LOG: Logger = LoggerFactory.getLogger(Logging::class.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: java">java</error>)
|
||||
|
||||
private fun request1(i: String) {
|
||||
val msg = "log messages: {}" + i
|
||||
LOG.atInfo().setCause(RuntimeException()).setMessage(msg).log()
|
||||
LOG.atInfo().setMessage(msg).<weak_warning descr="Similar log messages">log()</weak_warning>
|
||||
}
|
||||
|
||||
private fun request2(i: Int) {
|
||||
val msg = "log messages: {}" + i
|
||||
LOG.atInfo().setCause(RuntimeException()).setMessage(msg).log()
|
||||
LOG.atInfo().setMessage(msg).<weak_warning descr="Similar log messages">log()</weak_warning>
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test skip in the middle parts`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class Logging {
|
||||
private val LOG: Logger = LoggerFactory.getLogger(Logging::class.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: java">java</error>)
|
||||
|
||||
private fun request1(i: String) {
|
||||
val msg = "${"\${i}"}1234356${"\${i}"}"
|
||||
LOG.info(msg)
|
||||
}
|
||||
|
||||
private fun request2(i: Int) {
|
||||
val msg = "something 1234356${"\${i}"}"
|
||||
LOG.info(msg)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test skip inside calls`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class Logging {
|
||||
private val LOG: Logger = LoggerFactory.getLogger(Logging::class.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: java">java</error>)
|
||||
|
||||
private fun request2() {
|
||||
LOG.warn("Non-cached operation ${"\${operationName(\"update\")}"}")
|
||||
LOG.warn("Non-cached operation ${"\${operationName(\"getChildren\")}"}")
|
||||
}
|
||||
|
||||
private fun operationName(operationName: String): String {
|
||||
return operationName
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.logging
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle
|
||||
import com.intellij.jvm.analysis.internal.testFramework.logging.LoggingStatementNotGuardedByLogConditionInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinLoggingStatementNotGuardedByLogConditionInspectionTest : LoggingStatementNotGuardedByLogConditionInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
private val LOG = LoggerFactory.getLogger()
|
||||
|
||||
fun n(arg: String) {
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test {}", arg)</warning>
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test log4j2`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test {}", arg)</warning>
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOG: Logger = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test skip according level for slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
LOG.warn("test " + arg)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test is surrounded by guard for slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("test " + arg)
|
||||
}
|
||||
|
||||
if (LOG.isInfoEnabled) {
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test" + arg)</warning> //todo!
|
||||
}
|
||||
|
||||
if (true && LOG.isDebugEnabled) {
|
||||
LOG.debug("test {}", arg)
|
||||
}
|
||||
|
||||
if (true && LOG.isDebugEnabled) {
|
||||
if (true) {
|
||||
LOG.debug("test {}", arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test skip if only constant arguments for slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n() {
|
||||
LOG.debug("test")
|
||||
LOG.debug("test {} {}", "test" + "test", 1 + 1)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test don't skip if only constant arguments for slf4j flagUnguardedConstant`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n1() {
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test")</warning>
|
||||
}
|
||||
|
||||
fun n2() {
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test")</warning>
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test skip with several log calls for slf4j`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n2(arg: String) {
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test1" + arg)</warning>
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
|
||||
fun n3(arg: String) {
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test1" + arg)</warning>
|
||||
LOG.debug("test2" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
|
||||
fun constantCall(arg: String) {
|
||||
LOG.debug("test1")
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test2" + arg)</warning>
|
||||
}
|
||||
|
||||
fun beforeNotLog(arg: String) {
|
||||
constantCall(arg)
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test2" + arg)</warning>
|
||||
}
|
||||
|
||||
fun differentLevels(arg: String) {
|
||||
<warning descr="Logging call not guarded by a logging condition">LOG.debug("test1" + arg)</warning>
|
||||
LOG.warn("test2" + arg)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test fix simple slf4j`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
LOG.<caret>debug("test" + arg)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("test" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.log.statement.not.guarded.log.fix.family.name")
|
||||
)
|
||||
}
|
||||
|
||||
fun `test fix simple nested slf4j`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = false,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if(true){
|
||||
LOG.<caret>debug("test" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if(true){
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("test" + arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.log.statement.not.guarded.log.fix.family.name")
|
||||
)
|
||||
}
|
||||
|
||||
fun `test fix several similar slf4j`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
LOG.<caret>debug("test1" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("test1" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.log.statement.not.guarded.log.fix.family.name")
|
||||
)
|
||||
}
|
||||
|
||||
fun `test fix several different slf4j`() {
|
||||
myFixture.testQuickFix(
|
||||
testPreview = true,
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
before = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
LOG.<caret>debug("test1" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
LOG.info("test3" + arg)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
after = """
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
internal class X {
|
||||
fun n(arg: String) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("test1" + arg)
|
||||
LOG.debug("test2" + arg)
|
||||
}
|
||||
LOG.info("test3" + arg)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG: Logger = LoggerFactory.getLogger()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
hint = JvmAnalysisBundle.message("jvm.inspection.log.statement.not.guarded.log.fix.family.name")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.logging
|
||||
|
||||
import com.intellij.codeInspection.logging.LoggingStringTemplateAsArgumentInspection
|
||||
import com.intellij.codeInspection.logging.LoggingUtil
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.jvm.analysis.internal.testFramework.logging.LoggingStringTemplateAsArgumentInspectionTestBase
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
private const val INSPECTION_PATH = "/codeInspection/logging/stringTemplateAsArgument"
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData$INSPECTION_PATH")
|
||||
abstract class KotlinLoggingStringTemplateAsArgumentInspectionTest : LoggingStringTemplateAsArgumentInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override val inspection: LoggingStringTemplateAsArgumentInspection = LoggingStringTemplateAsArgumentInspection().apply {
|
||||
myLimitLevelType = LoggingUtil.LimitLevelType.ALL
|
||||
}
|
||||
|
||||
override fun getBasePath() = KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + INSPECTION_PATH
|
||||
|
||||
private fun withSettings(
|
||||
skipPrimitives: Boolean = inspection.mySkipPrimitives,
|
||||
levelType: LoggingUtil.LimitLevelType = inspection.myLimitLevelType,
|
||||
skipWithTheOnlyException: Boolean = inspection.mySkipWithTheOnlyException,
|
||||
test: () -> Unit
|
||||
) {
|
||||
val curSkipPrimitives = inspection.mySkipPrimitives
|
||||
val curLimitLevelType = inspection.myLimitLevelType
|
||||
val curSkipWithTheOnlyException = inspection.mySkipWithTheOnlyException
|
||||
try {
|
||||
inspection.mySkipPrimitives = skipPrimitives
|
||||
inspection.myLimitLevelType = levelType
|
||||
inspection.mySkipWithTheOnlyException = skipWithTheOnlyException
|
||||
test()
|
||||
} finally {
|
||||
inspection.mySkipPrimitives = curSkipPrimitives
|
||||
inspection.myLimitLevelType = curLimitLevelType
|
||||
inspection.mySkipWithTheOnlyException = curSkipWithTheOnlyException
|
||||
}
|
||||
}
|
||||
|
||||
fun `test default settings highlighting, with guards`() {
|
||||
myFixture.testHighlighting("StringTemplateAsArgumentGuarded.kt")
|
||||
}
|
||||
|
||||
fun `test highlighting info and lower no skip primitives`() {
|
||||
withSettings(skipPrimitives = false, levelType = LoggingUtil.LimitLevelType.INFO_AND_LOWER) {
|
||||
myFixture.testHighlighting("StringTemplateAsArgumentWarnInfo.kt")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test highlighting debug no skip primitives`() {
|
||||
withSettings(skipPrimitives = false, LoggingUtil.LimitLevelType.DEBUG_AND_LOWER) {
|
||||
myFixture.testHighlighting("StringTemplateAsArgumentWarnDebug.kt")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test highlighting all skip primitives`() {
|
||||
withSettings(skipPrimitives = true, LoggingUtil.LimitLevelType.ALL) {
|
||||
myFixture.testHighlighting("StringTemplateAsArgumentSkipPrimitives.kt")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test highlighting all no skip primitives`() {
|
||||
withSettings(skipPrimitives = false, LoggingUtil.LimitLevelType.ALL) {
|
||||
myFixture.testHighlighting("StringTemplateAsArgument.kt")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test fix all no skip primitives`() {
|
||||
withSettings(skipPrimitives = false, LoggingUtil.LimitLevelType.ALL) {
|
||||
myFixture.testQuickFix("StringTemplateAsArgumentFix.kt", checkPreview = true)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test fix with escape symbol all no skip primitives`() {
|
||||
withSettings(skipPrimitives = false, LoggingUtil.LimitLevelType.ALL) {
|
||||
myFixture.testQuickFix("StringTemplateAsArgumentWithEscapeSymbolsFix.kt", checkPreview = true)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test highlighting all no skip primitives skip with the only exception`() {
|
||||
withSettings(skipPrimitives = false, LoggingUtil.LimitLevelType.ALL, skipWithTheOnlyException = true) {
|
||||
myFixture.testHighlighting("StringTemplateAsArgumentSkipException.kt")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.performance
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.performance.UrlHashCodeInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinUrlHashCodeInspectionTest : UrlHashCodeInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test url hashcode call`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.net.URL
|
||||
|
||||
class UrlHashCode {
|
||||
@Suppress("DEPRECATION")
|
||||
fun foo() {
|
||||
val url = URL("")
|
||||
url.<warning descr="Call to 'hashCode()' on URL object">hashCode</warning>()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test url equals call`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.net.URL
|
||||
|
||||
class UrlHashCodeEquals {
|
||||
@Suppress("DEPRECATION")
|
||||
fun foo() {
|
||||
val url1 = URL("")
|
||||
val url2 = URL("")
|
||||
url1 <warning descr="Call to 'equals()' on URL object">==</warning> url2
|
||||
url1.<warning descr="Call to 'equals()' on URL object">equals</warning>(url2)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test url variable with URL maps or sets`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
|
||||
class CollectionContainsUrl {
|
||||
val strMap: Map<String, String> = HashMap()
|
||||
val <warning descr="'urlMap' may contain URL objects">urlMap</warning>: Map<URL, String> = HashMap()
|
||||
val <warning descr="'urlMapOfMap' may contain URL objects">urlMapOfMap</warning>: Map<String, Map<URL, String>> = HashMap()
|
||||
val <warning descr="'urlSet' may contain URL objects">urlSet</warning>: Set<URL> = HashSet()
|
||||
val <warning descr="'urlSetOfMap' may contain URL objects">urlSetOfMap</warning>: Set<Map<URL, String>> = HashSet()
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test url URL map operations`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
|
||||
class CollectionContainsUrl {
|
||||
val objMap: MutableMap<Any, Any> = HashMap()
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun foo() {
|
||||
<warning descr="'objMap' may contain URL objects">objMap</warning>.put(URL(""), "")
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test url URL set operations`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
|
||||
class CollectionContainsUrl {
|
||||
val objSet: MutableSet<Any> = HashSet()
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun foo() {
|
||||
<warning descr="'objSet' may contain URL objects">objSet</warning>.add(URL(""))
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test URL doesn't highlight when comparing with null`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import java.net.URL
|
||||
|
||||
@Suppress("DEPRECATION", "SENSELESS_COMPARISON")
|
||||
fun main() {
|
||||
val sample = URL("")
|
||||
if (sample == null) {}
|
||||
if (null == sample) {}
|
||||
sample.equals(null)
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.sourceToSink
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.jvm.analysis.internal.testFramework.sourceToSink.SourceToSinkFlowInspectionTestBase
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
private const val inspectionPath = "/codeInspection/sourceToSinkFlow/markAsSafeFix"
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData$inspectionPath")
|
||||
abstract class KotlinMarkAsSafeFixSourceToSinkFlowInspectionTest : SourceToSinkFlowInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override fun getBasePath() = KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + inspectionPath
|
||||
|
||||
fun `test common cases with checkFramework`() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testQuickFix("CommonCasesCheckFramework.kt", getMessage(), false)
|
||||
}
|
||||
|
||||
fun `test common cases with jsr`() {
|
||||
prepareJsr()
|
||||
myFixture.testQuickFix("CommonCasesJsr.kt", getMessage(), false)
|
||||
}
|
||||
|
||||
private fun getMessage(): @Nls String = JvmAnalysisBundle.message("jvm.inspections.source.unsafe.to.sink.flow.mark.as.safe.text")
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.sourceToSink
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle
|
||||
import com.intellij.jvm.analysis.KotlinJvmAnalysisTestUtil
|
||||
import com.intellij.jvm.analysis.internal.testFramework.sourceToSink.SourceToSinkFlowInspectionTestBase
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
private const val INSPECTION_PATH = "/codeInspection/sourceToSinkFlow"
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData$INSPECTION_PATH")
|
||||
abstract class KotlinSourceToSinkFlowInspectionTest : SourceToSinkFlowInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override fun getBasePath() = KotlinJvmAnalysisTestUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH + INSPECTION_PATH
|
||||
|
||||
fun testSimple() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("Simple.kt")
|
||||
}
|
||||
|
||||
fun testLocalInference() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("LocalInference.kt")
|
||||
}
|
||||
|
||||
fun testSink() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("Sink.kt")
|
||||
}
|
||||
|
||||
fun testSinkJsr() {
|
||||
prepareJsr()
|
||||
myFixture.testHighlighting("SinkJsr.kt")
|
||||
}
|
||||
|
||||
fun testCall() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("Call.kt")
|
||||
}
|
||||
|
||||
fun testLocalVariable() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("LocalVariables.kt")
|
||||
}
|
||||
|
||||
fun testParameters() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("Parameters.kt")
|
||||
}
|
||||
|
||||
fun testEnumAnnotations() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("EnumAnnotations.kt")
|
||||
}
|
||||
|
||||
fun testFields() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("Fields.kt")
|
||||
}
|
||||
|
||||
fun testStructure() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("Structure.kt")
|
||||
}
|
||||
|
||||
fun testMethodPropagation() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("MethodPropagation.kt")
|
||||
}
|
||||
|
||||
fun testKotlinPropertyPropagateFix() {
|
||||
prepareCheckFramework()
|
||||
myFixture.configureByFile("Property.kt")
|
||||
val propagateAction = myFixture.getAvailableIntention(
|
||||
JvmAnalysisBundle.message("jvm.inspections.source.unsafe.to.sink.flow.propagate.safe.text"))!!
|
||||
myFixture.launchAction(propagateAction)
|
||||
myFixture.checkResultByFile("Property.after.kt")
|
||||
}
|
||||
|
||||
fun testLimits() {
|
||||
prepareCheckFramework()
|
||||
myFixture.addClass("""
|
||||
@SuppressWarnings({"FieldMayBeStatic", "StaticNonFinalField", "RedundantSuppression"})
|
||||
public class Limit2 {
|
||||
|
||||
public final static String fromAnotherFile = "1";
|
||||
public final static String fromAnotherFile2 = fromAnotherFile;
|
||||
public final static String fromAnotherFile3 = fromMethod();
|
||||
public static String fromAnotherFile4 = "1";
|
||||
public final String fromAnotherFile5 = "1";
|
||||
public final String fromAnotherFile6;
|
||||
|
||||
public Limit2() {
|
||||
this.fromAnotherFile6 = "";
|
||||
}
|
||||
|
||||
private static String fromMethod() {
|
||||
return "null";
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
myFixture.testHighlighting("Limits.kt")
|
||||
}
|
||||
|
||||
fun testMethodsAsFields() {
|
||||
prepareCheckFramework()
|
||||
myFixture.addClass("""
|
||||
public class MethodAsFields {
|
||||
private static final String t = "1";
|
||||
|
||||
public String getT() {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
myFixture.testHighlighting("MethodsAsFields.kt")
|
||||
}
|
||||
|
||||
fun testDifferentExpressions() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("DifferentExpressions.kt")
|
||||
}
|
||||
|
||||
fun testKotlinConstructorArguments() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("KotlinConstructorArguments.kt")
|
||||
}
|
||||
|
||||
fun testKotlinParameters() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("KotlinParameters.kt")
|
||||
}
|
||||
|
||||
fun testDropLocality() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("DropLocality.kt")
|
||||
}
|
||||
|
||||
fun `test forEachLoop`() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("ForEachLoop.kt")
|
||||
}
|
||||
|
||||
fun `test lambdaWithForEachLoop`() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("LambdaWithForEachLoop.kt")
|
||||
}
|
||||
|
||||
fun `test if`() {
|
||||
prepareCheckFramework()
|
||||
myFixture.testHighlighting("ifStatement.kt")
|
||||
}
|
||||
|
||||
fun `test custom through tables`() {
|
||||
inspection.untaintedParameterIndex.apply {
|
||||
this.clear()
|
||||
this.add("1")
|
||||
}
|
||||
inspection.untaintedParameterMethodClass.apply {
|
||||
this.clear()
|
||||
this.add("FromMethod")
|
||||
}
|
||||
inspection.untaintedParameterMethodName.apply {
|
||||
this.clear()
|
||||
this.add("sink")
|
||||
}
|
||||
|
||||
inspection.taintedParameterIndex.apply {
|
||||
this.clear()
|
||||
this.add("0")
|
||||
}
|
||||
inspection.taintedParameterMethodClass.apply {
|
||||
this.clear()
|
||||
this.add("FromMethod")
|
||||
}
|
||||
inspection.taintedParameterMethodName.apply {
|
||||
this.clear()
|
||||
this.add("test")
|
||||
}
|
||||
|
||||
inspection.setTaintedMethod("java.lang.String", "toString")
|
||||
inspection.setUntaintedMethod("java.lang.String", "trim")
|
||||
|
||||
myFixture.testHighlighting("FromMethod.kt")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.test
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.test.AssertEqualsBetweenInconvertibleTypesInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
import java.io.File
|
||||
|
||||
abstract class KotlinAssertEqualsBetweenInconvertibleTypesInspectionTest : AssertEqualsBetweenInconvertibleTypesInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = object : AssertJProjectDescriptor(LanguageLevel.HIGHEST) {
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
super.configureModule(module, model, contentEntry)
|
||||
val jar = File(PathUtil.getJarPathForClass(JvmStatic::class.java))
|
||||
PsiTestUtil.addLibrary(model, "kotlin-stdlib", jar.parent, jar.name)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test AssertJ incompatible types`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
|
||||
class AssertEqualsBetweenInconvertibleTypes {
|
||||
@org.junit.jupiter.api.Test
|
||||
fun myTest() {
|
||||
assertThat(1).<warning descr="'isSameAs()' between objects of inconvertible types 'int' and 'String'">isSameAs</warning>("foo")
|
||||
Assertions.assertThat("foo").<warning descr="'isEqualTo()' between objects of inconvertible types 'String' and 'int'">isEqualTo</warning>(2)
|
||||
Assertions.assertThat("foo").isEqualTo("bar") //ok
|
||||
assertThat("foo").describedAs("foo").<warning descr="'isEqualTo()' between objects of inconvertible types 'String' and 'int'">isEqualTo</warning>(2)
|
||||
Assertions.assertThat("foo").<warning descr="'isEqualTo()' between objects of inconvertible types 'String' and 'int'">isEqualTo</warning>(2)
|
||||
Assertions.assertThat(1).<warning descr="'isSameAs()' between objects of inconvertible types 'int' and 'String'">isSameAs</warning>("foo")
|
||||
Assertions.assertThat("foo").describedAs("foo").<warning descr="'isSameAs()' between objects of inconvertible types 'String' and 'int'">isSameAs</warning>(2)
|
||||
assertThat(IntArray(2)).`as`("array").<warning descr="'isSameAs()' between objects of inconvertible types 'int[]' and 'int'">isSameAs</warning>(2)
|
||||
Assertions.assertThat("foo").`as`("foo").<warning descr="'isEqualTo()' between objects of inconvertible types 'String' and 'int'">isEqualTo</warning>(2)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
// TODO type is not displayed correctly here, something goes wrong with KT to Java type converter
|
||||
fun `_test AssertJ single element wrong type`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.assertj.core.api.Assertions
|
||||
|
||||
class MyTest {
|
||||
@org.junit.jupiter.api.Test
|
||||
fun testSingleElement() {
|
||||
Assertions.assertThat(listOf(1))
|
||||
.singleElement()
|
||||
.<warning descr="'isEqualTo()' between objects of inconvertible types 'Integer' and 'String'">isEqualTo</warning>("1")
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
// TODO type is not displayed correctly here, something goes wrong with KT to Java type converter
|
||||
fun `_test AssertJ is equal to null`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.assertj.core.api.Assertions
|
||||
|
||||
class MyTest {
|
||||
fun myNullable(): MyTest? = null
|
||||
|
||||
@org.junit.jupiter.api.Test
|
||||
fun testExtractingNoHighlight() {
|
||||
Assertions.assertThat(myNullable()).isEqualTo(null)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
// Fails on TC for unknown reason
|
||||
fun `_test AssertJ single element extracting type mismatch`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.assertj.core.api.Assertions
|
||||
|
||||
class MyTest {
|
||||
@org.junit.jupiter.api.Test
|
||||
fun testExtractingNoHighlight() {
|
||||
Assertions.assertThat(listOf(1))
|
||||
.singleElement()
|
||||
.extracting(Any::toString)
|
||||
.<warning descr="'isEqualTo()' between objects of inconvertible types 'String' and 'int'">isEqualTo</warning>(1)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
// Fails on TC for unknown reason
|
||||
fun `_test AssertJ extracting single element type mismatch`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.assertj.core.api.Assertions
|
||||
|
||||
class MyTest {
|
||||
@org.junit.jupiter.api.Test
|
||||
fun testExtractingNoHighlight() {
|
||||
Assertions.assertThat(listOf(1))
|
||||
.extracting(Any::toString)
|
||||
.singleElement()
|
||||
.<warning descr="'isEqualTo()' between objects of inconvertible types 'String' and 'int'">isEqualTo</warning>(1)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test AssertJ extracting as method reference type match`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.assertj.core.api.Assertions
|
||||
|
||||
class MyTest {
|
||||
@org.junit.jupiter.api.Test
|
||||
fun testExtractingNoHighlight() {
|
||||
Assertions.assertThat(1)
|
||||
.describedAs("Mapping to String")
|
||||
.extracting(Any::toString)
|
||||
.isEqualTo("1")
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test AssertJ extracting as lambda type match`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.assertj.core.api.Assertions
|
||||
|
||||
class MyTest {
|
||||
@org.junit.jupiter.api.Test
|
||||
fun testExtractingNoHighlight() {
|
||||
Assertions.assertThat(1)
|
||||
.describedAs("Mapping to String")
|
||||
.extracting { value -> "${"$"}value" }
|
||||
.isEqualTo("1")
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.test
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.test.TestCaseWithConstructorInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
import java.io.File
|
||||
|
||||
abstract class KotlinTestCaseWithConstructorInspectionTest : TestCaseWithConstructorInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = object : JUnitProjectDescriptor(LanguageLevel.HIGHEST) {
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
super.configureModule(module, model, contentEntry)
|
||||
val jar = File(PathUtil.getJarPathForClass(JvmStatic::class.java))
|
||||
PsiTestUtil.addLibrary(model, "kotlin-stdlib", jar.parent, jar.name)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test no highlighting parameterized test case`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import org.junit.runners.Parameterized.Parameters
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class ParameterizedTest(private val x: Int, private val y: Int) {
|
||||
@Test
|
||||
public fun testMe() { }
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters
|
||||
public fun parameters(): Array<Array<Any>> = arrayOf(arrayOf(1, 2), arrayOf(3, 4))
|
||||
}
|
||||
}
|
||||
""".trimIndent(), "ParameterizedTest")
|
||||
}
|
||||
|
||||
fun `test no highlighting trivial constructor`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import junit.framework.TestCase
|
||||
|
||||
class TestCaseWithConstructorInspection2() : TestCase() {
|
||||
constructor(x: Int) : this() {
|
||||
if (false) {
|
||||
println(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent(), "TestCaseWithConstructorInspection2")
|
||||
}
|
||||
|
||||
fun `test highlighting simple non-trivial constructor`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import junit.framework.TestCase
|
||||
|
||||
class TestCaseWithConstructorInspection1() : TestCase() {
|
||||
<warning descr="Initialization logic in constructor 'constructor()' instead of 'setup()' life cycle method">constructor</warning>(x: Int) : this() {
|
||||
println(x)
|
||||
}
|
||||
}
|
||||
""".trimIndent(), "TestCaseWithConstructorInspection1")
|
||||
}
|
||||
|
||||
fun `test highlighting Junit 4`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
public class JUnit4TestCaseWithConstructor {
|
||||
<warning descr="Initialization logic in constructor 'constructor()' instead of 'setup()' life cycle method">constructor</warning>() {
|
||||
println()
|
||||
println()
|
||||
println()
|
||||
}
|
||||
|
||||
@org.junit.Test
|
||||
public fun testMe() {}
|
||||
}
|
||||
""".trimIndent(), "JUnit4TestCaseWithConstructor")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.test
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.test.TestCaseWithoutTestsInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinTestCaseWithoutTestsInspectionTest : TestCaseWithoutTestsInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test case without test methods`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class <warning descr="Test class 'TestCaseWithNoTestMethods' has no tests">TestCaseWithNoTestMethods</warning> : junit.framework.TestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
fun testOne(): Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
private fun testThree() { }
|
||||
|
||||
fun testFour(i: Int) { i + 1 }
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test case with JUnit 3 inner class without test methods`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class <warning descr="Test class 'TestCaseWithInner' has no tests">TestCaseWithInner</warning> : junit.framework.TestCase() {
|
||||
class Inner : junit.framework.TestCase() {
|
||||
fun test1() {}
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test case with JUnit 5 nested class without test methods`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
class <warning descr="Test class 'TestCaseWithInner' has no tests">TestCaseWithInner</warning> {
|
||||
@org.junit.jupiter.api.Nested
|
||||
inner class <warning descr="Test class 'Inner' has no tests">Inner</warning> {
|
||||
private fun test1() { }
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test case without test methods but class is ignored`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
@org.junit.Ignore
|
||||
class IgnoredTest : junit.framework.TestCase() { }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test case with test in parent class`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
open class SomeParentClass(val name: String) : junit.framework.TestCase() {
|
||||
fun testInParent() { }
|
||||
}
|
||||
|
||||
class SomeTestClass : SomeParentClass("") { }
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.test
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.test.TestFailedLineInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinTestFailedLineInspectionTest : TestFailedLineInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test non qualified call`() {
|
||||
doTest(
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
text = """
|
||||
class MainTest : junit.framework.TestCase() {
|
||||
fun testFoo() {
|
||||
<warning descr="junit.framework.AssertionFailedError:">assertEquals</warning>()
|
||||
assertEquals()
|
||||
}
|
||||
|
||||
fun assertEquals() {}
|
||||
}
|
||||
""".trimIndent(),
|
||||
url = "java:test://MainTest/testFoo",
|
||||
errorMessage = "junit.framework.AssertionFailedError:",
|
||||
stackTrace = """
|
||||
|${'\t'}at junit.framework.Assert.fail(Assert.java:47)
|
||||
|${'\t'}at MainTest.assertEquals(Assert.java:207)
|
||||
|${'\t'}at MainTest.testFoo(MainTest.kt:3)
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test qualified call`() {
|
||||
doTest(
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
text = """
|
||||
class QualifiedTest : junit.framework.TestCase() {
|
||||
fun testFoo() {
|
||||
Assertions.<warning descr="junit.framework.AssertionFailedError:">assertEquals</warning>()
|
||||
}
|
||||
|
||||
object Assertions {
|
||||
fun assertEquals() {}
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
url = "java:test://QualifiedTest/testFoo",
|
||||
errorMessage = "junit.framework.AssertionFailedError:",
|
||||
stackTrace = """
|
||||
|${'\t'}at junit.framework.Assert.fail(Assert.java:47)
|
||||
|${'\t'}at QualifiedTest.assertEquals(Assert.java:207)
|
||||
|${'\t'}at QualifiedTest.testFoo(QualifiedTest.kt:3)
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test local method call`() {
|
||||
doTest(
|
||||
lang = JvmLanguage.KOTLIN,
|
||||
text = """
|
||||
class LocalFunctionTest {
|
||||
@org.junit.jupiter.api.Test
|
||||
fun testFoo() {
|
||||
fun doTest() {
|
||||
org.junit.jupiter.api.Assertions.assertEquals("expected", "actual")
|
||||
}
|
||||
<warning descr="org.opentest4j.AssertionFailedError:">doTest</warning>()
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
url = "java:test://LocalFunctionTest/testFoo",
|
||||
errorMessage = "org.opentest4j.AssertionFailedError:",
|
||||
stackTrace = """
|
||||
|${'\t'}at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
|
||||
|${'\t'}at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)
|
||||
|${'\t'}at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
|
||||
|${'\t'}at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
|
||||
|${'\t'}at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1141)
|
||||
|${'\t'}at LocalFunctionTest.testFoo${'$'}doTest(LocalFunctionTest.kt:5)
|
||||
|${'\t'}at LocalFunctionTest.testFoo(LocalFunctionTest.kt:7)
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.test
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.test.TestMethodWithoutAssertionInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.project.IntelliJProjectConfiguration
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
import java.io.File
|
||||
|
||||
abstract class KotlinTestMethodWithoutAssertionInspectionTest : TestMethodWithoutAssertionInspectionTestBase(), KotlinPluginModeProvider {
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = object : TestFrameworkDescriptor(LanguageLevel.HIGHEST) {
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
super.configureModule(module, model, contentEntry)
|
||||
val stdLibJar = File(PathUtil.getJarPathForClass(JvmStatic::class.java))
|
||||
PsiTestUtil.addLibrary(model, "kotlin-stdlib", stdLibJar.parent, stdLibJar.name)
|
||||
val ktTestJar = File(IntelliJProjectConfiguration.getProjectLibraryClassesRootPaths("kotlin-test").first())
|
||||
PsiTestUtil.addLibrary(model, "kotlin-test", ktTestJar.parent, ktTestJar.name)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test highlighting for empty method body`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Test
|
||||
import org.junit.Assert
|
||||
|
||||
class TestMethodWithoutAssertion : TestCase() {
|
||||
public fun <warning descr="Test method 'test()' contains no assertions">test</warning>() { }
|
||||
|
||||
@Test
|
||||
public fun <warning descr="Test method 'fourOhTest()' contains no assertions">fourOhTest</warning>() { }
|
||||
|
||||
@Test(expected = Exception::class)
|
||||
public fun fourOhTestWithExpected() { }
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test no highlighting when assertion is present`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Test
|
||||
import org.junit.Assert
|
||||
import mockit.*
|
||||
|
||||
class TestMethodWithoutAssertion : TestCase() {
|
||||
@Test
|
||||
public fun fourOhTest2() { Assert.assertTrue(true) }
|
||||
|
||||
public fun test2() { assertTrue(true) }
|
||||
|
||||
public fun test3() { fail() }
|
||||
|
||||
@Test
|
||||
public fun delegateOnly() { check() }
|
||||
|
||||
@Test
|
||||
public fun delegateAdditionally() {
|
||||
val i = 9
|
||||
println(i)
|
||||
check()
|
||||
}
|
||||
|
||||
private fun check() { Assert.assertTrue(true) }
|
||||
|
||||
@Test
|
||||
public fun testExecuteReverseAcknowledgement(@Mocked messageDAO: Any) {
|
||||
println(messageDAO)
|
||||
|
||||
object : Verifications() { }
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(AssertionError::class)
|
||||
public fun testMethodWhichThrowsExceptionOnFailure() {
|
||||
if (true) throw AssertionError()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test no highlighting kotlin stdlib assertion`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.junit.Test
|
||||
import kotlin.test.*
|
||||
|
||||
class TestMethodWithAssertion {
|
||||
@Test
|
||||
public fun ktPrecondition1() { assert(true) }
|
||||
|
||||
@Test
|
||||
public fun ktTestAssertion1() { assertTrue(true) }
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test no highlighting kotlin JUnit 5 assertion`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertDoesNotThrow
|
||||
|
||||
class TestMethodWithAssertion {
|
||||
@Test
|
||||
fun testFoo() {
|
||||
assertDoesNotThrow<IllegalStateException> { throw IllegalStateException() }
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test no highlighting mockk assertion`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.junit.jupiter.api.Test
|
||||
import io.mockk.verify
|
||||
|
||||
class TestMethodWithAssertion {
|
||||
@Test
|
||||
fun testFoo() {
|
||||
verify { }
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.test
|
||||
|
||||
import com.intellij.jvm.analysis.internal.testFramework.test.TestOnlyInspectionTestBase
|
||||
import com.intellij.jvm.analysis.testFramework.JvmLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
|
||||
abstract class KotlinTestOnlyInspectionTest : TestOnlyInspectionTestBase(), KotlinPluginModeProvider {
|
||||
fun `test @TestOnly on use-site targets`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
package test
|
||||
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
|
||||
// IDEA-269740 need better support for UAST properties
|
||||
@get:[TestOnly VisibleForTesting]
|
||||
val x = 0
|
||||
|
||||
@get:[TestOnly]
|
||||
val y = 0
|
||||
|
||||
@get:TestOnly
|
||||
val z = 0
|
||||
|
||||
fun doSomething(q: Int) = q
|
||||
|
||||
fun main() {
|
||||
doSomething(<warning descr="Test-only method is called in production code">y</warning>)
|
||||
doSomething(<warning descr="Test-only method is called in production code">z</warning>)
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test @TestOnly in production code`() {
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
package test
|
||||
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
|
||||
class TestOnlyTest @TestOnly constructor() {
|
||||
val nonTestField = 0
|
||||
|
||||
var aField = 0
|
||||
@TestOnly get() = field
|
||||
|
||||
@TestOnly
|
||||
fun aMethod(x: Int): Int = x
|
||||
|
||||
@TestOnly
|
||||
@<warning descr="@VisibleForTesting makes little sense on @TestOnly code">VisibleForTesting</warning>
|
||||
fun aStringMethod(): String = "Foo"
|
||||
}
|
||||
|
||||
/**
|
||||
* [TestOnlyTest.aMethod]
|
||||
* [testOnly]
|
||||
*/
|
||||
fun main() {
|
||||
val foo1 = <warning descr="Test-only class is referenced in production code">TestOnlyTest</warning>()
|
||||
val foo2 = test.<warning descr="Test-only class is referenced in production code">TestOnlyTest</warning>()
|
||||
val foo3 = <warning descr="Test-only class is referenced in production code">TestOnlyTest</warning>().nonTestField
|
||||
val bar = foo1.<warning descr="Test-only method is called in production code">aField</warning>
|
||||
foo1.<warning descr="Test-only method is called in production code">aMethod</warning>(bar)
|
||||
TestOnlyTest::<warning descr="Test-only method is called in production code">aMethod</warning>.invoke(foo2, foo3)
|
||||
test.TestOnlyTest::<warning descr="Test-only method is called in production code">aMethod</warning>.invoke(foo2, foo3)
|
||||
<warning descr="Test-only method is called in production code">testOnly</warning>()
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun testOnly() {
|
||||
val foo1 = TestOnlyTest()
|
||||
val foo2 = test.TestOnlyTest()
|
||||
val foo3 = TestOnlyTest().nonTestField
|
||||
val bar = foo1.aField
|
||||
foo1.aMethod(bar)
|
||||
TestOnlyTest::aMethod.invoke(foo2, foo3)
|
||||
test.TestOnlyTest::aMethod.invoke(foo2, foo3)
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test @VisibleForTesting in production code`() {
|
||||
myFixture.addFileToProject("VisibleForTestingTestApi.kt", """
|
||||
package testapi
|
||||
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
|
||||
object VisibleForTestingTestApi {
|
||||
var foo = 0 @VisibleForTesting get() = field
|
||||
|
||||
@VisibleForTesting
|
||||
fun bar() { }
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
myFixture.testHighlighting(JvmLanguage.KOTLIN, """
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
import testapi.VisibleForTestingTestApi
|
||||
|
||||
object VisibleForTestingTest {
|
||||
val foobar = 0
|
||||
@VisibleForTesting get() = field
|
||||
|
||||
fun main() {
|
||||
foobar
|
||||
VisibleForTestingTestApi.<warning descr="Test-only method is called in production code">foo</warning>
|
||||
VisibleForTestingTestApi.<warning descr="Test-only method is called in production code">bar</warning>()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user