[intention-preview] IDEA-304606 Call generatePreview with the copy of file from getElementToMakeWritable, rather than current file

Tested with AddModuleDirectiveFix

GitOrigin-RevId: 769cbab88190cb59bd767d53faf91095a8953ba4
This commit is contained in:
Tagir Valeev
2022-10-26 15:49:33 +00:00
committed by intellij-monorepo-bot
parent 5d36f1f497
commit f84e0b42a8
4 changed files with 17 additions and 20 deletions
@@ -3,12 +3,10 @@ package com.intellij.codeInsight.daemon.impl.quickfix
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.codeInsight.intention.impl.BaseIntentionAction
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.PsiUtil
abstract class AddModuleDirectiveFix(module: PsiJavaModule) : LocalQuickFixAndIntentionActionOnPsiElement(module) {
@@ -21,14 +19,6 @@ abstract class AddModuleDirectiveFix(module: PsiJavaModule) : LocalQuickFixAndIn
invoke(project, startElement as PsiJavaModule)
protected abstract fun invoke(project: Project, module: PsiJavaModule)
override fun generatePreview(project: Project, editor: Editor, file: PsiFile): IntentionPreviewInfo {
val moduleFile = (startElement.containingFile.copy() as? PsiFile) ?: return IntentionPreviewInfo.EMPTY
val module = (PsiTreeUtil.findSameElementInCopy(startElement, moduleFile) as? PsiJavaModule) ?: return IntentionPreviewInfo.EMPTY
val beforeText = module.text
invoke(project, module)
return IntentionPreviewInfo.CustomDiff(moduleFile.fileType, moduleFile.name, beforeText, module.text)
}
}
class AddRequiresDirectiveFix(module: PsiJavaModule, private val requiredName: String) : AddModuleDirectiveFix(module) {
@@ -57,7 +57,8 @@ class Java9ReflectionClassVisibilityTest : LightJava9ModulesCodeInsightFixtureTe
fun testExportsPackagePreview() {
moduleInfo("module MAIN { requires API; }", MAIN)
moduleInfo("module API { exports my.api; }", M2)
doTestPreview("Add 'exports my.impl' directive to module-info.java", "module API { exports my.api; exports my.impl; }")
doTestPreview("Add 'exports my.impl' directive to module-info.java",
"module API { exports my.api;\n exports my.impl;\n}")
}
fun testNotInRequirements() {
@@ -107,8 +107,10 @@ public interface IntentionAction extends FileModifier {
* overriding {@code getFileModifierForPreview} or {@code generatePreview} is desired.
*
* @param project current project
* @param editor editor. Could be a simplified headless Editor implementation that lacks some features.
* @param file non-physical file to apply
* @param editor editor where a file copy is opened.
* Could be a simplified headless Editor implementation that lacks some features.
* @param file a non-physical file to apply, which is a copy of the file that contains element returned from
* {@link #getElementToMakeWritable(PsiFile)}, or copy of the current file if that method returns null
* @return an object that describes the action preview to display
*/
default @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
@@ -107,11 +107,14 @@ internal class IntentionPreviewComputable(private val project: Project,
IntentionPreviewInfo.DIFF,
IntentionPreviewInfo.DIFF_NO_TRIM -> {
val document = psiFileCopy!!.viewProvider.document
val anotherFile = psiFileCopy.originalFile != origFile
val policy = if (result == IntentionPreviewInfo.DIFF) ComparisonPolicy.TRIM_WHITESPACES else ComparisonPolicy.DEFAULT
IntentionPreviewDiffResult(
psiFile = psiFileCopy,
origFile = origFile,
origFile = psiFileCopy.originalFile,
policy = policy,
fileName = if (anotherFile) psiFileCopy.name else null,
normalDiff = !anotherFile,
lineFragments = comparisonManager.compareLines(origFile.text, document.text, policy, DumbProgressIndicator.INSTANCE))
}
IntentionPreviewInfo.EMPTY, IntentionPreviewInfo.FALLBACK_DIFF -> null
@@ -135,21 +138,22 @@ internal class IntentionPreviewComputable(private val project: Project,
private fun invokePreview(origFile: PsiFile, selection: TextRange, caretOffset: Int): Pair<IntentionPreviewInfo, PsiFile?> {
var info: IntentionPreviewInfo = IntentionPreviewInfo.EMPTY
val psiFileCopy = IntentionPreviewUtils.obtainCopyForPreview(origFile)
val fileToCopy = action.getElementToMakeWritable(origFile) ?. containingFile ?: origFile
val psiFileCopy = IntentionPreviewUtils.obtainCopyForPreview(fileToCopy)
val editorCopy = IntentionPreviewEditor(psiFileCopy, originalEditor.settings)
editorCopy.caretModel.moveToOffset(caretOffset)
editorCopy.selectionModel.setSelection(selection.startOffset, selection.endOffset)
if (fileToCopy == origFile) {
editorCopy.caretModel.moveToOffset(caretOffset)
editorCopy.selectionModel.setSelection(selection.startOffset, selection.endOffset)
}
originalEditor.document.setReadOnly(true)
ProgressManager.checkCanceled()
IntentionPreviewUtils.previewSession(editorCopy) {
PostprocessReformattingAspect.getInstance(project)
.postponeFormattingInside { info = action.generatePreview(project, editorCopy, psiFileCopy) }
}
if (info == IntentionPreviewInfo.FALLBACK_DIFF) {
if (info == IntentionPreviewInfo.FALLBACK_DIFF && fileToCopy == origFile) {
if (!action.startInWriteAction()) return info to null
if (action.getElementToMakeWritable(originalFile)?.containingFile !== originalFile) return info to null
// Use fallback algorithm only if invokeForPreview is not explicitly overridden
// in this case, the absence of diff could be intended, thus should not be logged as error
val action = findCopyIntention(project, editorCopy, psiFileCopy, action) ?: return info to null
val unwrapped = IntentionActionDelegate.unwrap(action)
val cls = (if (unwrapped is QuickFixWrapper) unwrapped.fix else unwrapped)::class.java