mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-22 06:21:25 +07:00
[Java. Logging] Properly handling with logging placeholders resolve with backslash character
IDEA-342484 GitOrigin-RevId: 70cbc9a537943dd3520282206ef8ddb20f01ad5f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
44598e3b3b
commit
c25c1ba670
@@ -2,6 +2,8 @@
|
||||
package com.intellij.analysis.logging.resolve
|
||||
|
||||
import com.intellij.codeInspection.logging.*
|
||||
import com.intellij.codeInspection.logging.PlaceholderCountIndexStrategy.KOTLIN_MULTILINE_RAW_STRING
|
||||
import com.intellij.codeInspection.logging.PlaceholderCountIndexStrategy.RAW_STRING
|
||||
import com.intellij.codeInspection.logging.PlaceholderLoggerType.*
|
||||
import com.intellij.model.Symbol
|
||||
import com.intellij.model.psi.PsiExternalReferenceHost
|
||||
@@ -10,11 +12,8 @@ import com.intellij.model.psi.PsiSymbolReferenceHints
|
||||
import com.intellij.model.psi.PsiSymbolReferenceProvider
|
||||
import com.intellij.model.search.SearchRequest
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.uast.UCallExpression
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.expressions.UInjectionHost
|
||||
import org.jetbrains.uast.getParentOfType
|
||||
import org.jetbrains.uast.toUElementOfType
|
||||
|
||||
class LoggingArgumentSymbolReferenceProvider : PsiSymbolReferenceProvider {
|
||||
override fun getReferences(element: PsiExternalReferenceHost, hints: PsiSymbolReferenceHints): Collection<PsiSymbolReference> {
|
||||
@@ -74,14 +73,19 @@ internal fun <T> getAlignedPlaceholderCount(placeholderList: List<T>, context: P
|
||||
|
||||
internal fun getPlaceholderRanges(context: PlaceholderContext): List<PlaceholderRanges>? {
|
||||
val logStringText = context.logStringArgument.sourcePsi?.text ?: return null
|
||||
val type = if (isKotlinMultilineString(context.logStringArgument, logStringText)) KOTLIN_MULTILINE_RAW_STRING else RAW_STRING
|
||||
val partHolders = listOf(
|
||||
LoggingStringPartEvaluator.PartHolder(
|
||||
logStringText,
|
||||
true
|
||||
)
|
||||
)
|
||||
val placeholderCountResult = solvePlaceholderCount(context.loggerType, context.placeholderParameters.size, partHolders)
|
||||
val placeholderCountResult = solvePlaceholderCount(context.loggerType, context.placeholderParameters.size, partHolders, type)
|
||||
if (placeholderCountResult.status != PlaceholdersStatus.EXACTLY) return null
|
||||
|
||||
return placeholderCountResult.placeholderRangesList
|
||||
}
|
||||
|
||||
private fun isKotlinMultilineString(logString: UExpression, text : String): Boolean {
|
||||
return logString is UPolyadicExpression && text.startsWith("\"\"\"") && text.endsWith("\"\"\"") && text.length >= 6
|
||||
}
|
||||
@@ -56,7 +56,7 @@ class LoggingPlaceholderCountMatchesArgumentCountInspection : AbstractBaseUastLo
|
||||
|
||||
var finalArgumentCount = context.placeholderParameters.size
|
||||
|
||||
val placeholderCountHolder = solvePlaceholderCount(context.loggerType, finalArgumentCount, context.partHolderList)
|
||||
val placeholderCountHolder = solvePlaceholderCount(context.loggerType, finalArgumentCount, context.partHolderList, PlaceholderCountIndexStrategy.UAST_STRING)
|
||||
|
||||
if (placeholderCountHolder.status == PlaceholdersStatus.EMPTY) {
|
||||
return true
|
||||
|
||||
@@ -124,6 +124,26 @@ internal enum class PlaceholdersStatus {
|
||||
EXACTLY, PARTIAL, ERROR_TO_PARSE_STRING, EMPTY
|
||||
}
|
||||
|
||||
internal enum class PlaceholderCountIndexStrategy {
|
||||
UAST_STRING {
|
||||
override fun shiftAfterEscapeChar(index: Int): Int {
|
||||
return index
|
||||
}
|
||||
},
|
||||
KOTLIN_MULTILINE_RAW_STRING {
|
||||
override fun shiftAfterEscapeChar(index: Int): Int {
|
||||
return index
|
||||
}
|
||||
},
|
||||
RAW_STRING {
|
||||
override fun shiftAfterEscapeChar(index: Int): Int {
|
||||
return index + 1
|
||||
}
|
||||
};
|
||||
|
||||
abstract fun shiftAfterEscapeChar(index: Int): Int
|
||||
}
|
||||
|
||||
|
||||
internal class LoggerContext(val log4jAsImplementationForSlf4j: Boolean)
|
||||
|
||||
@@ -300,6 +320,7 @@ internal fun findAdditionalArguments(node: UCallExpression,
|
||||
* @param loggerType The type of the logger used.
|
||||
* @param argumentCount The number of arguments that the logger is expected to handle.
|
||||
* @param holders The list of PartHolder objects representing logging string parts.
|
||||
* @param placeholderCountShiftIndexStrategy The strategy of shifting index for escape backslash during parsing SLF4J placeholders. It is different for regular string and psi text
|
||||
*
|
||||
* @return PlaceholderCountResult returns the result of either countFormattedPlaceholders or countBracesPlaceholders based on the type of the logger.
|
||||
*/
|
||||
@@ -307,12 +328,13 @@ internal fun solvePlaceholderCount(
|
||||
loggerType: PlaceholderLoggerType,
|
||||
argumentCount: Int,
|
||||
holders: List<LoggingStringPartEvaluator.PartHolder>,
|
||||
placeholderCountShiftIndexStrategy: PlaceholderCountIndexStrategy
|
||||
): PlaceholderCountResult {
|
||||
return if (loggerType == PlaceholderLoggerType.LOG4J_FORMATTED_STYLE) {
|
||||
countFormattedBasedPlaceholders(holders, argumentCount)
|
||||
}
|
||||
else {
|
||||
countBracesBasedPlaceholders(holders, loggerType)
|
||||
countBracesBasedPlaceholders(holders, loggerType, placeholderCountShiftIndexStrategy)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +456,9 @@ internal fun hasThrowableType(lastArgument: UExpression): Boolean {
|
||||
return InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_THROWABLE)
|
||||
}
|
||||
|
||||
private fun countBracesBasedPlaceholders(holders: List<LoggingStringPartEvaluator.PartHolder>, loggerType: PlaceholderLoggerType): PlaceholderCountResult {
|
||||
private fun countBracesBasedPlaceholders(holders: List<LoggingStringPartEvaluator.PartHolder>,
|
||||
loggerType: PlaceholderLoggerType,
|
||||
placeholderCountShiftIndexStrategy: PlaceholderCountIndexStrategy): PlaceholderCountResult {
|
||||
var count = 0
|
||||
var full = true
|
||||
val placeholderRangeList: MutableList<PlaceholderRanges> = mutableListOf()
|
||||
@@ -448,14 +472,17 @@ private fun countBracesBasedPlaceholders(holders: List<LoggingStringPartEvaluato
|
||||
val length = string.length
|
||||
var escaped = false
|
||||
var lastPlaceholderIndex = -1
|
||||
for (i in 0 until length) {
|
||||
var i = 0
|
||||
while (i < length) {
|
||||
val c = string[i]
|
||||
if (c == '\\' &&
|
||||
(loggerType == PlaceholderLoggerType.SLF4J_EQUAL_PLACEHOLDERS || loggerType == PlaceholderLoggerType.SLF4J)) {
|
||||
escaped = !escaped
|
||||
i = placeholderCountShiftIndexStrategy.shiftAfterEscapeChar(i)
|
||||
}
|
||||
else if (c == '{') {
|
||||
if (holderIndex != 0 && i == 0 && !holders[holderIndex - 1].isConstant) {
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
if (!escaped) {
|
||||
@@ -477,6 +504,7 @@ private fun countBracesBasedPlaceholders(holders: List<LoggingStringPartEvaluato
|
||||
escaped = false
|
||||
lastPlaceholderIndex = -1
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
return PlaceholderCountResult(placeholderRangeList, if (full) PlaceholdersStatus.EXACTLY else PlaceholdersStatus.PARTIAL)
|
||||
|
||||
@@ -464,4 +464,64 @@ class JavaLoggingArgumentSymbolReferenceProviderTest : LoggingArgumentSymbolRefe
|
||||
""".trimIndent())
|
||||
doTest(emptyMap())
|
||||
}
|
||||
|
||||
fun `test should resolve with escape character in simple string log4j2`() {
|
||||
myFixture.configureByText("Logging.java", """
|
||||
import org.apache.logging.log4j.*;
|
||||
class Logging {
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
void m(int i) {
|
||||
LOG.info("\\{<caret>}", i);
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
doTest(mapOf(TextRange(3, 5) to "i"))
|
||||
}
|
||||
|
||||
fun `test should resolve with escape character in multiline string log4j2`() {
|
||||
val multilineString = "\"\"\"\n" +
|
||||
"\\\\{<caret>}" +
|
||||
"\"\"\""
|
||||
myFixture.configureByText("Logging.java", """
|
||||
import org.apache.logging.log4j.*;
|
||||
class Logging {
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
void m(int i) {
|
||||
LOG.info($multilineString, i);
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
doTest(mapOf(TextRange(6, 8) to "i"))
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun `test should not resolve with escape character in simple string slf4j`() {
|
||||
myFixture.configureByText("Logging.java", """
|
||||
import org.slf4j.*;
|
||||
class Logging {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Logging.class);
|
||||
void m(int i) {
|
||||
LOG.info("\\{<caret>}", i);
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
doTest(emptyMap())
|
||||
}
|
||||
|
||||
fun `test should not resolve with escape character in multiline string slf4j`() {
|
||||
val multilineString = "\"\"\"\n" +
|
||||
"\\\\{<caret>}" +
|
||||
"\"\"\""
|
||||
myFixture.configureByText("Logging.java", """
|
||||
import org.slf4j.*;
|
||||
class Logging {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Logging.class);
|
||||
void m(int i) {
|
||||
LOG.info($multilineString, i);
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
doTest(emptyMap())
|
||||
}
|
||||
}
|
||||
@@ -482,4 +482,64 @@ class KotlinLoggingArgumentSymbolReferenceProviderTest : LoggingArgumentSymbolRe
|
||||
""".trimIndent())
|
||||
doTest(emptyMap())
|
||||
}
|
||||
|
||||
fun `test should resolve with escape character in simple string log4j2`() {
|
||||
myFixture.configureByText("Logging.kt", """
|
||||
import org.apache.logging.log4j.*
|
||||
class Logging {
|
||||
val LOG: Logger = LoggerFactory.getLogger(Logging.class)
|
||||
fun m(i: Int) {
|
||||
LOG.info("\\{<caret>}", i)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
doTest(mapOf(TextRange(3, 5) to "i"))
|
||||
}
|
||||
|
||||
|
||||
fun `test should resolve with escape character in multiline string log4j2`() {
|
||||
val multilineString = "\"\"\"\n" +
|
||||
"\\\\{<caret>}" +
|
||||
"\"\"\""
|
||||
myFixture.configureByText("Logging.kt", """
|
||||
import org.apache.logging.log4j.*
|
||||
class Logging {
|
||||
val LOG: Logger = LoggerFactory.getLogger(Logging.class)
|
||||
fun m(i: Int) {
|
||||
LOG.info("$multilineString", i)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
doTest(mapOf(TextRange(7, 9) to "i"))
|
||||
}
|
||||
|
||||
fun `test should not resolve with escape character in simple string slf4j`() {
|
||||
myFixture.configureByText("Logging.kt", """
|
||||
import org.slf4j.*
|
||||
class Logging {
|
||||
val LOG: Logger = LogManager.getFormatterLogger()
|
||||
fun m(i: Int) {
|
||||
LOG.info("\\{<caret>}", i)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
doTest(emptyMap())
|
||||
}
|
||||
|
||||
|
||||
fun `test should resolve with escape character in multiline string slf4j`() {
|
||||
val multilineString = "\"\"\"\n" +
|
||||
"\\\\{<caret>}" +
|
||||
"\"\"\""
|
||||
myFixture.configureByText("Logging.kt", """
|
||||
import org.slf4j.*
|
||||
class Logging {
|
||||
val LOG: Logger = LoggerFactory.getLogger(Logging.class)
|
||||
fun m(i: Int) {
|
||||
LOG.info("$multilineString", i)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
doTest(mapOf(TextRange(7, 9) to "i"))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user