diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml
index 5715e17b8c8..86d79ebcc36 100644
--- a/idea/resources/META-INF/plugin-common.xml
+++ b/idea/resources/META-INF/plugin-common.xml
@@ -3316,6 +3316,14 @@
language="kotlin"
key="inspection.redundant.elvis.return.null.display.name" bundle="messages.KotlinBundle"/>
+
+
diff --git a/idea/resources/inspectionDescriptions/KotlinLoggerInitializedWithForeignClass.html b/idea/resources/inspectionDescriptions/KotlinLoggerInitializedWithForeignClass.html
new file mode 100644
index 00000000000..81806f14b95
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/KotlinLoggerInitializedWithForeignClass.html
@@ -0,0 +1,7 @@
+
+
+This inspection reports any Loggers which are initialized with a class literal from a different class than the Logger is contained in.
+
+Use the table below to specify the logger factory classes and logger factory methods recognized by this inspection.
+
+
\ No newline at end of file
diff --git a/idea/resources/messages/KotlinBundle.properties b/idea/resources/messages/KotlinBundle.properties
index 0beb48597a8..11d6bf8474c 100644
--- a/idea/resources/messages/KotlinBundle.properties
+++ b/idea/resources/messages/KotlinBundle.properties
@@ -2206,4 +2206,9 @@ kotlin.script.definitions.model.name.name=Name
codestyle.name.kotlin=Kotlin
add.missing.class.keyword=Add missing 'class' keyword
fix.move.typealias.to.top.level=Move typealias to top level
-fix.change.jvm.name=Change JVM name
\ No newline at end of file
+fix.change.jvm.name=Change JVM name
+inspection.logger.initialized.with.foreign.class.display.name=Logger initialized with foreign class
+logger.initialized.with.foreign.class=Logger initialized with foreign class ''{0}''
+logger.factory.method.name=Logger factory method name
+logger.factory.class.name=Logger factory class name
+choose.logger.factory.class=Choose logger factory class
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/logging/KotlinLoggerInitializedWithForeignClassInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/logging/KotlinLoggerInitializedWithForeignClassInspection.kt
new file mode 100644
index 00000000000..b3483ceefd8
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/logging/KotlinLoggerInitializedWithForeignClassInspection.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.inspections.logging
+
+import com.intellij.codeInspection.LocalQuickFix
+import com.intellij.codeInspection.ProblemDescriptor
+import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.codeInspection.ui.ListTable
+import com.intellij.codeInspection.ui.ListWrappingTableModel
+import com.intellij.openapi.project.Project
+import com.intellij.util.xmlb.Accessor
+import com.intellij.util.xmlb.SerializationFilterBase
+import com.intellij.util.xmlb.XmlSerializer
+import com.siyeh.ig.BaseInspection
+import com.siyeh.ig.ui.UiUtils
+import org.jdom.Element
+import org.jetbrains.kotlin.idea.KotlinBundle
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
+import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
+import org.jetbrains.kotlin.idea.intentions.callExpression
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.containingClass
+import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
+import org.jetbrains.kotlin.utils.addToStdlib.safeAs
+import javax.swing.JComponent
+
+class KotlinLoggerInitializedWithForeignClassInspection : AbstractKotlinInspection() {
+ companion object {
+ private val DEFAULT_LOGGER_FACTORIES = listOf(
+ "java.util.logging.Logger" to "getLogger",
+ "org.slf4j.LoggerFactory" to "getLogger",
+ "org.apache.commons.logging.LogFactory" to "getLog",
+ "org.apache.log4j.Logger" to "getLogger",
+ "org.apache.logging.log4j.LogManager" to "getLogger",
+ )
+ private val DEFAULT_LOGGER_FACTORY_CLASS_NAMES = DEFAULT_LOGGER_FACTORIES.map { it.first }
+ private val DEFAULT_LOGGER_FACTORY_METHOD_NAMES = DEFAULT_LOGGER_FACTORIES.map { it.second }
+ private val DEFAULT_LOGGER_FACTORY_CLASS_NAME = BaseInspection.formatString(DEFAULT_LOGGER_FACTORY_CLASS_NAMES)
+ private val DEFAULT_LOGGER_FACTORY_METHOD_NAME = BaseInspection.formatString(DEFAULT_LOGGER_FACTORY_METHOD_NAMES)
+ }
+
+ @Suppress("MemberVisibilityCanBePrivate")
+ var loggerFactoryClassName: String = DEFAULT_LOGGER_FACTORY_CLASS_NAME
+
+ @Suppress("MemberVisibilityCanBePrivate")
+ var loggerFactoryMethodName: String = DEFAULT_LOGGER_FACTORY_METHOD_NAME
+
+ private val loggerFactoryClassNames = DEFAULT_LOGGER_FACTORY_CLASS_NAMES.toMutableList()
+ private val loggerFactoryMethodNames = DEFAULT_LOGGER_FACTORY_METHOD_NAMES.toMutableList()
+ private val loggerFactoryFqNames
+ get() = loggerFactoryClassNames.zip(loggerFactoryMethodNames).groupBy(
+ { (_, methodName) -> methodName },
+ { (className, methodName) -> FqName("${className}.${methodName}") }
+ )
+
+ override fun createOptionsPanel(): JComponent? {
+ val table = ListTable(
+ ListWrappingTableModel(
+ listOf(loggerFactoryClassNames, loggerFactoryMethodNames),
+ KotlinBundle.message("logger.factory.class.name"),
+ KotlinBundle.message("logger.factory.method.name")
+ )
+ )
+ return UiUtils.createAddRemoveTreeClassChooserPanel(table, KotlinBundle.message("choose.logger.factory.class"))
+ }
+
+ override fun readSettings(element: Element) {
+ super.readSettings(element)
+ BaseInspection.parseString(loggerFactoryClassName, loggerFactoryClassNames)
+ BaseInspection.parseString(loggerFactoryMethodName, loggerFactoryMethodNames)
+ if (loggerFactoryClassNames.isEmpty() || loggerFactoryClassNames.size != loggerFactoryMethodNames.size) {
+ BaseInspection.parseString(DEFAULT_LOGGER_FACTORY_CLASS_NAME, loggerFactoryClassNames)
+ BaseInspection.parseString(DEFAULT_LOGGER_FACTORY_METHOD_NAME, loggerFactoryMethodNames)
+ }
+ }
+
+ override fun writeSettings(element: Element) {
+ loggerFactoryClassName = BaseInspection.formatString(loggerFactoryClassNames)
+ loggerFactoryMethodName = BaseInspection.formatString(loggerFactoryMethodNames)
+ XmlSerializer.serializeInto(this, element, object : SerializationFilterBase() {
+ override fun accepts(accessor: Accessor, bean: Any, beanValue: Any?): Boolean {
+ if (accessor.name == "loggerFactoryClassName" && beanValue == DEFAULT_LOGGER_FACTORY_CLASS_NAME) return false
+ if (accessor.name == "loggerFactoryMethodName" && beanValue == DEFAULT_LOGGER_FACTORY_METHOD_NAME) return false
+ return true
+ }
+ })
+ }
+
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = callExpressionVisitor(fun(call) {
+ val containingClassName = call.containingClass()?.name ?: return
+
+ val callee = call.calleeExpression ?: return
+ val loggerMethodFqNames = loggerFactoryFqNames[callee.text] ?: return
+
+ val argument = call.valueArguments.singleOrNull()?.getArgumentExpression() as? KtDotQualifiedExpression ?: return
+ val argumentSelector = argument.selectorExpression ?: return
+ val classLiteral = when (val argumentReceiver = argument.receiverExpression) {
+ // Foo::class.java, Foo::class.qualifiedName, Foo::class.simpleName
+ is KtClassLiteralExpression -> {
+ val selectorText = argumentSelector.safeAs()?.text
+ if (selectorText !in listOf("java", "qualifiedName", "simpleName")) return
+ argumentReceiver
+ }
+ // Foo::class.java.name, Foo::class.java.simpleName, Foo::class.java.canonicalName
+ is KtDotQualifiedExpression -> {
+ val classLiteral = argumentReceiver.receiverExpression as? KtClassLiteralExpression ?: return
+ if (argumentReceiver.selectorExpression.safeAs()?.text != "java") return
+ val selectorText = argumentSelector.safeAs()?.text
+ ?: argumentSelector.safeAs()?.calleeExpression?.text
+ if (selectorText !in listOf("name", "simpleName", "canonicalName", "getName", "getSimpleName", "getCanonicalName")) return
+ classLiteral
+ }
+ else -> return
+ }
+ val classLiteralName = classLiteral.receiverExpression?.text ?: return
+ if (containingClassName == classLiteralName) return
+
+ if (call.resolveToCall()?.resultingDescriptor?.fqNameOrNull() !in loggerMethodFqNames) return
+
+ holder.registerProblem(
+ classLiteral,
+ KotlinBundle.message("logger.initialized.with.foreign.class", "$classLiteralName::class"),
+ ReplaceForeignFix(containingClassName)
+ )
+ })
+
+ private class ReplaceForeignFix(private val containingClassName: String) : LocalQuickFix {
+ override fun getName() = KotlinBundle.message("replace.with.0", "$containingClassName::class")
+
+ override fun getFamilyName() = name
+
+ override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
+ val argument = descriptor.psiElement.getStrictParentOfType()?.getArgumentExpression()
+ as? KtDotQualifiedExpression ?: return
+ val receiver = argument.receiverExpression
+ val selector = argument.selectorExpression ?: return
+ val psiFactory = KtPsiFactory(argument)
+ val newArgument = when (receiver) {
+ is KtClassLiteralExpression -> {
+ psiFactory.createExpressionByPattern("${containingClassName}::class.$0", selector)
+ }
+ is KtDotQualifiedExpression -> {
+ psiFactory.createExpressionByPattern("${containingClassName}::class.java.$0", selector)
+ }
+ else -> return
+ }
+ argument.replace(newArgument)
+ }
+ }
+}
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/.inspection b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/.inspection
new file mode 100644
index 00000000000..7389a382020
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.logging.KotlinLoggerInitializedWithForeignClassInspection
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/canonicalName.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/canonicalName.kt
new file mode 100644
index 00000000000..dce99776846
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/canonicalName.kt
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.java.canonicalName)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/canonicalName.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/canonicalName.kt.after
new file mode 100644
index 00000000000..8d43ac171fb
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/canonicalName.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.java.canonicalName)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getCanonicalName.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getCanonicalName.kt
new file mode 100644
index 00000000000..5c4025d77b3
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getCanonicalName.kt
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.java.getCanonicalName())
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getCanonicalName.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getCanonicalName.kt.after
new file mode 100644
index 00000000000..e0e690fec0e
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getCanonicalName.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.java.getCanonicalName())
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getName.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getName.kt
new file mode 100644
index 00000000000..a387163f7c0
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getName.kt
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.java.getName())
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getName.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getName.kt.after
new file mode 100644
index 00000000000..54428f78963
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getName.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.java.getName())
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getSimpleName.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getSimpleName.kt
new file mode 100644
index 00000000000..47d03dbeadf
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getSimpleName.kt
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.java.getSimpleName())
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getSimpleName.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getSimpleName.kt.after
new file mode 100644
index 00000000000..0342a840aaa
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getSimpleName.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.java.getSimpleName())
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassQualiiedName.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassQualiiedName.kt
new file mode 100644
index 00000000000..94174db7ece
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassQualiiedName.kt
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.qualifiedName)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassQualiiedName.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassQualiiedName.kt.after
new file mode 100644
index 00000000000..2709c95edb5
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassQualiiedName.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.qualifiedName)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassSimpleName.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassSimpleName.kt
new file mode 100644
index 00000000000..d03958e9078
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassSimpleName.kt
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.simpleName)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassSimpleName.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassSimpleName.kt.after
new file mode 100644
index 00000000000..786cb32733b
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassSimpleName.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.simpleName)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/name.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/name.kt
new file mode 100644
index 00000000000..731f1e4afd7
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/name.kt
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.java.name)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/name.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/name.kt.after
new file mode 100644
index 00000000000..a0ac4d28196
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/name.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.java.name)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/nonForeignClass.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/nonForeignClass.kt
new file mode 100644
index 00000000000..2abd3fdd66d
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/nonForeignClass.kt
@@ -0,0 +1,14 @@
+// WITH_RUNTIME
+// PROBLEM: none
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.java)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simple.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simple.kt
new file mode 100644
index 00000000000..8c14b89ea28
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simple.kt
@@ -0,0 +1,15 @@
+// WITH_RUNTIME
+// PROBLEM: Logger initialized with foreign class 'Bar::class'
+// FIX: Replace with 'Foo::class'
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.java)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simple.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simple.kt.after
new file mode 100644
index 00000000000..2e772e7152c
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simple.kt.after
@@ -0,0 +1,15 @@
+// WITH_RUNTIME
+// PROBLEM: Logger initialized with foreign class 'Bar::class'
+// FIX: Replace with 'Foo::class'
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.java)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simpleName.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simpleName.kt
new file mode 100644
index 00000000000..15d948d5f41
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simpleName.kt
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Bar::class.java.simpleName)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simpleName.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simpleName.kt.after
new file mode 100644
index 00000000000..b297ab038b5
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simpleName.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+package org.apache.commons.logging
+
+class Foo {
+ private val logger = LogFactory.getLog(Foo::class.java.simpleName)
+}
+
+class Bar
+
+object LogFactory {
+ fun getLog(clazz: Class<*>) {}
+ fun getLog(name: String?) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j/simple.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j/simple.kt
new file mode 100644
index 00000000000..b9abf548416
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j/simple.kt
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+package org.apache.log4j
+
+class Foo {
+ private val logger = Logger.getLogger(Bar::class.java)
+}
+
+class Bar
+
+object Logger {
+ fun getLogger(clazz: Class<*>) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j/simple.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j/simple.kt.after
new file mode 100644
index 00000000000..53f264f5516
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j/simple.kt.after
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+package org.apache.log4j
+
+class Foo {
+ private val logger = Logger.getLogger(Foo::class.java)
+}
+
+class Bar
+
+object Logger {
+ fun getLogger(clazz: Class<*>) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2/simple.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2/simple.kt
new file mode 100644
index 00000000000..b36f4c5b81c
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2/simple.kt
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+package org.apache.logging.log4j
+
+class Foo {
+ private val logger = LogManager.getLogger(Bar::class.java)
+}
+
+class Bar
+
+object LogManager {
+ fun getLogger(clazz: Class<*>) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2/simple.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2/simple.kt.after
new file mode 100644
index 00000000000..aa243b6f0c6
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2/simple.kt.after
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+package org.apache.logging.log4j
+
+class Foo {
+ private val logger = LogManager.getLogger(Foo::class.java)
+}
+
+class Bar
+
+object LogManager {
+ fun getLogger(clazz: Class<*>) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j/simple.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j/simple.kt
new file mode 100644
index 00000000000..3ad07c3cfea
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j/simple.kt
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+package org.slf4j
+
+class Foo {
+ private val logger = LoggerFactory.getLogger(Bar::class.java)
+}
+
+class Bar
+
+object LoggerFactory {
+ fun getLogger(clazz: Class<*>) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j/simple.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j/simple.kt.after
new file mode 100644
index 00000000000..1f4f88714a0
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j/simple.kt.after
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+package org.slf4j
+
+class Foo {
+ private val logger = LoggerFactory.getLogger(Foo::class.java)
+}
+
+class Bar
+
+object LoggerFactory {
+ fun getLogger(clazz: Class<*>) {}
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple.kt
new file mode 100644
index 00000000000..d9896d32ca0
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple.kt
@@ -0,0 +1,10 @@
+// RUNTIME_WITH_FULL_JDK
+package util
+
+import java.util.logging.Logger
+
+class Foo {
+ private val logger = Logger.getLogger(Bar::class.qualifiedName)
+}
+
+class Bar
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple.kt.after
new file mode 100644
index 00000000000..ae26de5e81a
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple.kt.after
@@ -0,0 +1,10 @@
+// RUNTIME_WITH_FULL_JDK
+package util
+
+import java.util.logging.Logger
+
+class Foo {
+ private val logger = Logger.getLogger(Foo::class.qualifiedName)
+}
+
+class Bar
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple2.kt b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple2.kt
new file mode 100644
index 00000000000..c901c1c6d13
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple2.kt
@@ -0,0 +1,10 @@
+// RUNTIME_WITH_FULL_JDK
+package util
+
+import java.util.logging.Logger.getLogger
+
+class Foo {
+ private val logger = getLogger(Bar::class.qualifiedName)
+}
+
+class Bar
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple2.kt.after b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple2.kt.after
new file mode 100644
index 00000000000..f9a5d7d396d
--- /dev/null
+++ b/idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple2.kt.after
@@ -0,0 +1,10 @@
+// RUNTIME_WITH_FULL_JDK
+package util
+
+import java.util.logging.Logger.getLogger
+
+class Foo {
+ private val logger = getLogger(Foo::class.qualifiedName)
+}
+
+class Bar
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
index 2c28d84d923..bd627cb7f46 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
@@ -5797,6 +5797,172 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
+ @TestMetadata("idea/testData/inspectionsLocal/logging")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Logging extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInLogging() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/logging"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
+ }
+
+ @TestMetadata("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class LoggerInitializedWithForeignClass extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInLoggerInitializedWithForeignClass() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
+ }
+
+ @TestMetadata("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Commons extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInCommons() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
+ }
+
+ @TestMetadata("canonicalName.kt")
+ public void testCanonicalName() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/canonicalName.kt");
+ }
+
+ @TestMetadata("getCanonicalName.kt")
+ public void testGetCanonicalName() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getCanonicalName.kt");
+ }
+
+ @TestMetadata("getName.kt")
+ public void testGetName() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getName.kt");
+ }
+
+ @TestMetadata("getSimpleName.kt")
+ public void testGetSimpleName() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/getSimpleName.kt");
+ }
+
+ @TestMetadata("kclassQualiiedName.kt")
+ public void testKclassQualiiedName() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassQualiiedName.kt");
+ }
+
+ @TestMetadata("kclassSimpleName.kt")
+ public void testKclassSimpleName() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/kclassSimpleName.kt");
+ }
+
+ @TestMetadata("name.kt")
+ public void testName() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/name.kt");
+ }
+
+ @TestMetadata("nonForeignClass.kt")
+ public void testNonForeignClass() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/nonForeignClass.kt");
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simple.kt");
+ }
+
+ @TestMetadata("simpleName.kt")
+ public void testSimpleName() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/commons/simpleName.kt");
+ }
+ }
+
+ @TestMetadata("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Log4j extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInLog4j() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j/simple.kt");
+ }
+ }
+
+ @TestMetadata("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Log4j2 extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInLog4j2() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/log4j2/simple.kt");
+ }
+ }
+
+ @TestMetadata("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Slf4j extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInSlf4j() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/slf4j/simple.kt");
+ }
+ }
+
+ @TestMetadata("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Util extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInUtil() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple.kt");
+ }
+
+ @TestMetadata("simple2.kt")
+ public void testSimple2() throws Exception {
+ runTest("idea/testData/inspectionsLocal/logging/loggerInitializedWithForeignClass/util/simple2.kt");
+ }
+ }
+ }
+ }
+
@TestMetadata("idea/testData/inspectionsLocal/mainFunctionReturnUnit")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)