mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
IDEA-169518 Convert "Move assignment to field declaration" to the inspection
This commit is contained in:
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return CodeInsightBundle.message("intention.move.field.assignment.to.declaration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
PsiAssignmentExpression assignment = getAssignmentUnderCaret(editor, file);
|
||||
if (assignment == null) return false;
|
||||
PsiElement parent = assignment.getParent();
|
||||
if (!(parent instanceof PsiExpressionStatement)) return false;
|
||||
PsiField field = getAssignedField(assignment);
|
||||
if (field == null || field.hasInitializer()) return false;
|
||||
PsiClass psiClass = field.getContainingClass();
|
||||
|
||||
if (psiClass == null || psiClass.isInterface()) return false;
|
||||
if (psiClass.getContainingFile() != file) return false;
|
||||
PsiModifierListOwner ctrOrInitializer = enclosingMethodOrClassInitializer(assignment, field);
|
||||
if (ctrOrInitializer == null) return false;
|
||||
if (ctrOrInitializer.hasModifierProperty(PsiModifier.STATIC) != field.hasModifierProperty(PsiModifier.STATIC)) return false;
|
||||
|
||||
if (!isValidAsFieldInitializer(assignment.getRExpression(), ctrOrInitializer)) return false;
|
||||
if (!isInitializedWithSameExpression(field, assignment, new ArrayList<>())) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isValidAsFieldInitializer(final PsiExpression initializer, final PsiModifierListOwner ctrOrInitializer) {
|
||||
if (initializer == null) return false;
|
||||
final Ref<Boolean> result = new Ref<>(Boolean.TRUE);
|
||||
initializer.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
PsiElement resolved = expression.resolve();
|
||||
if (resolved == null) return;
|
||||
if (PsiTreeUtil.isAncestor(ctrOrInitializer, resolved, false) && !PsiTreeUtil.isAncestor(initializer, resolved, false)) {
|
||||
// resolved somewhere inside constructor but outside initializer
|
||||
result.set(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result.get().booleanValue();
|
||||
}
|
||||
|
||||
private static PsiModifierListOwner enclosingMethodOrClassInitializer(final PsiAssignmentExpression assignment, final PsiField field) {
|
||||
PsiElement parentOwner = assignment;
|
||||
while (true) {
|
||||
parentOwner = PsiTreeUtil.getParentOfType(parentOwner, PsiModifierListOwner.class, true, PsiMember.class);
|
||||
if (parentOwner == null) return null;
|
||||
PsiElement parent = parentOwner.getParent();
|
||||
|
||||
if (parent == field.getContainingClass()) return (PsiModifierListOwner)parentOwner;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInitializedWithSameExpression(final PsiField field,
|
||||
final PsiAssignmentExpression assignment,
|
||||
final Collection<PsiAssignmentExpression> initializingAssignments) {
|
||||
final PsiExpression expression = assignment.getRExpression();
|
||||
if (expression == null) return false;
|
||||
PsiClass containingClass = field.getContainingClass();
|
||||
if (containingClass == null) return false;
|
||||
|
||||
final Ref<Boolean> result = new Ref<>(Boolean.TRUE);
|
||||
final List<PsiAssignmentExpression> totalUsages = new ArrayList<>();
|
||||
containingClass.accept(new JavaRecursiveElementVisitor() {
|
||||
private PsiCodeBlock currentInitializingBlock; //ctr or class initializer
|
||||
|
||||
@Override
|
||||
public void visitCodeBlock(PsiCodeBlock block) {
|
||||
PsiElement parent = block.getParent();
|
||||
if (parent instanceof PsiClassInitializer || parent instanceof PsiMethod && ((PsiMethod)parent).isConstructor()) {
|
||||
currentInitializingBlock = block;
|
||||
super.visitCodeBlock(block);
|
||||
currentInitializingBlock = null;
|
||||
}
|
||||
else {
|
||||
super.visitCodeBlock(block);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression reference) {
|
||||
if (!result.get().booleanValue()) return;
|
||||
super.visitReferenceExpression(reference);
|
||||
if (!PsiUtil.isOnAssignmentLeftHand(reference)) return;
|
||||
PsiElement resolved = reference.resolve();
|
||||
if (resolved != field) return;
|
||||
PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(reference, PsiAssignmentExpression.class);
|
||||
PsiExpression rValue = assignmentExpression.getRExpression();
|
||||
if (currentInitializingBlock != null) {
|
||||
// ignore usages other than initializing
|
||||
if (rValue == null || !PsiEquivalenceUtil.areElementsEquivalent(rValue, expression)) {
|
||||
result.set(Boolean.FALSE);
|
||||
}
|
||||
initializingAssignments.add(assignmentExpression);
|
||||
}
|
||||
totalUsages.add(assignment);
|
||||
}
|
||||
});
|
||||
// the only assignment is OK
|
||||
if (totalUsages.size() == 1 && initializingAssignments.isEmpty()) {
|
||||
initializingAssignments.addAll(totalUsages);
|
||||
return true;
|
||||
}
|
||||
return result.get().booleanValue();
|
||||
}
|
||||
|
||||
private static PsiField getAssignedField(final PsiAssignmentExpression assignment) {
|
||||
PsiExpression lExpression = PsiUtil.skipParenthesizedExprDown(assignment.getLExpression());
|
||||
if (!(lExpression instanceof PsiReferenceExpression)) return null;
|
||||
PsiElement resolved = ((PsiReferenceExpression)lExpression).resolve();
|
||||
if (!(resolved instanceof PsiField)) return null;
|
||||
return (PsiField)resolved;
|
||||
}
|
||||
|
||||
private static PsiAssignmentExpression getAssignmentUnderCaret(final Editor editor, final PsiFile file) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
PsiElement element = file.findElementAt(offset);
|
||||
if (element == null || element instanceof PsiCompiledElement) return null;
|
||||
return PsiTreeUtil.getParentOfType(element, PsiAssignmentExpression.class, false, PsiMember.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
PsiAssignmentExpression assignment = getAssignmentUnderCaret(editor, file);
|
||||
if (assignment == null) return;
|
||||
PsiField field = getAssignedField(assignment);
|
||||
if (field == null) return;
|
||||
|
||||
List<PsiAssignmentExpression> assignments = new ArrayList<>();
|
||||
if (!isInitializedWithSameExpression(field, assignment, assignments)) return;
|
||||
PsiExpression initializer = assignment.getRExpression();
|
||||
field.setInitializer(initializer);
|
||||
|
||||
for (PsiAssignmentExpression assignmentExpression : assignments) {
|
||||
PsiElement statement = assignmentExpression.getParent();
|
||||
PsiElement parent = statement.getParent();
|
||||
if (parent instanceof PsiIfStatement ||
|
||||
parent instanceof PsiWhileStatement ||
|
||||
parent instanceof PsiForStatement ||
|
||||
parent instanceof PsiForeachStatement) {
|
||||
PsiStatement emptyStatement =
|
||||
JavaPsiFacade.getInstance(file.getProject()).getElementFactory().createStatementFromText(";", statement);
|
||||
statement.replace(emptyStatement);
|
||||
}
|
||||
else {
|
||||
statement.delete();
|
||||
}
|
||||
}
|
||||
|
||||
TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
|
||||
HighlightManager.getInstance(project).addOccurrenceHighlights(editor, new PsiElement[]{field.getInitializer()}, attributes, false, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.ConstructionUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
public class MoveFieldAssignmentToInitializerInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitAssignmentExpression(PsiAssignmentExpression assignment) {
|
||||
PsiElement parent = assignment.getParent();
|
||||
if (!(parent instanceof PsiExpressionStatement)) return;
|
||||
PsiField field = getAssignedField(assignment);
|
||||
if (field == null || field.hasInitializer()) return;
|
||||
PsiClass psiClass = field.getContainingClass();
|
||||
|
||||
if (psiClass == null || psiClass.isInterface()) return;
|
||||
if (psiClass.getContainingFile() != holder.getFile()) return;
|
||||
PsiModifierListOwner ctrOrInitializer = enclosingMethodOrClassInitializer(assignment, field);
|
||||
if (ctrOrInitializer == null) return;
|
||||
if (ctrOrInitializer.hasModifierProperty(PsiModifier.STATIC) != field.hasModifierProperty(PsiModifier.STATIC)) return;
|
||||
|
||||
if (!isValidAsFieldInitializer(assignment.getRExpression(), ctrOrInitializer, field)) return;
|
||||
if (!isInitializedWithSameExpression(field, assignment, new ArrayList<>())) return;
|
||||
|
||||
boolean shouldWarn = shouldWarn(ctrOrInitializer, field, assignment);
|
||||
if (shouldWarn) {
|
||||
PsiExpression lValue = assignment.getLExpression();
|
||||
TextRange range = new TextRange(0, lValue.getTextLength()).shiftRight(lValue.getStartOffsetInParent());
|
||||
holder.registerProblem(assignment, CodeInsightBundle.message("intention.move.field.assignment.to.declaration"),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, range, new MoveFieldAssignmentToInitializerFix());
|
||||
} else {
|
||||
if(!isOnTheFly) return;
|
||||
holder.registerProblem(assignment, CodeInsightBundle.message("intention.move.field.assignment.to.declaration"),
|
||||
ProblemHighlightType.INFORMATION, new MoveFieldAssignmentToInitializerFix());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
boolean shouldWarn(PsiModifierListOwner ctrOrInitializer, PsiField field, PsiAssignmentExpression assignment) {
|
||||
if (!(ctrOrInitializer instanceof PsiClassInitializer)) return false;
|
||||
PsiExpressionStatement statement = ObjectUtils.tryCast(assignment.getParent(), PsiExpressionStatement.class);
|
||||
if (statement == null) return false;
|
||||
PsiCodeBlock codeBlock = ObjectUtils.tryCast(statement.getParent(), PsiCodeBlock.class);
|
||||
if (codeBlock == null) return false;
|
||||
if (codeBlock.getParent() != ctrOrInitializer) return false;
|
||||
if (!ReferencesSearch.search(field, new LocalSearchScope(ctrOrInitializer)).forEach(ref -> {
|
||||
return PsiTreeUtil.isAncestor(assignment, ref.getElement(), true);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
// If it's not the first statement in the initializer, allow some more (likely unrelated) assignments only
|
||||
if (StreamEx.of(codeBlock.getStatements()).takeWhile(st -> statement != st).allMatch(st -> ExpressionUtils.getAssignment(st) != null)) {
|
||||
return true;
|
||||
}
|
||||
// Or allow simple initializers
|
||||
PsiExpression value = assignment.getRExpression();
|
||||
return ExpressionUtils.isSimpleExpression(value) || ConstructionUtils.isEmptyCollectionInitializer(value);
|
||||
}
|
||||
|
||||
private static boolean isValidAsFieldInitializer(final PsiExpression initializer,
|
||||
final PsiModifierListOwner ctrOrInitializer,
|
||||
PsiField field) {
|
||||
if (initializer == null) return false;
|
||||
if (!ExceptionUtil.getThrownCheckedExceptions(initializer).isEmpty()) return false;
|
||||
final Ref<Boolean> result = new Ref<>(Boolean.TRUE);
|
||||
initializer.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
super.visitReferenceExpression(expression);
|
||||
PsiElement resolved = expression.resolve();
|
||||
if (resolved == null) return;
|
||||
if (PsiTreeUtil.isAncestor(ctrOrInitializer, resolved, false) && !PsiTreeUtil.isAncestor(initializer, resolved, false)) {
|
||||
// resolved somewhere inside constructor but outside initializer
|
||||
result.set(Boolean.FALSE);
|
||||
}
|
||||
if (resolved instanceof PsiMember &&
|
||||
resolved != field &&
|
||||
((PsiMember)resolved).getContainingClass() == field.getContainingClass()) {
|
||||
if (field.hasModifierProperty(PsiModifier.STATIC) ||
|
||||
!((PsiMember)resolved).hasModifierProperty(PsiModifier.STATIC)) {
|
||||
// refers to another field/method of the same class (except referring from non-static member to static)
|
||||
result.set(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result.get().booleanValue();
|
||||
}
|
||||
|
||||
static PsiModifierListOwner enclosingMethodOrClassInitializer(final PsiAssignmentExpression assignment, final PsiField field) {
|
||||
PsiElement parentOwner = assignment;
|
||||
while (true) {
|
||||
parentOwner = PsiTreeUtil.getParentOfType(parentOwner, PsiModifierListOwner.class, true, PsiMember.class);
|
||||
if (parentOwner == null) return null;
|
||||
PsiElement parent = parentOwner.getParent();
|
||||
|
||||
if (parent == field.getContainingClass()) return (PsiModifierListOwner)parentOwner;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInitializedWithSameExpression(final PsiField field,
|
||||
final PsiAssignmentExpression assignment,
|
||||
final Collection<PsiAssignmentExpression> initializingAssignments) {
|
||||
final PsiExpression expression = assignment.getRExpression();
|
||||
if (expression == null) return false;
|
||||
PsiClass containingClass = field.getContainingClass();
|
||||
if (containingClass == null) return false;
|
||||
|
||||
final Ref<Boolean> result = new Ref<>(Boolean.TRUE);
|
||||
final List<PsiAssignmentExpression> totalUsages = new ArrayList<>();
|
||||
containingClass.accept(new JavaRecursiveElementVisitor() {
|
||||
private PsiCodeBlock currentInitializingBlock; //ctr or class initializer
|
||||
|
||||
@Override
|
||||
public void visitCodeBlock(PsiCodeBlock block) {
|
||||
PsiElement parent = block.getParent();
|
||||
if (parent instanceof PsiClassInitializer || parent instanceof PsiMethod && ((PsiMethod)parent).isConstructor()) {
|
||||
currentInitializingBlock = block;
|
||||
super.visitCodeBlock(block);
|
||||
currentInitializingBlock = null;
|
||||
}
|
||||
else {
|
||||
super.visitCodeBlock(block);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression reference) {
|
||||
if (!result.get().booleanValue()) return;
|
||||
super.visitReferenceExpression(reference);
|
||||
if (!PsiUtil.isOnAssignmentLeftHand(reference)) return;
|
||||
PsiElement resolved = reference.resolve();
|
||||
if (resolved != field) return;
|
||||
PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(reference, PsiAssignmentExpression.class);
|
||||
if (assignmentExpression == null) return;
|
||||
PsiExpression rValue = assignmentExpression.getRExpression();
|
||||
if (currentInitializingBlock != null) {
|
||||
// ignore usages other than initializing
|
||||
if (rValue == null || !PsiEquivalenceUtil.areElementsEquivalent(rValue, expression)) {
|
||||
result.set(Boolean.FALSE);
|
||||
}
|
||||
initializingAssignments.add(assignmentExpression);
|
||||
}
|
||||
totalUsages.add(assignment);
|
||||
}
|
||||
});
|
||||
// the only assignment is OK
|
||||
if (totalUsages.size() == 1 && initializingAssignments.isEmpty()) {
|
||||
initializingAssignments.addAll(totalUsages);
|
||||
return true;
|
||||
}
|
||||
return result.get().booleanValue();
|
||||
}
|
||||
|
||||
private static PsiField getAssignedField(final PsiAssignmentExpression assignment) {
|
||||
PsiExpression lExpression = PsiUtil.skipParenthesizedExprDown(assignment.getLExpression());
|
||||
if (!(lExpression instanceof PsiReferenceExpression)) return null;
|
||||
PsiElement resolved = ((PsiReferenceExpression)lExpression).resolve();
|
||||
if (!(resolved instanceof PsiField)) return null;
|
||||
return (PsiField)resolved;
|
||||
}
|
||||
|
||||
private static class MoveFieldAssignmentToInitializerFix implements LocalQuickFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return CodeInsightBundle.message("intention.move.field.assignment.to.declaration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiAssignmentExpression assignment = ObjectUtils.tryCast(descriptor.getStartElement(), PsiAssignmentExpression.class);
|
||||
if (assignment == null) return;
|
||||
PsiField field = getAssignedField(assignment);
|
||||
if (field == null) return;
|
||||
|
||||
List<PsiAssignmentExpression> assignments = new ArrayList<>();
|
||||
if (!isInitializedWithSameExpression(field, assignment, assignments)) return;
|
||||
|
||||
PsiElement prev = PsiTreeUtil.skipSiblingsBackward(assignment.getParent(), PsiComment.class, PsiWhiteSpace.class);
|
||||
String comments = prev == null ? null : CommentTracker.commentsBetween(prev, assignment);
|
||||
|
||||
PsiExpression initializer = assignment.getRExpression();
|
||||
field.setInitializer(initializer);
|
||||
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
if (comments != null) {
|
||||
PsiCodeBlock block = factory.createCodeBlockFromText("{" + comments + "}", initializer);
|
||||
for(PsiElement child : block.getChildren()) {
|
||||
if(child instanceof PsiComment || child instanceof PsiWhiteSpace) {
|
||||
field.getParent().addBefore(child, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PsiModifierListOwner owner = enclosingMethodOrClassInitializer(assignment, field);
|
||||
|
||||
for (PsiAssignmentExpression assignmentExpression : assignments) {
|
||||
PsiElement statement = assignmentExpression.getParent();
|
||||
PsiElement parent = statement.getParent();
|
||||
if (parent instanceof PsiIfStatement ||
|
||||
parent instanceof PsiWhileStatement ||
|
||||
parent instanceof PsiForStatement ||
|
||||
parent instanceof PsiForeachStatement) {
|
||||
PsiStatement emptyStatement = factory.createStatementFromText(";", statement);
|
||||
statement.replace(emptyStatement);
|
||||
}
|
||||
else {
|
||||
statement.delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete empty initializer left after fix
|
||||
if (owner instanceof PsiClassInitializer) {
|
||||
PsiCodeBlock body = ((PsiClassInitializer)owner).getBody();
|
||||
if(body.getStatements().length == 0 && Arrays.stream(body.getChildren()).noneMatch(PsiComment.class::isInstance)) {
|
||||
owner.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Move assignment to field declaration" "true"
|
||||
// "Move assignment to field declaration" "INFORMATION"
|
||||
|
||||
class X {
|
||||
int f = 0;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// "Move assignment to field declaration" "true"
|
||||
// "Move assignment to field declaration" "GENERIC_ERROR_OR_WARNING"
|
||||
|
||||
class X {
|
||||
static int f = 0;
|
||||
static {
|
||||
<caret>}
|
||||
X(int i) {
|
||||
/*
|
||||
Set to zero
|
||||
*/
|
||||
static int f = 0;
|
||||
|
||||
X(int i) {
|
||||
}
|
||||
void x() {
|
||||
int i = f;
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
// "Move assignment to field declaration" "true"
|
||||
|
||||
class X {
|
||||
Object f = new Runnable() {
|
||||
void x(int p) {
|
||||
int f = p;
|
||||
}
|
||||
// Create default runnable
|
||||
Object f = new Runnable() {
|
||||
void x(int p) {
|
||||
int f = p;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
public void run() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
X() {
|
||||
<caret>//
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// "Move assignment to field declaration" "INFORMATION"
|
||||
public class Test {
|
||||
static LoggingSystem LOG = LoggingSystem.getLogger();
|
||||
|
||||
static {
|
||||
LoggingSystem.init();
|
||||
}
|
||||
}
|
||||
|
||||
class LoggingSystem {
|
||||
private static LoggingSystem L;
|
||||
|
||||
static LoggingSystem getLogger() {
|
||||
return L;
|
||||
}
|
||||
|
||||
static void init() {
|
||||
if(L == null) {
|
||||
L = new LoggingSystem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// "Move assignment to field declaration" "true"
|
||||
public class X {
|
||||
int i = 0;
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Move assignment to field declaration" "INFORMATION"
|
||||
public class Test {
|
||||
String myField = getValue();
|
||||
private String value;
|
||||
|
||||
void f() {
|
||||
}
|
||||
|
||||
public static String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Move assignment to field declaration" "true"
|
||||
// "Move assignment to field declaration" "INFORMATION"
|
||||
|
||||
class X {
|
||||
int f;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// "Move assignment to field declaration" "true"
|
||||
// "Move assignment to field declaration" "GENERIC_ERROR_OR_WARNING"
|
||||
|
||||
class X {
|
||||
static int f;
|
||||
static {
|
||||
f = <caret>0;
|
||||
/*
|
||||
Set to zero
|
||||
*/
|
||||
<caret>f = 0;
|
||||
}
|
||||
X(int i) {
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class X {
|
||||
Object f;
|
||||
X() {
|
||||
// Create default runnable
|
||||
<caret>f = new Runnable() {
|
||||
void x(int p) {
|
||||
int f = p;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// "Move assignment to field declaration" "INFORMATION"
|
||||
public class Test {
|
||||
static LoggingSystem LOG;
|
||||
|
||||
static {
|
||||
LoggingSystem.init();
|
||||
<caret>LOG = LoggingSystem.getLogger();
|
||||
}
|
||||
}
|
||||
|
||||
class LoggingSystem {
|
||||
private static LoggingSystem L;
|
||||
|
||||
static LoggingSystem getLogger() {
|
||||
return L;
|
||||
}
|
||||
|
||||
static void init() {
|
||||
if(L == null) {
|
||||
L = new LoggingSystem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Move assignment to field declaration" "false"
|
||||
public class Test {
|
||||
String myField;
|
||||
private String value;
|
||||
|
||||
void f() {
|
||||
<caret>myField = getValue();
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,6 @@
|
||||
public class X {
|
||||
int i;
|
||||
{
|
||||
(i)=<caret>0;
|
||||
(<caret>i)=0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Move assignment to field declaration" "false"
|
||||
public class Test {
|
||||
final static String FIELD;
|
||||
static {
|
||||
String data = " foo ";
|
||||
<caret>FIELD = data.trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Move assignment to field declaration" "INFORMATION"
|
||||
public class Test {
|
||||
String myField;
|
||||
private String value;
|
||||
|
||||
void f() {
|
||||
<caret>myField = getValue();
|
||||
}
|
||||
|
||||
public static String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.MoveFieldAssignmentToInitializerInspection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
public class MoveFieldAssignmentToInitializerInspectionTest extends LightQuickFixParameterizedTestCase {
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new MoveFieldAssignmentToInitializerInspection()};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/moveFieldAssignmentToInitializer";
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.intellij.codeInsight.intention;
|
||||
|
||||
import com.intellij.codeInsight.daemon.LightIntentionActionTestCase;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class MoveFieldAssignmentToInitializerActionTest extends LightIntentionActionTestCase {
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/moveFieldAssignmentToInitializer";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>This intention replaces initialization of field via assignment with field initializer.</p>
|
||||
<p>The code is highlighted only if field initializer is located in the initializer
|
||||
and joining with the field declaration is likely to be safe.</p>
|
||||
<p>In other cases the inspection works like intention action as it may change the code semantics.</p>
|
||||
<!-- tooltip end -->
|
||||
<small>Since 2017.2</small>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +0,0 @@
|
||||
public class X {
|
||||
int field = 0;
|
||||
public X() {
|
||||
|
||||
}
|
||||
void reset() {
|
||||
field = -1;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
public class X {
|
||||
int field;
|
||||
public X() {
|
||||
<spot>field = 0;</spot>
|
||||
}
|
||||
void reset() {
|
||||
field = -1;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
This intention replaces intialization of field via assignment with field initializer.
|
||||
<p>
|
||||
Please note that this intention may change program semantics.
|
||||
</body>
|
||||
</html>
|
||||
@@ -920,6 +920,10 @@
|
||||
groupPath="Java" groupBundle="messages.InspectionsBundle" groupKey="group.names.reflective.access.issues"
|
||||
bundle="messages.InspectionsBundle" key="inspection.handle.signature.name"
|
||||
implementationClass="com.intellij.codeInspection.reflectiveAccess.JavaLangInvokeHandleSignatureInspection"/>
|
||||
<localInspection language="JAVA" shortName="MoveFieldAssignmentToInitializer" enabledByDefault="true" level="WARNING"
|
||||
groupPath="Java" groupBundle="messages.InspectionsBundle" groupKey="group.names.code.style.issues"
|
||||
displayName="Move field assignment to initializer"
|
||||
implementationClass="com.intellij.codeInspection.MoveFieldAssignmentToInitializerInspection"/>
|
||||
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.SplitIfAction</className>
|
||||
@@ -1068,10 +1072,6 @@
|
||||
<className>com.intellij.testIntegration.intention.MoveInitializerToSetUpMethodAction</className>
|
||||
<category>Java/Declaration</category>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.MoveFieldAssignmentToInitializerAction</className>
|
||||
<category>Java/Declaration</category>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.daemon.impl.quickfix.AddRuntimeExceptionToThrowsAction</className>
|
||||
<category>Java/Declaration</category>
|
||||
|
||||
Reference in New Issue
Block a user