mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +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
|
package com.intellij.analysis.logging.resolve
|
||||||
|
|
||||||
import com.intellij.codeInspection.logging.*
|
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.codeInspection.logging.PlaceholderLoggerType.*
|
||||||
import com.intellij.model.Symbol
|
import com.intellij.model.Symbol
|
||||||
import com.intellij.model.psi.PsiExternalReferenceHost
|
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.psi.PsiSymbolReferenceProvider
|
||||||
import com.intellij.model.search.SearchRequest
|
import com.intellij.model.search.SearchRequest
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.uast.UCallExpression
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.UExpression
|
|
||||||
import org.jetbrains.uast.expressions.UInjectionHost
|
import org.jetbrains.uast.expressions.UInjectionHost
|
||||||
import org.jetbrains.uast.getParentOfType
|
|
||||||
import org.jetbrains.uast.toUElementOfType
|
|
||||||
|
|
||||||
class LoggingArgumentSymbolReferenceProvider : PsiSymbolReferenceProvider {
|
class LoggingArgumentSymbolReferenceProvider : PsiSymbolReferenceProvider {
|
||||||
override fun getReferences(element: PsiExternalReferenceHost, hints: PsiSymbolReferenceHints): Collection<PsiSymbolReference> {
|
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>? {
|
internal fun getPlaceholderRanges(context: PlaceholderContext): List<PlaceholderRanges>? {
|
||||||
val logStringText = context.logStringArgument.sourcePsi?.text ?: return null
|
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(
|
val partHolders = listOf(
|
||||||
LoggingStringPartEvaluator.PartHolder(
|
LoggingStringPartEvaluator.PartHolder(
|
||||||
logStringText,
|
logStringText,
|
||||||
true
|
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
|
if (placeholderCountResult.status != PlaceholdersStatus.EXACTLY) return null
|
||||||
|
|
||||||
return placeholderCountResult.placeholderRangesList
|
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
|
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) {
|
if (placeholderCountHolder.status == PlaceholdersStatus.EMPTY) {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -124,6 +124,26 @@ internal enum class PlaceholdersStatus {
|
|||||||
EXACTLY, PARTIAL, ERROR_TO_PARSE_STRING, EMPTY
|
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)
|
internal class LoggerContext(val log4jAsImplementationForSlf4j: Boolean)
|
||||||
|
|
||||||
@@ -300,6 +320,7 @@ internal fun findAdditionalArguments(node: UCallExpression,
|
|||||||
* @param loggerType The type of the logger used.
|
* @param loggerType The type of the logger used.
|
||||||
* @param argumentCount The number of arguments that the logger is expected to handle.
|
* @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 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.
|
* @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,
|
loggerType: PlaceholderLoggerType,
|
||||||
argumentCount: Int,
|
argumentCount: Int,
|
||||||
holders: List<LoggingStringPartEvaluator.PartHolder>,
|
holders: List<LoggingStringPartEvaluator.PartHolder>,
|
||||||
|
placeholderCountShiftIndexStrategy: PlaceholderCountIndexStrategy
|
||||||
): PlaceholderCountResult {
|
): PlaceholderCountResult {
|
||||||
return if (loggerType == PlaceholderLoggerType.LOG4J_FORMATTED_STYLE) {
|
return if (loggerType == PlaceholderLoggerType.LOG4J_FORMATTED_STYLE) {
|
||||||
countFormattedBasedPlaceholders(holders, argumentCount)
|
countFormattedBasedPlaceholders(holders, argumentCount)
|
||||||
}
|
}
|
||||||
else {
|
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)
|
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 count = 0
|
||||||
var full = true
|
var full = true
|
||||||
val placeholderRangeList: MutableList<PlaceholderRanges> = mutableListOf()
|
val placeholderRangeList: MutableList<PlaceholderRanges> = mutableListOf()
|
||||||
@@ -448,14 +472,17 @@ private fun countBracesBasedPlaceholders(holders: List<LoggingStringPartEvaluato
|
|||||||
val length = string.length
|
val length = string.length
|
||||||
var escaped = false
|
var escaped = false
|
||||||
var lastPlaceholderIndex = -1
|
var lastPlaceholderIndex = -1
|
||||||
for (i in 0 until length) {
|
var i = 0
|
||||||
|
while (i < length) {
|
||||||
val c = string[i]
|
val c = string[i]
|
||||||
if (c == '\\' &&
|
if (c == '\\' &&
|
||||||
(loggerType == PlaceholderLoggerType.SLF4J_EQUAL_PLACEHOLDERS || loggerType == PlaceholderLoggerType.SLF4J)) {
|
(loggerType == PlaceholderLoggerType.SLF4J_EQUAL_PLACEHOLDERS || loggerType == PlaceholderLoggerType.SLF4J)) {
|
||||||
escaped = !escaped
|
escaped = !escaped
|
||||||
|
i = placeholderCountShiftIndexStrategy.shiftAfterEscapeChar(i)
|
||||||
}
|
}
|
||||||
else if (c == '{') {
|
else if (c == '{') {
|
||||||
if (holderIndex != 0 && i == 0 && !holders[holderIndex - 1].isConstant) {
|
if (holderIndex != 0 && i == 0 && !holders[holderIndex - 1].isConstant) {
|
||||||
|
i += 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (!escaped) {
|
if (!escaped) {
|
||||||
@@ -477,6 +504,7 @@ private fun countBracesBasedPlaceholders(holders: List<LoggingStringPartEvaluato
|
|||||||
escaped = false
|
escaped = false
|
||||||
lastPlaceholderIndex = -1
|
lastPlaceholderIndex = -1
|
||||||
}
|
}
|
||||||
|
i += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PlaceholderCountResult(placeholderRangeList, if (full) PlaceholdersStatus.EXACTLY else PlaceholdersStatus.PARTIAL)
|
return PlaceholderCountResult(placeholderRangeList, if (full) PlaceholdersStatus.EXACTLY else PlaceholdersStatus.PARTIAL)
|
||||||
|
|||||||
@@ -464,4 +464,64 @@ class JavaLoggingArgumentSymbolReferenceProviderTest : LoggingArgumentSymbolRefe
|
|||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
doTest(emptyMap())
|
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())
|
""".trimIndent())
|
||||||
doTest(emptyMap())
|
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