IG: use normalize declaration fix and expand activation area when no highlight

for "C-style array declaration" inspection
This commit is contained in:
Bas Leijdekkers
2019-04-02 19:55:04 +02:00
parent ee16c03546
commit 5af7c99c9a
13 changed files with 169 additions and 118 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2018 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2019 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,59 +18,107 @@ package com.siyeh.ig.fixes;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.JavaSharedImplUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.DeclarationSearchUtils;
import org.jetbrains.annotations.NotNull;
public class NormalizeDeclarationFix extends InspectionGadgetsFix {
private final boolean myCStyleDeclaration;
public NormalizeDeclarationFix(boolean cStyleDeclaration) {
myCStyleDeclaration = cStyleDeclaration;
}
@Override
@NotNull
public String getFamilyName() {
return InspectionGadgetsBundle.message("normalize.declaration.quickfix");
return myCStyleDeclaration
? InspectionGadgetsBundle.message("c.style.array.declaration.replace.quickfix")
: InspectionGadgetsBundle.message("normalize.declaration.quickfix");
}
@Override
public void doFix(Project project, ProblemDescriptor descriptor) {
final PsiElement variableNameElement = descriptor.getPsiElement();
final PsiVariable parent =
(PsiVariable)variableNameElement.getParent();
if (parent == null) {
return;
PsiElement element = descriptor.getPsiElement();
if (!(element instanceof PsiVariable) && !(element instanceof PsiMethod)) {
element = element.getParent();
}
if (parent instanceof PsiField) {
parent.normalizeDeclaration();
return;
if (element instanceof PsiLocalVariable) {
final PsiElement parent = element.getParent();
if (!(parent instanceof PsiDeclarationStatement)) {
return;
}
PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)parent;
final PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiForStatement) {
splitMultipleDeclarationInForStatementInitialization(declarationStatement);
return;
}
final PsiElement[] elements = declarationStatement.getDeclaredElements();
final PsiVariable variable = (PsiVariable)elements[0];
variable.normalizeDeclaration();
for (int i = 1; i < elements.length; i++) {
declarationStatement = PsiTreeUtil.getNextSiblingOfType(declarationStatement, PsiDeclarationStatement.class);
assert declarationStatement != null;
JavaSharedImplUtil.normalizeBrackets((PsiVariable)declarationStatement.getDeclaredElements()[0]);
}
}
final PsiElement grandParent = parent.getParent();
if (!(grandParent instanceof PsiDeclarationStatement)) {
return;
else if (element instanceof PsiField) {
PsiField field = DeclarationSearchUtils.findFirstFieldInDeclaration((PsiField)element);
PsiField nextField = field;
int count = 0;
while (nextField != null) {
count++;
nextField = DeclarationSearchUtils.findNextFieldInDeclaration(nextField);
}
field.normalizeDeclaration();
for (int i = 1; i < count; i++) {
field = PsiTreeUtil.getNextSiblingOfType(field, PsiField.class);
assert field != null;
JavaSharedImplUtil.normalizeBrackets(field);
}
}
final PsiElement greatGrandParent = grandParent.getParent();
if (greatGrandParent instanceof PsiForStatement) {
final PsiDeclarationStatement declarationStatement =
(PsiDeclarationStatement)grandParent;
splitMultipleDeclarationInForStatementInitialization(
declarationStatement);
return;
else if (element instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)element;
final PsiTypeElement returnTypeElement = method.getReturnTypeElement();
if (returnTypeElement == null) {
return;
}
final PsiType returnType = method.getReturnType();
if (returnType == null) {
return;
}
PsiElement child = method.getParameterList();
while (!(child instanceof PsiCodeBlock)) {
final PsiElement elementToDelete = child;
child = child.getNextSibling();
if (elementToDelete instanceof PsiJavaToken) {
final IElementType tokenType = ((PsiJavaToken)elementToDelete).getTokenType();
if (JavaTokenType.LBRACKET.equals(tokenType) || JavaTokenType.RBRACKET.equals(tokenType)) {
elementToDelete.delete();
}
}
}
final PsiTypeElement typeElement = JavaPsiFacade.getElementFactory(project).createTypeElement(returnType);
returnTypeElement.replace(typeElement);
}
parent.normalizeDeclaration();
}
private static void splitMultipleDeclarationInForStatementInitialization(
PsiDeclarationStatement declarationStatement) {
private static void splitMultipleDeclarationInForStatementInitialization(PsiDeclarationStatement declarationStatement) {
final PsiElement forStatement = declarationStatement.getParent();
final PsiElement[] declaredElements =
declarationStatement.getDeclaredElements();
final PsiElement[] declaredElements = declarationStatement.getDeclaredElements();
final Project project = forStatement.getProject();
final PsiElementFactory factory =
JavaPsiFacade.getElementFactory(project);
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final PsiElement greatGreatGrandParent = forStatement.getParent();
final PsiBlockStatement blockStatement;
final PsiCodeBlock codeBlock;
if (!(greatGreatGrandParent instanceof PsiCodeBlock)) {
blockStatement = (PsiBlockStatement)
factory.createStatementFromText("{}", forStatement);
blockStatement = (PsiBlockStatement)factory.createStatementFromText("{}", forStatement);
codeBlock = blockStatement.getCodeBlock();
}
else {
@@ -85,19 +133,14 @@ public class NormalizeDeclarationFix extends InspectionGadgetsFix {
final PsiVariable variable = (PsiVariable)declaredElement;
final PsiType type = variable.getType();
final String typeText = type.getCanonicalText();
final StringBuilder newStatementText =
new StringBuilder(typeText);
newStatementText.append(' ');
newStatementText.append(variable.getName());
final StringBuilder newStatementText = new StringBuilder(typeText);
newStatementText.append(' ').append(variable.getName());
final PsiExpression initializer = variable.getInitializer();
if (initializer != null) {
newStatementText.append('=');
newStatementText.append(initializer.getText());
newStatementText.append('=').append(initializer.getText());
}
newStatementText.append(';');
final PsiStatement newStatement =
factory.createStatementFromText(
newStatementText.toString(), forStatement);
final PsiStatement newStatement = factory.createStatementFromText(newStatementText.toString(), forStatement);
if (codeBlock == null) {
greatGreatGrandParent.addBefore(newStatement, forStatement);
}
@@ -105,12 +148,17 @@ public class NormalizeDeclarationFix extends InspectionGadgetsFix {
codeBlock.add(newStatement);
}
}
for (int i = 1; i < declaredElements.length; i++) {
for (int i = 0; i < declaredElements.length; i++) {
final PsiElement declaredElement = declaredElements[i];
if (!(declaredElement instanceof PsiVariable)) {
continue;
}
declaredElement.delete();
if (i == 0) {
((PsiVariable)declaredElement).normalizeDeclaration();
}
else {
declaredElement.delete();
}
}
if (codeBlock != null) {
codeBlock.add(forStatement);
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2017 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2019 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,16 +30,12 @@ public class DeclarationSearchUtils {
private DeclarationSearchUtils() {}
public static boolean variableNameResolvesToTarget(
@NotNull String variableName, @NotNull PsiVariable target,
@NotNull PsiElement context) {
public static boolean variableNameResolvesToTarget(@NotNull String variableName, @NotNull PsiVariable target,
@NotNull PsiElement context) {
final Project project = context.getProject();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
final PsiResolveHelper resolveHelper = psiFacade.getResolveHelper();
final PsiVariable variable =
resolveHelper.resolveAccessibleReferencedVariable(
variableName, context);
final PsiVariable variable = resolveHelper.resolveAccessibleReferencedVariable(variableName, context);
return target.equals(variable);
}
@@ -98,4 +94,15 @@ public class DeclarationSearchUtils {
}
return cost == PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES;
}
public static PsiField findFirstFieldInDeclaration(PsiField field) {
final PsiTypeElement typeElement = field.getTypeElement();
if (typeElement == null) return field; // e.g. enum constant
return (PsiField)typeElement.getParent();
}
public static PsiField findNextFieldInDeclaration(PsiField field) {
final PsiField nextField = PsiTreeUtil.getNextSiblingOfType(field, PsiField.class);
return nextField != null && field.getTypeElement() == nextField.getTypeElement() ? nextField : null;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2018 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2019 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,16 +16,15 @@
package com.siyeh.ig.style;
import com.intellij.codeInspection.CleanupLocalInspectionTool;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.openapi.project.Project;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.tree.IElementType;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.fixes.NormalizeDeclarationFix;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -61,53 +60,7 @@ public class CStyleArrayDeclarationInspection extends BaseInspection implements
@Override
public InspectionGadgetsFix buildFix(Object... infos) {
return new CStyleArrayDeclarationFix();
}
private static class CStyleArrayDeclarationFix
extends InspectionGadgetsFix {
@Override
@NotNull
public String getFamilyName() {
return InspectionGadgetsBundle.message(
"c.style.array.declaration.replace.quickfix");
}
@Override
public void doFix(Project project, ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement().getParent();
if (element instanceof PsiVariable) {
final PsiVariable variable = (PsiVariable)element;
variable.normalizeDeclaration();
CodeStyleManager.getInstance(project).reformat(variable);
}
else if (element instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)element;
final PsiTypeElement returnTypeElement = method.getReturnTypeElement();
if (returnTypeElement == null) {
return;
}
final PsiType returnType = method.getReturnType();
if (returnType == null) {
return;
}
PsiElement child = method.getParameterList();
while (!(child instanceof PsiCodeBlock)) {
final PsiElement element1 = child;
child = child.getNextSibling();
if (element1 instanceof PsiJavaToken) {
final PsiJavaToken token = (PsiJavaToken)element1;
final IElementType tokenType = token.getTokenType();
if (JavaTokenType.LBRACKET.equals(tokenType) || JavaTokenType.RBRACKET.equals(tokenType)) {
token.delete();
}
}
}
final PsiTypeElement typeElement = JavaPsiFacade.getElementFactory(project).createTypeElement(returnType);
returnTypeElement.replace(typeElement);
}
}
return new NormalizeDeclarationFix(true);
}
@Override
@@ -135,7 +88,12 @@ public class CStyleArrayDeclarationInspection extends BaseInspection implements
if (elementType.equals(declaredType)) {
return;
}
registerVariableError(variable, variable);
if (InspectionProjectProfileManager.isInformationLevel(getShortName(), variable)) {
registerError(variable, variable);
}
else {
registerVariableError(variable, variable);
}
}
@Override
@@ -153,6 +111,24 @@ public class CStyleArrayDeclarationInspection extends BaseInspection implements
if (type.equals(returnType)) {
return;
}
if (InspectionProjectProfileManager.isInformationLevel(getShortName(), method)) {
registerError(typeElement, method);
PsiElement child = method.getParameterList();
PsiJavaToken first = null;
PsiJavaToken last = null;
while (!(child instanceof PsiCodeBlock)) {
if (child instanceof PsiJavaToken) {
PsiJavaToken token = (PsiJavaToken)child;
final IElementType tokenType = token.getTokenType();
if (JavaTokenType.LBRACKET.equals(tokenType) || JavaTokenType.RBRACKET.equals(tokenType)) {
if (first == null) first = token;
last = token;
}
}
child = child.getNextSibling();
}
if (first != null) registerErrorAtRange(first, last, method);
}
registerMethodError(method, method);
}
}
@@ -1,4 +1,4 @@
class FieldWithWhitespace {
String[] s;
String[] s;
}
@@ -0,0 +1,7 @@
class InForLoop {
void x(int i) {
if (true) {
int[] is = {};
for (int[] ii = {0}; i < 10; i++) {}
}
}}
@@ -0,0 +1,4 @@
class InForLoop {
void x(int i) {
if (true) for (int ii[] = {0}, is<caret>[] = {}; i < 10; i++) {}
}}
@@ -0,0 +1,6 @@
class X {
int[] array;
int[][] array2;
int[][][] array3;
}
@@ -0,0 +1,4 @@
class X {
int[] array, array2<caret>[], array3[][];
}
@@ -0,0 +1,6 @@
class X {{
int[] array;
int[][] array2;
int[][][] array3;
}}
@@ -0,0 +1,4 @@
class X {{
int[] array, array2<caret>[], array3[][];
}}
@@ -1,6 +1,6 @@
public class SimpleMethod {
public String[] ohGod(String[] a) {
public String[]/*2*/ ohGod(String[] a)/*1*/ {
return a;
}
}
@@ -1,6 +1,6 @@
public class SimpleMethod {
public String ohGo<caret>d(String[] a)[] {
public String/*2*/ ohGo<caret>d(String[] a)/*1*/[] {
return a;
}
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2014 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.siyeh.ig.fixes.style;
import com.siyeh.InspectionGadgetsBundle;
@@ -26,6 +12,9 @@ public class CStyleArrayDeclarationFixTest extends IGQuickFixesTestCase {
public void testSimpleMethod() { doTest(); }
public void testFieldWithWhitespace() { doTest(); }
public void testInForLoop() { doTest(); }
public void testMultipleVariablesSingleDeclaration() { doTest(); }
public void testMultipleFieldsSingleDeclaration() { doTest(); }
@Override
public void setUp() throws Exception {