[Java. Logging] Add tests for anonymous and implicitly declared classes + review refactor

IDEA-331693

GitOrigin-RevId: 2ca3503bfbf7d37602ad698f071292a8773c6e29
This commit is contained in:
Georgii Ustinov
2024-02-07 13:30:04 +00:00
committed by intellij-monorepo-bot
parent 7019bbd5df
commit baf6a46750
11 changed files with 94 additions and 22 deletions
@@ -21,7 +21,8 @@ import com.intellij.psi.util.parentsOfType
import com.intellij.refactoring.IntroduceTargetChooser
import com.intellij.refactoring.introduce.PsiIntroduceTarget
import com.intellij.refactoring.suggested.endOffset
import com.intellij.ui.logging.JavaSettingsStorage
import com.intellij.refactoring.util.CommonRefactoringUtil
import com.intellij.ui.logging.JvmLoggingSettingsStorage
import org.jetbrains.java.generate.GenerationUtil
class GenerateLoggerHandler : CodeInsightActionHandler {
@@ -35,7 +36,16 @@ class GenerateLoggerHandler : CodeInsightActionHandler {
val chosenLogger = getSelectedLogger(project, availableLoggers) ?: return
when (places.size) {
0 -> return
0 -> {
CommonRefactoringUtil.showErrorHint(
project,
editor,
JavaBundle.message("generate.logger.no.place.found.dialog.message"),
JavaBundle.message("generate.logger.no.place.found.dialog.title"),
null
)
return
}
1 -> execute(places.first(), chosenLogger, project, editor)
else -> {
val targetInfo = places.map { PsiTargetClassInfo(it) }
@@ -85,7 +95,7 @@ class GenerateLoggerHandler : CodeInsightActionHandler {
0 -> null
1 -> availableLoggers.first()
else -> {
val preferredLogger = JvmLogger.getLoggerByName(project.service<JavaSettingsStorage>().state.loggerName)
val preferredLogger = JvmLogger.getLoggerByName(project.service<JvmLoggingSettingsStorage>().state.loggerName)
val chooseLoggerDialog = ChooseLoggerDialogWrapper(
project,
@@ -110,7 +120,7 @@ class GenerateLoggerHandler : CodeInsightActionHandler {
private fun saveLoggerAfterFirstTime(project: Project, logger: JvmLogger?) {
if (logger == null) return
val settings = project.service<JavaSettingsStorage>().state
val settings = project.service<JvmLoggingSettingsStorage>().state
if (settings.loggerName == UnspecifiedLogger.UNSPECIFIED_LOGGER_NAME) {
settings.loggerName = logger.toString()
}
@@ -123,7 +133,7 @@ class GenerateLoggerHandler : CodeInsightActionHandler {
fun getPossiblePlacesForLogger(element: PsiElement, loggerList: List<JvmLogger>): List<PsiClass> = element.parentsOfType(
PsiClass::class.java, true)
.filter { clazz -> clazz !is PsiAnonymousClass && isPossibleToPlaceLogger(clazz, loggerList) }
.filter { clazz -> clazz !is PsiAnonymousClass && clazz !is PsiImplicitClass && isPossibleToPlaceLogger(clazz, loggerList) }
.toList()
.reversed()
@@ -134,7 +144,7 @@ class GenerateLoggerHandler : CodeInsightActionHandler {
}
private class PsiTargetClassInfo(clazz: PsiClass) : PsiIntroduceTarget<PsiClass>(clazz) {
private val className : String = clazz.name ?: throw IllegalStateException("Unable to fetch class name")
private val className: String = clazz.name ?: throw IllegalStateException("Unable to fetch class name")
override fun render(): String = "class $className"
@@ -8,7 +8,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.ComboBox
import com.intellij.openapi.ui.DialogWrapper
import com.intellij.ui.logging.JavaLoggerModel
import com.intellij.ui.logging.JavaSettingsStorage
import com.intellij.ui.logging.JvmLoggingSettingsStorage
import com.intellij.ui.logging.JvmLoggingConfigurable
import com.intellij.ui.dsl.builder.Cell
import com.intellij.ui.dsl.builder.panel
@@ -25,7 +25,7 @@ class ChooseLoggerDialogWrapper(
private set
private lateinit var comboBox: Cell<ComboBox<String>>
private val settings = project.service<JavaSettingsStorage>().state
private val settings = project.service<JvmLoggingSettingsStorage>().state
init {
title = JavaBundle.message("dialog.title.choose.logger")
@@ -7,11 +7,13 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import org.jetbrains.annotations.ApiStatus
/**
* Extension point representing a JVM logger. Extensions of this EP are used to store information about concrete logger and provide
* the way to generate a logger at the class.
* the way to generate a logger at the class. Please, don't use it now, this API will be rewritten in the future.
*/
@ApiStatus.Internal
interface JvmLogger {
/**
* This field represents fully qualified name of the logger's type
@@ -20,7 +22,7 @@ interface JvmLogger {
/**
* This field is used to determine the order of loggers in the settings
* @see com.intellij.settings.JvmLoggingConfigurable
* @see com.intellij.ui.logging.JvmLoggingConfigurable
*/
val priority: Int
@@ -29,7 +31,7 @@ interface JvmLogger {
* For example, it happens after creation of the new project.
*
* @return true if the logger should only be used during startup, false otherwise
* @see com.intellij.logging.UnspecifiedLogger
* @see com.intellij.lang.logging.UnspecifiedLogger
*/
fun isOnlyOnStartup() = false
@@ -42,7 +44,7 @@ interface JvmLogger {
fun insertLoggerAtClass(project: Project, clazz: PsiClass, logger: PsiElement): PsiElement?
/**
* Determines if the logger is available for the given project.
* Determines if the logger is available for the given project. Should only be invoked inside ReadAction.
*
* @param project the project context
* @return true if the logger is available, false otherwise
@@ -50,7 +52,7 @@ interface JvmLogger {
fun isAvailable(project: Project?) : Boolean
/**
* Determines if the logger is available for the given module.
* Determines if the logger is available for the given module. Should only be invoked inside ReadAction.
*
* @param module the module context
* @return true if the logger is available, false otherwise
@@ -20,8 +20,7 @@ import javax.swing.JComponent
class JvmLoggingConfigurable(private val project: Project) : SearchableConfigurable, NoScroll {
private lateinit var warningRow: Row
private lateinit var panel: DialogPanel
private val boundedExecutor = AppExecutorUtil.getAppExecutorService()
private val settings = project.service<JavaSettingsStorage>().state
private val settings = project.service<JvmLoggingSettingsStorage>().state
override fun getDisplayName(): String = JavaBundle.message("jvm.logging.configurable.display.name")
@@ -53,7 +52,7 @@ class JvmLoggingConfigurable(private val project: Project) : SearchableConfigura
JvmLogger.getLoggerByName(loggerDisplayName)?.isAvailable(project) == false
}.finishOnUiThread(ModalityState.any()) { isVisible ->
warningRow.visible(isVisible)
}.submit(boundedExecutor)
}.submit(AppExecutorUtil.getAppExecutorService())
}
override fun isModified(): Boolean = panel.isModified()
@@ -5,9 +5,9 @@ import com.intellij.lang.logging.UnspecifiedLogger
import com.intellij.openapi.components.*
@Service(Service.Level.PROJECT)
@State(name = "JavaSettingsStorage",
@State(name = "JvmLoggingSettingsStorage",
storages = [Storage(StoragePathMacros.WORKSPACE_FILE)])
class JavaSettingsStorage : SimplePersistentStateComponent<JavaSettingsStorage.State>(State()) {
class JvmLoggingSettingsStorage : SimplePersistentStateComponent<JvmLoggingSettingsStorage.State>(State()) {
class State : BaseState() {
var loggerName: String? by string(UnspecifiedLogger.UNSPECIFIED_LOGGER_NAME)
}
@@ -0,0 +1,13 @@
import org.apache.log4j.Logger;
class A {
private static final Logger log<caret> = Logger.getLogger(A.class);
public void foo() {
new Runnable() {
@Override
public void run() {
}
}
}
}
@@ -0,0 +1,2 @@
void main() {<caret>
}
@@ -0,0 +1,9 @@
class A {
public void foo() {
new Runnable() {
@Override
public void run() {<caret>
}
}
}
}
@@ -0,0 +1,2 @@
void main() {<caret>
}
@@ -14,7 +14,7 @@ import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
import com.intellij.ui.UiInterceptors
import com.intellij.ui.UiInterceptors.UiInterceptor
import com.intellij.ui.components.JBList
import com.intellij.ui.logging.JavaSettingsStorage
import com.intellij.ui.logging.JvmLoggingSettingsStorage
import com.intellij.util.ui.UIUtil
import junit.framework.TestCase
import javax.swing.ListModel
@@ -82,6 +82,39 @@ class GenerateLoggerTest : LightJavaCodeInsightFixtureTestCase() {
doTest()
}
fun testAnonymousClass() {
myFixture.addClass("""
package org.apache.log4j;
interface Logger {
static <T> Logger getLogger(Class<T> clazz) {}
}
""".trimIndent())
doTest()
}
fun testImplicitlyDeclaredClass() {
myFixture.addClass("""
package org.apache.log4j;
interface Logger {
static <T> Logger getLogger(Class<T> clazz) {}
}
""".trimIndent())
myFixture.configureByText("implicitlyDeclaredClass.java",
"""
void main() {<caret>
}
""".trimIndent())
val loggers = GenerateLoggerHandler.findSuitableLoggers(module)
TestCase.assertTrue(loggers.isNotEmpty())
val element = file.findElementAt(editor.caretModel.offset)!!
val places = GenerateLoggerHandler.getPossiblePlacesForLogger(element, loggers)
TestCase.assertTrue(places.isEmpty())
}
fun testNestedClassesOuterClass() {
myFixture.addClass("""
package org.slf4j;
@@ -156,12 +189,12 @@ class GenerateLoggerTest : LightJavaCodeInsightFixtureTestCase() {
static <T> Logger getLogger(Class<T> clazz) {}
}
""".trimIndent())
assertEquals(project.service<JavaSettingsStorage>().state.loggerName, UnspecifiedLogger.UNSPECIFIED_LOGGER_NAME)
assertEquals(project.service<JvmLoggingSettingsStorage>().state.loggerName, UnspecifiedLogger.UNSPECIFIED_LOGGER_NAME)
doTest()
assertEquals(project.service<JavaSettingsStorage>().state.loggerName, "Log4j")
assertEquals(project.service<JvmLoggingSettingsStorage>().state.loggerName, "Log4j")
}
override fun getProjectDescriptor(): LightProjectDescriptor = JAVA_LATEST_WITH_LATEST_JDK
override fun getProjectDescriptor(): LightProjectDescriptor = JAVA_21
private fun doTestWithMultiplePlaces(expectedClassNameList: List<String>, selectedClass: String) {
val name = getTestName(false)
@@ -300,6 +300,8 @@ generate.getter.fields.chooser.title=Select Fields to Generate Getters
generate.getter.setter.title=Select Fields to Generate Getters and Setters
generate.getter.template=&Getter template:
generate.hashcode.template.title=HashCode Template:
generate.logger.no.place.found.dialog.title = No Places Found
generate.logger.no.place.found.dialog.message = Could not find places to insert logger
generate.logger.specify.place.popup.title=Choose Place
generate.record.constructor.title=Generate Records Constructor
generate.setter.fields.chooser.title=Select Fields to Generate Setters