[uast-inspection] IJ-CR-130570 IDEA-350483 New inspection LoggingGuardedByConditionInspection also deletes comments

- uast comment tracker

GitOrigin-RevId: d484939094c50bd5b7304d9703052f9841679c46
This commit is contained in:
Mikhail Pyltsin
2024-04-03 20:02:45 +00:00
committed by intellij-monorepo-bot
parent c446f2c4d0
commit 719bb1619c
10 changed files with 178 additions and 37 deletions
@@ -54,6 +54,9 @@
<extensionPoint qualifiedName="org.jetbrains.uast.generate.uastCodeGenerationPlugin"
interface="org.jetbrains.uast.generate.UastCodeGenerationPlugin"
dynamic="true"/>
<extensionPoint qualifiedName="org.jetbrains.uast.generate.uastCommentSaverFactory"
interface="org.jetbrains.uast.generate.UastCommentSaverFactory"
dynamic="true"/>
<extensionPoint qualifiedName="org.jetbrains.uast.evaluation.uastEvaluatorExtension"
interface="org.jetbrains.uast.evaluation.UEvaluatorExtension"
dynamic="true"/>
@@ -144,6 +147,7 @@
<uastLanguagePlugin implementation="org.jetbrains.uast.java.JavaUastLanguagePlugin"/>
<analysis.uastAnalysisPlugin implementation="org.jetbrains.uast.java.analysis.JavaUastAnalysisPlugin"/>
<generate.uastCodeGenerationPlugin implementation="org.jetbrains.uast.java.generate.JavaUastCodeGenerationPlugin"/>
<generate.uastCommentSaverFactory implementation="org.jetbrains.uast.java.generate.JavaUastCommentSaverFactory"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
@@ -11,13 +11,13 @@ import com.intellij.modcommand.ModPsiUpdater
import com.intellij.modcommand.PsiUpdateModCommandQuickFix
import com.intellij.openapi.project.Project
import com.intellij.profile.codeInspection.InspectionProjectProfileManager
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.uast.UastHintedVisitorAdapter
import org.jetbrains.uast.*
import org.jetbrains.uast.generate.UastCommentSaverFactory
import org.jetbrains.uast.generate.replace
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
import org.jetbrains.uast.visitor.AbstractUastVisitor
@@ -138,53 +138,27 @@ class LoggingGuardedByConditionInspection : AbstractBaseUastLocalInspectionTool(
uIfExpression.replace(thenExpression)
return
}
val ifStatementSourcePsi = uIfExpression.sourcePsi ?: return
val commentSaverFactory = UastCommentSaverFactory.byLanguage(ifStatementSourcePsi.language)
val commentSaver = commentSaverFactory?.grabComments(uIfExpression)
val expressions = thenExpression.expressions
if (expressions.isEmpty()) return
var currentParent = ifStatementSourcePsi.parent
var after = ifStatementSourcePsi
var nextExpression = expressions[0].sourcePsi
var lastExpression = expressions.last().sourcePsi
val lastExpression = expressions.last().sourcePsi ?: return
while (nextExpression?.parent.toUElement()?.sourcePsi == expressions[0].sourcePsi) {
nextExpression = nextExpression?.parent
}
while (lastExpression?.parent.toUElement()?.sourcePsi == expressions.last().sourcePsi) {
lastExpression = lastExpression?.parent
}
while (true) {
if (nextExpression?.prevSibling is PsiComment) {
nextExpression = nextExpression.prevSibling
continue
}
if(nextExpression?.prevSibling is PsiWhiteSpace && nextExpression.prevSibling?.prevSibling is PsiComment) {
nextExpression = nextExpression.prevSibling.prevSibling
continue
}
break
}
while (true) {
if (lastExpression?.nextSibling is PsiComment) {
lastExpression = lastExpression.nextSibling
continue
}
if (lastExpression?.nextSibling is PsiWhiteSpace && lastExpression.nextSibling?.nextSibling is PsiComment) {
lastExpression = lastExpression.nextSibling.nextSibling
continue
}
break
}
if (nextExpression == null) return
if (lastExpression == null) return
while (true) {
if (nextExpression == null) break
commentSaver?.markUnchanged(nextExpression.toUElement())
var newAdded: PsiElement = currentParent.addAfter(nextExpression.copy(), after)
if (nextExpression is PsiWhiteSpace) {
while (newAdded.nextSibling !is PsiWhiteSpace) {
@@ -200,6 +174,10 @@ class LoggingGuardedByConditionInspection : AbstractBaseUastLocalInspectionTool(
nextExpression = nextExpression.nextSibling ?: break
}
ifStatementSourcePsi.delete()
val uElement = after.toUElement()
if (uElement != null) {
commentSaver?.restore(uElement)
}
}
}
}
@@ -217,10 +217,9 @@ class JavaLoggingGuardedByConditionInspectionTest : LoggingGuardedByConditionIns
void n(String arg) {
//comment1
//comment2
LOG.debug("test" + arg);
//comment3
//comment4
LOG.debug("test" + arg);
}
}
""".trimIndent(),
@@ -103,6 +103,7 @@
<analysis.uastAnalysisPlugin implementation="org.jetbrains.uast.kotlin.analysis.KotlinUastAnalysisPlugin"/>
<evaluation.uastEvaluatorExtension implementation="org.jetbrains.uast.kotlin.evaluation.KotlinEvaluatorExtension"/>
<generate.uastCodeGenerationPlugin implementation="org.jetbrains.uast.kotlin.generate.KotlinUastCodeGenerationPlugin"/>
<generate.uastCommentSaverFactory implementation="org.jetbrains.uast.kotlin.generate.KotlinUastCommentSaverFactory"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
@@ -57,6 +57,7 @@
<extensions defaultExtensionNs="org.jetbrains.uast">
<uastLanguagePlugin implementation="org.jetbrains.uast.kotlin.FirKotlinUastLanguagePlugin"/>
<generate.uastCodeGenerationPlugin implementation="org.jetbrains.uast.kotlin.FirKotlinUastCodeGenerationPlugin"/>
<generate.uastCommentSaverFactory implementation="org.jetbrains.uast.kotlin.generate.KotlinUastCommentSaverFactory"/>
</extensions>
<applicationListeners>
@@ -24,5 +24,6 @@
<orderEntry type="module" module-name="kotlin.gradle.gradle" scope="RUNTIME" />
<orderEntry type="module" module-name="kotlin.test-framework" scope="TEST" />
<orderEntry type="module" module-name="kotlin.base.util" />
<orderEntry type="module" module-name="kotlin.base.code-insight" />
</component>
</module>
@@ -0,0 +1,34 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.uast.kotlin.generate
import com.intellij.lang.Language
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.psi.psiUtil.PsiChildRange
import org.jetbrains.uast.UElement
import org.jetbrains.uast.generate.UastCommentSaverFactory
@ApiStatus.Experimental
class KotlinUastCommentSaverFactory: UastCommentSaverFactory {
override val language: Language
get() = KotlinLanguage.INSTANCE
override fun grabComments(firstResultUElement: UElement, lastResultUElement: UElement?): UastCommentSaverFactory.UastCommentSaver? {
val firstSourcePsiElement = firstResultUElement.sourcePsi ?: return null
val lastSourcePsiElement = lastResultUElement?.sourcePsi ?: firstSourcePsiElement
val commentSaver = CommentSaver(PsiChildRange(firstSourcePsiElement, lastSourcePsiElement))
return object : UastCommentSaverFactory.UastCommentSaver{
override fun restore(firstResultUElement: UElement, lastResultUElement: UElement?) {
val firstPsiElement = firstResultUElement.sourcePsi ?: return
val lastPsiElement = lastResultUElement?.sourcePsi ?: firstPsiElement
commentSaver.restore(PsiChildRange(firstPsiElement, lastPsiElement))
}
override fun markUnchanged(firstResultUElement: UElement?, lastResultUElement: UElement?) {
//do nothing
}
}
}
}
@@ -0,0 +1,34 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.uast.kotlin.generate
import com.intellij.lang.Language
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.psi.psiUtil.PsiChildRange
import org.jetbrains.uast.UElement
import org.jetbrains.uast.generate.UastCommentSaverFactory
@ApiStatus.Experimental
class KotlinUastCommentSaverFactory: UastCommentSaverFactory {
override val language: Language
get() = KotlinLanguage.INSTANCE
override fun grabComments(firstResultUElement: UElement, lastResultUElement: UElement?): UastCommentSaverFactory.UastCommentSaver? {
val firstSourcePsiElement = firstResultUElement.sourcePsi ?: return null
val lastSourcePsiElement = lastResultUElement?.sourcePsi ?: firstSourcePsiElement
val commentSaver = CommentSaver(PsiChildRange(firstSourcePsiElement, lastSourcePsiElement))
return object : UastCommentSaverFactory.UastCommentSaver{
override fun restore(firstResultUElement: UElement, lastResultUElement: UElement?) {
val firstPsiElement = firstResultUElement.sourcePsi ?: return
val lastPsiElement = lastResultUElement?.sourcePsi ?: firstPsiElement
commentSaver.restore(PsiChildRange(firstPsiElement, lastPsiElement))
}
override fun markUnchanged(firstResultUElement: UElement?, lastResultUElement: UElement?) {
//do nothing
}
}
}
}
@@ -0,0 +1,41 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.uast.generate
import com.intellij.lang.Language
import com.intellij.openapi.extensions.ExtensionPointName
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.uast.UElement
/**
* Represents a factory for creating UastCommentSaver instances, which can be used to save and restore comments.
*
*/
@ApiStatus.Experimental
interface UastCommentSaverFactory {
companion object {
private val extensionPointName = ExtensionPointName<UastCommentSaverFactory>("org.jetbrains.uast.generate.uastCommentSaverFactory")
@JvmStatic
fun byLanguage(language: Language): UastCommentSaverFactory? = extensionPointName.extensionList.firstOrNull { it.language == language }
}
/**
* The underlying programming language.
*/
val language: Language
/**
* Retrieves the comments associated with the given UElement.
*
* @return The UastCommentSaver containing the comments associated with the UElement, null if it is impossible to create
*/
fun grabComments(firstResultUElement: UElement, lastResultUElement: UElement? = null): UastCommentSaver?
/**
* Represents an interface for restoring comments which are not included in resultUElements.
*/
interface UastCommentSaver {
fun restore(firstResultUElement: UElement, lastResultUElement: UElement? = null)
fun markUnchanged(firstResultUElement: UElement?, lastResultUElement: UElement? = null)
}
}
@@ -0,0 +1,48 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.uast.java.generate
import com.intellij.lang.Language
import com.intellij.lang.java.JavaLanguage
import com.intellij.psi.PsiElement
import com.siyeh.ig.psiutils.CommentTracker
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.uast.UElement
import org.jetbrains.uast.generate.UastCommentSaverFactory
import org.jetbrains.uast.toUElement
@ApiStatus.Experimental
internal class JavaUastCommentSaverFactory : UastCommentSaverFactory {
override val language: Language
get() = JavaLanguage.INSTANCE
override fun grabComments(firstResultUElement: UElement, lastResultUElement: UElement?): UastCommentSaverFactory.UastCommentSaver? {
val firstSourcePsiElement = firstResultUElement.sourcePsi ?: return null
val lastSourcePsiElement = lastResultUElement?.sourcePsi ?: firstSourcePsiElement
val commentTracker = CommentTracker()
var e = firstSourcePsiElement
commentTracker.grabComments(e)
while (e !== lastSourcePsiElement) {
e = e.getNextSibling() ?: break
commentTracker.grabComments(e)
}
return object : UastCommentSaverFactory.UastCommentSaver {
override fun restore(firstResultUElement: UElement, lastResultUElement: UElement?) {
var target: PsiElement? = firstResultUElement.sourcePsi ?: return
while (target?.parent.toUElement()?.sourcePsi == firstResultUElement.sourcePsi) {
target = target?.parent
}
if (target != null) {
commentTracker.insertCommentsBefore(target)
}
}
override fun markUnchanged(firstResultUElement: UElement?, lastResultUElement: UElement?) {
val firstPsiElement = firstResultUElement?.sourcePsi ?: return
val lastPsiElement = lastResultUElement?.sourcePsi ?: firstPsiElement
commentTracker.markRangeUnchanged(firstPsiElement, lastPsiElement)
}
}
}
}