[java-inspections] IJ-CR-27871 Introduce local variable in preview

GitOrigin-RevId: 1d9b8d6e4acab1a48e99370cf8a296e84309d7f2
This commit is contained in:
Bart van Helvert
2022-08-04 15:48:33 +02:00
committed by intellij-monorepo-bot
parent adf4b5bc15
commit 07e6ec4678
15 changed files with 88 additions and 53 deletions

View File

@@ -2,6 +2,8 @@
package com.intellij.codeInspection.varScopeCanBeNarrowed;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.FileModifier;
import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.java.JavaBundle;
@@ -41,6 +43,11 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen
return false;
}
@Override
public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) {
return LocalQuickFix.super.getFileModifierForPreview(target);
}
@Nullable
protected abstract V getVariable(@NotNull ProblemDescriptor descriptor);
@@ -54,7 +61,9 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final V variable = getVariable(descriptor);
if (variable == null || !variable.isValid()) return; //weird. should not get here when field becomes invalid
if (!FileModificationService.getInstance().prepareFileForWrite(descriptor.getPsiElement().getContainingFile())) return;
if (!IntentionPreviewUtils.isPreviewElement(variable)
&& !FileModificationService.getInstance().prepareFileForWrite(descriptor.getPsiElement().getContainingFile())
) return;
final PsiFile myFile = variable.getContainingFile();
try {
final List<PsiElement> newDeclarations = moveDeclaration(project, variable);
@@ -74,12 +83,19 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen
final PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(newVariable.getInitializer());
if (VariableAccessUtils.isLocalVariableCopy(newVariable, initializer)) {
Collection<PsiReference> references = ReferencesSearch.search(newVariable).findAll();
WriteAction.run(() -> {
if (IntentionPreviewUtils.isPreviewElement(declaration)) {
for (PsiReference reference : references) {
CommonJavaInlineUtil.getInstance().inlineVariable(newVariable, initializer, (PsiJavaCodeReferenceElement)reference, null);
}
declaration.delete();
});
} else { // TODO don't copy paste
WriteAction.run(() -> {
for (PsiReference reference : references) {
CommonJavaInlineUtil.getInstance().inlineVariable(newVariable, initializer, (PsiJavaCodeReferenceElement)reference, null);
}
declaration.delete();
});
}
}
}
}

View File

@@ -5,6 +5,7 @@ import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.daemon.ImplicitUsageProvider;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.codeInspection.util.IntentionName;
@@ -425,6 +426,12 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
return CommonJavaRefactoringUtil.suggestUniqueVariableName(localName, scope, field);
}
@Override
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) {
applyFix(project, previewDescriptor);
return IntentionPreviewInfo.DIFF;
}
@NotNull
@Override
protected List<PsiElement> moveDeclaration(@NotNull final Project project, @NotNull final PsiField variable) {
@@ -433,19 +440,25 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
final PsiClass containingClass = variable.getContainingClass();
if (containingClass == null) return newDeclarations;
final PsiClass scope = findVariableScope(containingClass);
if (!groupByCodeBlocks(ReferencesSearch.search(variable, new LocalSearchScope(scope)).findAll(), refs)) return newDeclarations;
if (!groupByCodeBlocks(ReferencesSearch.search(variable, new LocalSearchScope(scope)).findAll(), refs)) return newDeclarations;
PsiElement declaration;
for (Collection<PsiReference> psiReferences : refs.values()) {
declaration = WriteAction.compute(() -> copyVariableToMethodBody(variable, psiReferences));
if (IntentionPreviewUtils.isPreviewElement(variable)) {
declaration = copyVariableToMethodBody(variable, psiReferences);
} else {
declaration = WriteAction.compute(() -> copyVariableToMethodBody(variable, psiReferences));
}
if (declaration != null) newDeclarations.add(declaration);
}
return WriteAction.compute(() -> {
if (!newDeclarations.isEmpty()) {
final PsiElement lastDeclaration = newDeclarations.get(newDeclarations.size() - 1);
if (!newDeclarations.isEmpty()) {
final PsiElement lastDeclaration = newDeclarations.get(newDeclarations.size() - 1);
if (IntentionPreviewUtils.isPreviewElement(variable)) {
deleteField(variable, lastDeclaration);
} else {
WriteAction.run(() -> deleteField(variable, lastDeclaration));
}
return newDeclarations;
});
}
return newDeclarations;
}
private static void deleteField(@NotNull PsiField variable, PsiElement newDeclaration) {
@@ -454,13 +467,5 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
tracker.delete(variable);
tracker.insertCommentsBefore(newDeclaration);
}
@Override
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) {
PsiField field = getVariable(previewDescriptor);
if (field == null) return IntentionPreviewInfo.EMPTY;
field.delete();
return IntentionPreviewInfo.DIFF;
}
}
}

View File

@@ -3,6 +3,7 @@ package com.intellij.codeInspection.varScopeCanBeNarrowed;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils;
import com.intellij.codeInspection.*;
import com.intellij.java.JavaBundle;
import com.intellij.openapi.application.WriteAction;
@@ -144,6 +145,12 @@ public class ParameterCanBeLocalInspection extends AbstractBaseJavaLocalInspecti
return parameter.getName();
}
@Override
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) {
applyFix(project, previewDescriptor);
return IntentionPreviewInfo.DIFF;
}
@Override
@NotNull
protected List<PsiElement> moveDeclaration(@NotNull Project project, @NotNull PsiParameter variable) {
@@ -152,7 +159,9 @@ public class ParameterCanBeLocalInspection extends AbstractBaseJavaLocalInspecti
final PsiElement scope = variable.getDeclarationScope();
if (!(scope instanceof PsiMethod)) return Collections.emptyList();
final PsiMethod method = (PsiMethod)scope;
if (!FileModificationService.getInstance().preparePsiElementsForWrite(method)) return Collections.emptyList();
if (!IntentionPreviewUtils.isPreviewElement(variable)
&& !FileModificationService.getInstance().preparePsiElementsForWrite(method)
) return Collections.emptyList();
final PsiParameter[] parameters = method.getParameterList().getParameters();
final List<ParameterInfoImpl> info = new ArrayList<>();
for (int i = 0; i < parameters.length; i++) {
@@ -162,25 +171,24 @@ public class ParameterCanBeLocalInspection extends AbstractBaseJavaLocalInspecti
}
final ParameterInfoImpl[] newParams = info.toArray(new ParameterInfoImpl[0]);
final String visibilityModifier = VisibilityUtil.getVisibilityModifier(method.getModifierList());
PsiElement moved = WriteAction.compute(() -> copyVariableToMethodBody(variable, references));
PsiElement moved;
if (IntentionPreviewUtils.isPreviewElement(variable)) {
moved = copyVariableToMethodBody(variable, references);
} else {
moved = WriteAction.compute(() -> copyVariableToMethodBody(variable, references));
}
if (moved == null) return Collections.emptyList();
SmartPsiElementPointer<PsiElement> newDeclaration = SmartPointerManager.createPointer(moved);
var processor = JavaRefactoringFactory.getInstance(project).createChangeSignatureProcessor(
method, false, visibilityModifier, method.getName(), method.getReturnType(), newParams,
null, null, null, null
);
processor.run();
if (IntentionPreviewUtils.isPreviewElement(variable)) {
variable.delete();
} else {
var processor = JavaRefactoringFactory.getInstance(project).createChangeSignatureProcessor(
method, false, visibilityModifier, method.getName(), method.getReturnType(), newParams,
null, null, null, null
);
processor.run();
}
return Collections.singletonList(Objects.requireNonNull(newDeclaration.getElement()));
}
@Override
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) {
PsiParameter parameter = getVariable(previewDescriptor);
if (parameter == null) return IntentionPreviewInfo.EMPTY;
final Collection<PsiReference> references = ReferencesSearch.search(parameter).findAll();
copyVariableToMethodBody(parameter, references);
parameter.delete();
return IntentionPreviewInfo.DIFF;
}
}
}

View File

@@ -2,7 +2,8 @@
class Test {
int getFoo1(boolean f) {
if (f) {
int myFoo;
if (f) {
myFoo = 1;
}
else {

View File

@@ -5,7 +5,9 @@ class ITest {
public IntelliJBugConvertToLocal(int x, int z) {
if (x == 5) {
//my comment to keep in code
ArrayList<String> mayBeLocal = new ArrayList<String>();
if (x == 5) {
mayBeLocal.add("jjj");
}

View File

@@ -2,8 +2,7 @@
class Test {
public Test(String param) {
field = param;
System.out.println(field == null ? "null" : field);
System.out.println(param == null ? "null" : param);
}
}

View File

@@ -3,7 +3,11 @@ class TestFieldConversion
{
public void someMethod(int s) {
switch (s) {
/**
* doc1
*/
int someInt = 0;
switch (s) {
case 1:
System.out.println(someInt);
break;

View File

@@ -2,7 +2,7 @@
class TestInitializer {
{
field = true;
boolean field = true;
System.out.println(field);
}

View File

@@ -4,8 +4,8 @@ class Foo {
class Bar {
void test() {
x = 2; // could be local
System.out.println(x);
int x = 2; // could be local
System.out.println(x);
}
}
}

View File

@@ -5,12 +5,12 @@ class Outer {
class Local {
void foo() {
s = "1";
String s = "1";
System.out.println(s);
}
void bar() {
s = "2";
String s = "2";
System.out.println(s);
}

View File

@@ -2,13 +2,13 @@
class Test {
int getFoo1() {
myFoo//c1
= 1;
//c1
int myFoo = 1;
return myFoo;
}
int getFoo2() {
myFoo = 2;
int myFoo = 2;
return myFoo;
}
}

View File

@@ -12,6 +12,5 @@ class MyClassTest {
}
public void setEditable1(final boolean editable1) {
this.editable1 = editable1;
}
}

View File

@@ -3,8 +3,8 @@ class Foo {
static class Bar {
void test() {
x = 2; // could be local
System.out.println(x);
int x = 2; // could be local
System.out.println(x);
}
}
}

View File

@@ -2,6 +2,6 @@
class Test {
private Runnable r = () -> {
field = "foo";
String field = "foo";
}
}

View File

@@ -6,7 +6,8 @@ class FieldCanBeLocalTest extends JPanel {
public FieldCanBeLocalTest() {
super();
setName(name);
String name = "MyName";
setName(name);
}
public static void main(String[] args) {}