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

- move commenter into UastCodeGenerationPlugin

GitOrigin-RevId: 8c0079fb1e3c0b7f4606bca547e40721c118b9c2
This commit is contained in:
Mikhail Pyltsin
2024-04-09 13:05:43 +02:00
committed by intellij-monorepo-bot
parent 70962589e8
commit df6d77f795
12 changed files with 114 additions and 126 deletions

View File

@@ -54,9 +54,6 @@
<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"/>
@@ -147,7 +144,6 @@
<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">

View File

@@ -17,7 +17,7 @@ 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.UastCodeGenerationPlugin
import org.jetbrains.uast.generate.replace
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
import org.jetbrains.uast.visitor.AbstractUastVisitor
@@ -142,9 +142,9 @@ class LoggingGuardedByConditionInspection : AbstractBaseUastLocalInspectionTool(
val ifStatementSourcePsi = uIfExpression.sourcePsi ?: return
val commentSaverFactory = UastCommentSaverFactory.byLanguage(ifStatementSourcePsi.language)
val uastCodeGenerationPlugin = UastCodeGenerationPlugin.byLanguage(ifStatementSourcePsi.language)
val commentSaver = commentSaverFactory?.grabComments(uIfExpression)
val commentSaver = uastCodeGenerationPlugin?.grabComments(uIfExpression)
val expressions = thenExpression.expressions
if (expressions.isEmpty()) return

View File

@@ -103,7 +103,6 @@
<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">

View File

@@ -56,8 +56,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"/>
<generate.uastCodeGenerationPlugin implementation="org.jetbrains.uast.kotlin.IdeaFirKotlinUastCodeGenerationPlugin"/>
</extensions>
<applicationListeners>

View File

@@ -4,18 +4,14 @@ package org.jetbrains.uast.kotlin
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisFromWriteAction
import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisFromWriteAction
import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.uast.generate.UastElementFactory
import org.jetbrains.uast.kotlin.generate.KotlinUastBaseCodeGenerationPlugin
import org.jetbrains.uast.kotlin.generate.KotlinUastElementFactory
import org.jetbrains.uast.kotlin.internal.analyzeForUast
class FirKotlinUastCodeGenerationPlugin : KotlinUastBaseCodeGenerationPlugin() {
open class FirKotlinUastCodeGenerationPlugin : KotlinUastBaseCodeGenerationPlugin() {
@OptIn(KtAllowAnalysisOnEdt::class)
override fun shortenReference(sourcePsi: KtElement): PsiElement {
val ktFile = sourcePsi.containingKtFile

View File

@@ -1,34 +1,26 @@
// 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
import org.jetbrains.uast.generate.UastCommentSaver
@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
}
fun createUastCommentSaver(firstResultUElement: UElement, lastResultUElement: UElement): UastCommentSaver? {
val firstSourcePsiElement = firstResultUElement.sourcePsi ?: return null
val lastSourcePsiElement = lastResultUElement.sourcePsi ?: firstSourcePsiElement
val commentSaver = CommentSaver(PsiChildRange(firstSourcePsiElement, lastSourcePsiElement))
return object : 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
}
}
}
}

View File

@@ -0,0 +1,13 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.uast.kotlin
import org.jetbrains.uast.UElement
import org.jetbrains.uast.generate.UastCommentSaver
import org.jetbrains.uast.kotlin.generate.createUastCommentSaver
class IdeaFirKotlinUastCodeGenerationPlugin : FirKotlinUastCodeGenerationPlugin(){
override fun grabComments(firstResultUElement: UElement, lastResultUElement: UElement): UastCommentSaver? {
return createUastCommentSaver(firstResultUElement, lastResultUElement)
}
}

View File

@@ -22,8 +22,10 @@ import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.UQualifiedReferenceExpression
import org.jetbrains.uast.generate.UastCommentSaver
import org.jetbrains.uast.generate.UastElementFactory
import org.jetbrains.uast.toUElementOfType
@@ -68,4 +70,8 @@ class KotlinUastCodeGenerationPlugin : KotlinUastBaseCodeGenerationPlugin() {
}
}
}
override fun grabComments(firstResultUElement: UElement, lastResultUElement: UElement): UastCommentSaver? {
return createUastCommentSaver(firstResultUElement, lastResultUElement)
}
}

View File

@@ -114,6 +114,32 @@ interface UastCodeGenerationPlugin {
* @return new return expression with changed label if return is explicit, otherwise same expression if return is implicit
*/
fun changeLabel(returnExpression: UReturnExpression, context: PsiElement) : UReturnExpression
/**
* Retrieves the comments associated with the given UElement and restore after modifications.
*
* Example:
* ```
* if(a()){
* //some comments
* doSomething();
* }
* ```
* Becomes after grabbing and restoring comments:
* ```
* //some comments
* doSomething();
* ```
* The process includes three steps:
* - grab comments (collect comments from the range)
* - mark unchanged comments (optional step. Comments, which are not changed, should be marked and they will not be restored)
* - restore comments after modification (Usually comments will be restored before anchors)
*
* The implementation and places for new comments can be different for different languages and rely on language plugins
*
* @return The UastCommentSaver containing the comments associated with the UElement, null if it is impossible to create
*/
fun grabComments(firstResultUElement: UElement, lastResultUElement: UElement = firstResultUElement): UastCommentSaver? = null
}
/**
@@ -232,3 +258,22 @@ val UElement.generationPlugin: UastCodeGenerationPlugin?
fun UElement.getUastElementFactory(project: Project): UastElementFactory? =
generationPlugin?.getElementFactory(project)
/**
* Represents an interface for restoring comments which are not included in resultUElements.
*/
@ApiStatus.Experimental
interface UastCommentSaver {
/**
* Restore comments.
* Given range of elements is used as an anchor
* and can be used to calculate what comments should be restored.
* This method can be called only once.
*/
fun restore(firstResultUElement: UElement, lastResultUElement: UElement = firstResultUElement)
/**
* Marks comments inside the given range of UElements as unchanged.
* These comments will not be restored
*/
fun markUnchanged(firstResultUElement: UElement?, lastResultUElement: UElement? = firstResultUElement)
}

View File

@@ -1,41 +0,0 @@
// 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)
}
}

View File

@@ -17,10 +17,12 @@ import com.intellij.psi.impl.source.tree.ElementType
import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl
import com.intellij.psi.util.*
import com.intellij.util.asSafely
import com.siyeh.ig.psiutils.CommentTracker
import com.siyeh.ig.psiutils.ParenthesesUtils
import org.jetbrains.uast.*
import org.jetbrains.uast.generate.UParameterInfo
import org.jetbrains.uast.generate.UastCodeGenerationPlugin
import org.jetbrains.uast.generate.UastCommentSaver
import org.jetbrains.uast.generate.UastElementFactory
import org.jetbrains.uast.java.*
@@ -134,6 +136,35 @@ internal class JavaUastCodeGenerationPlugin : UastCodeGenerationPlugin {
}
override fun changeLabel(returnExpression: UReturnExpression, context: PsiElement): UReturnExpression = returnExpression
override fun grabComments(firstResultUElement: UElement, lastResultUElement: UElement): 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 : 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)
}
}
}
}
private fun PsiElementFactory.createExpressionStatement(expression: PsiExpression, oldElement: UElement? = null): PsiStatement? {

View File

@@ -1,48 +0,0 @@
// 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)
}
}
}
}