IG: merge two inspections and enable at INFORMATION level (IDEA-30715)

merging "Multiple variables in one declaration" and "Multiple typed variables in one declaration" inspections
This commit is contained in:
Bas Leijdekkers
2019-04-02 19:55:05 +02:00
parent 5af7c99c9a
commit fc1cc50ff9
27 changed files with 364 additions and 474 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2018 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.
// 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.intellij.codeInsight.intention.impl;
import com.intellij.codeInsight.CodeInsightBundle;
@@ -12,7 +12,6 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.source.tree.Factory;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
@@ -32,100 +31,66 @@ public class SplitDeclarationAction extends PsiElementBaseIntentionAction {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
if (element instanceof PsiCompiledElement) return false;
if (!canModify(element)) return false;
if (!element.getLanguage().isKindOf(JavaLanguage.INSTANCE)) return false;
final PsiElement context = PsiTreeUtil.getParentOfType(element, PsiDeclarationStatement.class, PsiClass.class);
if (context instanceof PsiDeclarationStatement) {
return isAvailableOnDeclarationStatement((PsiDeclarationStatement)context, element);
return isAvailableOnDeclarationStatement((PsiDeclarationStatement)context);
}
PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class);
if (field != null && PsiTreeUtil.getParentOfType(element, PsiDocComment.class) == null && isAvailableOnField(field)) {
setText(CodeInsightBundle.message("intention.split.declaration.text"));
return true;
}
return false;
}
private static boolean isAvailableOnField(PsiField field) {
final PsiTypeElement typeElement = field.getTypeElement();
if (typeElement == null) return false;
if (PsiTreeUtil.getParentOfType(typeElement, PsiField.class) != field) return true;
PsiElement nextField = field.getNextSibling();
while (nextField != null && !(nextField instanceof PsiField)) nextField = nextField.getNextSibling();
if (nextField != null && ((PsiField)nextField).getTypeElement() == typeElement) return true;
return false;
}
private boolean isAvailableOnDeclarationStatement(PsiDeclarationStatement decl, PsiElement element) {
private boolean isAvailableOnDeclarationStatement(PsiDeclarationStatement decl) {
PsiElement[] declaredElements = decl.getDeclaredElements();
if (declaredElements.length == 0) return false;
if (declaredElements.length != 1) return false;
if (!(declaredElements[0] instanceof PsiLocalVariable)) return false;
if (declaredElements.length == 1) {
PsiLocalVariable var = (PsiLocalVariable)declaredElements[0];
if (var.getInitializer() == null) return false;
if (var.getTypeElement().isInferredType() && !PsiTypesUtil.isDenotableType(var.getType(), var)) {
PsiLocalVariable var = (PsiLocalVariable)declaredElements[0];
if (var.getInitializer() == null) return false;
if (var.getTypeElement().isInferredType() && !PsiTypesUtil.isDenotableType(var.getType(), var)) {
return false;
}
PsiElement parent = decl.getParent();
if (parent instanceof PsiForStatement) {
String varName = var.getName();
if (varName == null) {
return false;
}
PsiElement parent = decl.getParent();
if (parent instanceof PsiForStatement) {
String varName = var.getName();
if (varName == null) {
}
parent = parent.getNextSibling();
while (parent != null) {
Ref<Boolean> conflictFound = new Ref<>(false);
parent.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitClass(PsiClass aClass) { }
@Override
public void visitVariable(PsiVariable variable) {
super.visitVariable(variable);
if (varName.equals(variable.getName())) {
conflictFound.set(true);
stopWalking();
}
}
});
if (conflictFound.get()) {
return false;
}
parent = parent.getNextSibling();
while (parent != null) {
Ref<Boolean> conflictFound = new Ref<>(false);
parent.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitClass(PsiClass aClass) { }
@Override
public void visitVariable(PsiVariable variable) {
super.visitVariable(variable);
if (varName.equals(variable.getName())) {
conflictFound.set(true);
stopWalking();
}
}
});
if (conflictFound.get()) {
return false;
}
parent = parent.getNextSibling();
}
}
setText(CodeInsightBundle.message("intention.split.declaration.assignment.text"));
return true;
}
else {
if (decl.getParent() instanceof PsiForStatement) return false;
setText(CodeInsightBundle.message("intention.split.declaration.text"));
return true;
}
setText(CodeInsightBundle.message("intention.split.declaration.assignment.text"));
return true;
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
final PsiDeclarationStatement decl = PsiTreeUtil.getParentOfType(element, PsiDeclarationStatement.class);
final PsiManager psiManager = PsiManager.getInstance(project);
if (decl != null) {
invokeOnDeclarationStatement(decl, psiManager, project);
}
else {
PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class);
if (field != null) {
field.normalizeDeclaration();
}
invokeOnDeclarationStatement(decl, PsiManager.getInstance(project), project);
}
}
@@ -1,7 +1,6 @@
<html>
<body>
This intention converts a local variable declaration with an initializer into separate variable declaration and variable assignment
Converts a local variable declaration with an initializer into separate variable declaration and assignment
statements.
For multiple declarations in one statement, intention splits them into separate declarations
</body>
</html>
@@ -143,7 +143,7 @@ public abstract class InspectionElementsMergerBase extends InspectionElementsMer
private void copyDefaultSettings(@NotNull Element targetElement, @NotNull Map<String, Element> inspectionElements, @NotNull String sourceToolName) {
Element oldElement = getSourceElement(inspectionElements, sourceToolName);
if (oldElement != null) {
Element defaultElement = wrapElement(sourceToolName, oldElement, targetElement);
Element defaultElement = transformElement(sourceToolName, oldElement, targetElement);
oldElement.getChildren().stream()
.filter(child -> !"scope".equals(child.getName()))
.forEach(child -> defaultElement.addContent(child.clone()));
@@ -159,7 +159,7 @@ public abstract class InspectionElementsMergerBase extends InspectionElementsMer
@NotNull Element toolElement,
@NotNull Map<String, Element> scopes,
@NotNull Map<String, Set<String>> mentionedTools) {
Element wrapElement = wrapElement(sourceToolName, sourceElement, toolElement);
Element wrapElement = transformElement(sourceToolName, sourceElement, toolElement);
for (Element element : sourceElement.getChildren()) {
if ("scope".equals(element.getName())) {
String scopeName = element.getAttributeValue("name");
@@ -179,13 +179,13 @@ public abstract class InspectionElementsMergerBase extends InspectionElementsMer
}
private void copyScopeContent(@NotNull String sourceToolName, @NotNull Element element, @NotNull Element scopeElement) {
Element wrappedScope = wrapElement(sourceToolName, element, scopeElement);
Element wrappedScope = transformElement(sourceToolName, element, scopeElement);
for (Element scopeEl : element.getChildren()) {
wrappedScope.addContent(scopeEl.clone());
}
}
protected Element wrapElement(@NotNull String sourceToolName, @NotNull Element sourceElement, @NotNull Element toolElement) {
protected Element transformElement(@NotNull String sourceToolName, @NotNull Element sourceElement, @NotNull Element toolElement) {
return toolElement;
}
}
@@ -1,6 +1,4 @@
// Copyright 2000-2017 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.
// 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.intellij.codeInspection.naming;
import com.intellij.codeInspection.ex.InspectionElementsMergerBase;
@@ -45,7 +43,7 @@ public abstract class AbstractNamingConventionMerger<T extends PsiNameIdentifier
}
@Override
protected Element wrapElement(@NotNull String sourceToolName, @NotNull Element sourceElement, @NotNull Element toolElement) {
protected Element transformElement(@NotNull String sourceToolName, @NotNull Element sourceElement, @NotNull Element toolElement) {
Element element = new Element("extension").setAttribute("name", sourceToolName);
element.setAttribute("enabled", ObjectUtils.notNull(sourceElement.getAttributeValue("enabled"), "false"));
toolElement.addContent(element);
@@ -165,8 +165,7 @@ i18nize.dialog.property.file.chooser.title=Choose Properties File
i18nize.dialog.template.link.label=Edit I18n template
i18nize.dialog.error.property.already.defined.message=Property ''{0}'' already exists in the file ''{1}''. Override its value?
i18nize.dialog.error.property.already.defined.title=Property Already Exists
intention.split.declaration.family=Split Declaration
intention.split.declaration.text=Split into separate declarations
intention.split.declaration.family=Split declaration
intention.split.declaration.assignment.text=Split into declaration and assignment
intention.split.if.family=Split 'if'
intention.split.if.text=Split into 2 if's
@@ -1,18 +1,4 @@
/*
* 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.
*/
// 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;
import com.intellij.CommonBundle;
@@ -598,7 +598,6 @@ unnecessary.temporary.on.conversion.to.string.display.name=Unnecessary temporary
unnecessary.continue.display.name=Unnecessary 'continue' statement
inner.class.on.interface.display.name=Inner class of interface
unused.label.display.name=Unused label
multiple.typed.declaration.display.name=Variables of different types in one declaration
overly.complex.boolean.expression.display.name=Overly complex boolean expression
continue.statement.with.label.display.name='continue' statement with label
class.loader.instantiation.display.name=ClassLoader instantiation
@@ -988,7 +987,7 @@ missorted.modifiers.problem.descriptor=Missorted modifiers <code>#ref</code> #lo
cstyle.array.variable.declaration.problem.descriptor=C-style array declaration of {0, choice, 1#field|2#parameter|3#local variable} <code>#ref</code> #loc
cstyle.array.method.declaration.problem.descriptor=C-style array declaration of the return type of method <code>#ref()</code>#loc
multiple.declaration.problem.descriptor=Multiple variables in one declaration #loc
multiple.typed.declaration.problem.descriptor=Variables of different types in one declaration #loc
multiple.typed.declaration.problem.descriptor=Variables with different array dimension in one declaration #loc
serializable.inner.class.has.serial.version.uid.field.problem.descriptor=Inner class <code>#ref</code> does not define a 'serialVersionUID' field #loc
serializable.inner.class.with.non.serializable.outer.class.problem.descriptor=Inner class <code>#ref</code> is serializable while its outer class is not #loc
busy.wait.problem.descriptor=Call to <code>Thread.#ref()</code> in a loop, probably busy-waiting #loc
@@ -1185,7 +1184,7 @@ make.initialization.explicit.quickfix=Make initialization explicit
move.anonymous.to.inner.quickfix=Convert to named inner class
anonymous.inner.may.be.named.static.inner.class.quickfix=Convert to named 'static' inner class
move.class.quickfix=Move class
normalize.declaration.quickfix=Split into multiple declarations
normalize.declaration.quickfix=Split into separate declarations
remove.modifier.quickfix=Remove ''{0}'' modifier
replace.inheritance.with.delegation.quickfix=Replace inheritance with delegation
big.decimal.equals.replace.quickfix=Replace with 'compareTo()==0'
@@ -1774,6 +1773,7 @@ cast.conflicts.with.instanceof.quickfix2=Replace ''{0}'' with ''{1}'' in instanc
double.checked.locking.quickfix=Make ''{0}'' volatile
double.literal.may.be.float.literal.display.name='double' literal cast to 'float' could be 'float' literal
multiple.declaration.option=Ignore 'for' loop declarations
multiple.declaration.array.only.option=Only warn on different array dimensions in a single declaration
simplifiable.annotation.display.name=Simplifiable annotation
simplifiable.annotation.problem.descriptor=Unnecessary <code>#ref</code> in annotation #loc
simplifiable.annotation.whitespace.problem.descriptor=Unnecessary whitespace in annotation #loc
@@ -45,16 +45,18 @@ public class NormalizeDeclarationFix extends InspectionGadgetsFix {
@Override
public void doFix(Project project, ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (!(element instanceof PsiVariable) && !(element instanceof PsiMethod)) {
if (!(element instanceof PsiVariable) && !(element instanceof PsiMethod) && !(element instanceof PsiDeclarationStatement)) {
element = element.getParent();
}
if (element instanceof PsiLocalVariable) {
final PsiElement parent = element.getParent();
if (!(parent instanceof PsiDeclarationStatement)) {
element = element.getParent();
if (!(element instanceof PsiDeclarationStatement)) {
return;
}
PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)parent;
final PsiElement grandParent = parent.getParent();
}
if (element instanceof PsiDeclarationStatement) {
PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)element;
final PsiElement grandParent = element.getParent();
if (grandParent instanceof PsiForStatement) {
splitMultipleDeclarationInForStatementInitialization(declarationStatement);
return;
@@ -1,122 +0,0 @@
/*
* Copyright 2003-2010 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.
* 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.siyeh.ig.style;
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.psi.*;
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 javax.swing.*;
public class MultipleDeclarationInspection extends BaseInspection {
@SuppressWarnings({"PublicField"})
public boolean ignoreForLoopDeclarations = true;
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"multiple.declaration.display.name");
}
@Override
@NotNull
public String getID() {
return "MultipleVariablesInDeclaration";
}
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"multiple.declaration.problem.descriptor");
}
@Override
public JComponent createOptionsPanel() {
return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message(
"multiple.declaration.option"),
this, "ignoreForLoopDeclarations");
}
@Override
public InspectionGadgetsFix buildFix(Object... infos) {
return new NormalizeDeclarationFix();
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new MultipleDeclarationVisitor();
}
private class MultipleDeclarationVisitor
extends BaseInspectionVisitor {
@Override
public void visitDeclarationStatement(
PsiDeclarationStatement statement) {
super.visitDeclarationStatement(statement);
if (statement.getDeclaredElements().length <= 1) {
return;
}
final PsiElement parent = statement.getParent();
if (ignoreForLoopDeclarations &&
parent instanceof PsiForStatement) {
return;
}
final PsiElement[] declaredElements =
statement.getDeclaredElements();
for (int i = 1; i < declaredElements.length; i++) {
//skip the first one;
final PsiElement declaredElement = declaredElements[i];
if (!(declaredElement instanceof PsiVariable)) {
continue;
}
final PsiVariable variable =
(PsiVariable)declaredElement;
registerVariableError(variable);
}
}
@Override
public void visitField(@NotNull PsiField field) {
super.visitField(field);
if (childrenContainTypeElement(field)) {
return;
}
if (field instanceof PsiEnumConstant) {
return;
}
registerFieldError(field);
}
public boolean childrenContainTypeElement(PsiElement field) {
final PsiElement[] children = field.getChildren();
for (PsiElement aChildren : children) {
if (aChildren instanceof PsiTypeElement) {
return true;
}
}
return false;
}
}
}
@@ -1,150 +0,0 @@
/*
* Copyright 2003-2008 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.
* 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.siyeh.ig.style;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
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 java.util.ArrayList;
import java.util.List;
public class MultipleTypedDeclarationInspection extends BaseInspection {
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"multiple.typed.declaration.display.name");
}
@Override
@NotNull
public String getID() {
return "VariablesOfDifferentTypesInDeclaration";
}
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"multiple.typed.declaration.problem.descriptor");
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new MultiplyTypedDeclarationVisitor();
}
@Override
public InspectionGadgetsFix buildFix(Object... infos) {
return new NormalizeDeclarationFix();
}
private static class MultiplyTypedDeclarationVisitor
extends BaseInspectionVisitor {
@Override
public void visitDeclarationStatement(
PsiDeclarationStatement statement) {
super.visitDeclarationStatement(statement);
final PsiElement[] elements = statement.getDeclaredElements();
if (elements.length > 1) {
final PsiType baseType = ((PsiVariable)elements[0]).getType();
boolean hasMultipleTypes = false;
for (int i = 1; i < elements.length; i++) {
final PsiLocalVariable var = (PsiLocalVariable)elements[i];
final PsiType variableType = var.getType();
if (!variableType.equals(baseType)) {
hasMultipleTypes = true;
}
}
if (hasMultipleTypes) {
for (int i = 1; i < elements.length; i++) {
final PsiLocalVariable var =
(PsiLocalVariable)elements[i];
registerVariableError(var);
}
}
}
}
@Override
public void visitField(@NotNull PsiField field) {
super.visitField(field);
if (!childrenContainTypeElement(field)) {
return;
}
final List<PsiField> fields = getSiblingFields(field);
if (fields.size() > 1) {
final PsiField firstField = fields.get(0);
final PsiType baseType = firstField.getType();
boolean hasMultipleTypes = false;
for (int i = 1; i < fields.size(); i++) {
final PsiField variable = fields.get(i);
final PsiType variableType = variable.getType();
if (!variableType.equals(baseType)) {
hasMultipleTypes = true;
}
}
if (hasMultipleTypes) {
for (int i = 1; i < fields.size(); i++) {
final PsiField var = fields.get(i);
registerVariableError(var);
}
}
}
}
public static List<PsiField> getSiblingFields(PsiField field) {
final List<PsiField> out = new ArrayList<>(5);
out.add(field);
PsiField nextField =
PsiTreeUtil.getNextSiblingOfType(field,
PsiField.class);
if (nextField != null) {
PsiTypeElement nextTypeElement = nextField.getTypeElement();
while (nextTypeElement != null &&
nextTypeElement.equals(field.getTypeElement())) {
out.add(nextField);
nextField =
PsiTreeUtil.getNextSiblingOfType(nextField,
PsiField.class);
if (nextField == null) {
break;
}
nextTypeElement = nextField.getTypeElement();
}
}
return out;
}
public static boolean childrenContainTypeElement(PsiElement field) {
final PsiElement[] children = field.getChildren();
for (PsiElement aChildren : children) {
if (aChildren instanceof PsiTypeElement) {
return true;
}
}
return false;
}
}
}
@@ -0,0 +1,143 @@
// 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.style;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
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 com.siyeh.ig.psiutils.DeclarationSearchUtils;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class MultipleVariablesInDeclarationInspection extends BaseInspection {
@SuppressWarnings("PublicField")
public boolean ignoreForLoopDeclarations = true;
@SuppressWarnings("PublicField")
public boolean onlyWarnArrayDimensions = false;
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message("multiple.declaration.display.name");
}
@Override
@NotNull
public String getID() {
return "MultipleVariablesInDeclaration";
}
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return onlyWarnArrayDimensions
? InspectionGadgetsBundle.message("multiple.typed.declaration.problem.descriptor")
: InspectionGadgetsBundle.message("multiple.declaration.problem.descriptor");
}
@Override
public JComponent createOptionsPanel() {
MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this);
panel.addCheckbox(InspectionGadgetsBundle.message("multiple.declaration.option"), "ignoreForLoopDeclarations");
panel.addCheckbox(InspectionGadgetsBundle.message("multiple.declaration.array.only.option"), "onlyWarnArrayDimensions");
return panel;
}
@Override
public InspectionGadgetsFix buildFix(Object... infos) {
return new NormalizeDeclarationFix(false);
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new MultipleDeclarationVisitor();
}
private class MultipleDeclarationVisitor extends BaseInspectionVisitor {
@Override
public void visitDeclarationStatement(PsiDeclarationStatement statement) {
super.visitDeclarationStatement(statement);
final PsiElement[] declaredElements = statement.getDeclaredElements();
if (declaredElements.length < 2) {
return;
}
final PsiElement parent = statement.getParent();
final ProblemHighlightType highlightType;
if (ignoreForLoopDeclarations && parent instanceof PsiForStatement) {
highlightType = ProblemHighlightType.INFORMATION;
}
else if (onlyWarnArrayDimensions) {
PsiVariable variable = (PsiVariable)declaredElements[0];
final PsiType baseType = variable.getType();
boolean hasMultipleTypes = false;
for (int i = 1; i < declaredElements.length; i++) {
final PsiType variableType = ((PsiLocalVariable)declaredElements[i]).getType();
if (!variableType.equals(baseType)) {
hasMultipleTypes = true;
}
}
highlightType = !hasMultipleTypes ? ProblemHighlightType.INFORMATION : ProblemHighlightType.WARNING;
}
else {
highlightType = ProblemHighlightType.WARNING;
}
if (highlightType == ProblemHighlightType.INFORMATION
|| InspectionProjectProfileManager.isInformationLevel(getShortName(), statement)) {
registerError(statement, highlightType);
}
else {
final PsiElement nameIdentifier = ((PsiVariable)declaredElements[0]).getNameIdentifier();
if (nameIdentifier == null) {
return;
}
registerError(nameIdentifier, highlightType);
}
}
@Override
public void visitField(@NotNull PsiField field) {
super.visitField(field);
if (field instanceof PsiEnumConstant) {
return;
}
if (DeclarationSearchUtils.findFirstFieldInDeclaration(field) != field) {
if (InspectionProjectProfileManager.isInformationLevel(getShortName(), field)) {
registerError(field);
}
return;
}
else if (DeclarationSearchUtils.findNextFieldInDeclaration(field) == null) {
return;
}
final boolean informationLevel = InspectionProjectProfileManager.isInformationLevel(getShortName(), field);
final ProblemHighlightType highlightType;
if (onlyWarnArrayDimensions) {
if (!informationLevel) {
PsiField nextField = DeclarationSearchUtils.findNextFieldInDeclaration(field);
final PsiType baseType = field.getType();
while (nextField != null) {
if (!baseType.equals(nextField.getType())) {
registerVariableError(field);
return;
}
nextField = DeclarationSearchUtils.findNextFieldInDeclaration(nextField);
}
}
highlightType = ProblemHighlightType.INFORMATION;
}
else {
highlightType = ProblemHighlightType.WARNING;
}
registerError(informationLevel || highlightType == ProblemHighlightType.INFORMATION ? field : field.getNameIdentifier(), highlightType);
}
}
}
@@ -0,0 +1,61 @@
// 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.style;
import com.intellij.codeInspection.ex.InspectionElementsMergerBase;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
/**
* @author Bas Leijdekkers
*/
public class MultipleVariablesInDeclarationInspectionMerger extends InspectionElementsMergerBase {
private static final String MULTIPLE_DECLARATION = "MultipleDeclaration";
private static final String MULTIPLE_TYPED_DECLARATION = "MultipleTypedDeclaration";
@Override
protected boolean isEnabledByDefault(@NotNull String sourceToolName) {
return false;
}
@NotNull
@Override
public String getMergedToolName() {
return "MultipleVariablesInDeclaration";
}
@NotNull
@Override
public String[] getSourceToolNames() {
return new String[] {
MULTIPLE_DECLARATION,
MULTIPLE_TYPED_DECLARATION
};
}
@NotNull
@Override
public String[] getSuppressIds() {
return new String[] {
"VariablesOfDifferentTypesInDeclaration",
"MultipleVariablesInDeclaration"
};
}
/**
* Add settings to merged tool when MULTIPLE_TYPED_DECLARATION is enabled and MULTIPLE_DECLARATION is disabled
*/
@Override
protected Element transformElement(@NotNull String sourceToolName, @NotNull Element sourceElement, @NotNull Element toolElement) {
if (MULTIPLE_DECLARATION.equals(sourceToolName) && Boolean.parseBoolean(sourceElement.getAttributeValue("enabled", "false"))) {
toolElement.setAttribute("enabled", "true");
}
else if (MULTIPLE_TYPED_DECLARATION.equals(sourceToolName)
&& !Boolean.parseBoolean(toolElement.getAttributeValue("enabled", "false"))
&& Boolean.parseBoolean(sourceElement.getAttributeValue("enabled", "false"))) {
toolElement.addContent(new Element("option").setAttribute("name", "ignoreForLoopDeclarations").setAttribute("value", "false"));
toolElement.addContent(new Element("option").setAttribute("name", "onlyWarnArrayDimensions").setAttribute("value", "true"));
}
return toolElement;
}
}
@@ -2292,6 +2292,7 @@
implementationClass="com.siyeh.ig.serialization.TransientFieldNotInitializedInspection"/>
<!--group.names.code.style.issues-->
<inspectionElementsMerger implementation="com.siyeh.ig.style.MultipleVariablesInDeclarationInspectionMerger"/>
<localInspection groupPath="Java" language="JAVA" shortName="AssertMessageNotString" bundle="com.siyeh.InspectionGadgetsBundle"
key="assert.message.not.string.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.code.style.issues"
enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.style.AssertMessageNotStringInspection"/>
@@ -2357,14 +2358,10 @@
<localInspection groupPath="Java" language="JAVA" shortName="MissortedModifiers" bundle="com.siyeh.InspectionGadgetsBundle" key="missorted.modifiers.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.code.style.issues" enabledByDefault="false" cleanupTool="true"
level="WARNING" implementationClass="com.siyeh.ig.style.MissortedModifiersInspection"/>
<localInspection groupPath="Java" language="JAVA" suppressId="MultipleVariablesInDeclaration" shortName="MultipleDeclaration" bundle="com.siyeh.InspectionGadgetsBundle"
<localInspection groupPath="Java" language="JAVA" suppressId="MultipleVariablesInDeclaration" shortName="MultipleVariablesInDeclaration" bundle="com.siyeh.InspectionGadgetsBundle"
key="multiple.declaration.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.code.style.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.style.MultipleDeclarationInspection"/>
<localInspection groupPath="Java" language="JAVA" suppressId="VariablesOfDifferentTypesInDeclaration" shortName="MultipleTypedDeclaration"
bundle="com.siyeh.InspectionGadgetsBundle" key="multiple.typed.declaration.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.code.style.issues" enabledByDefault="false"
level="WARNING" implementationClass="com.siyeh.ig.style.MultipleTypedDeclarationInspection"/>
groupKey="group.names.code.style.issues" enabledByDefault="true" level="INFORMATION"
implementationClass="com.siyeh.ig.style.MultipleVariablesInDeclarationInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="UnnecessaryConstantArrayCreationExpression" bundle="com.siyeh.InspectionGadgetsBundle"
key="unnecessary.constant.array.creation.expression.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.code.style.issues" enabledByDefault="false" level="WARNING" cleanupTool="true"
@@ -1,9 +0,0 @@
<html>
<body>
Reports multiple variables being declared in a single declaration.
Some coding standards prohibit such declarations.
<!-- tooltip end -->
<p>
</body>
</html>
@@ -1,11 +0,0 @@
<html>
<body>
Reports multiple different types of variables being declared in a single declaration. In such a declaration the types
used can only differ in array dimension. Such declarations may be confusing.
<p>For example the following will be reported by this inspection:<br>
<code><pre>String s = "", array[];</pre></code>
<!-- tooltip end -->
<p>
</body>
</html>
@@ -0,0 +1,13 @@
<html>
<body>
Reports multiple variables being declared in a single declaration.
Some coding standards prohibit such declarations.
<!-- tooltip end -->
<p>
Use the first checkbox below to ignore multiple variables declared in the initialization of a 'for' loop statement, e.g.:
<pre><code><b>for</b> (int i = 0, max = list.size(); i < max; i++) {}</code></pre>
<p>
Use the second checkbox below to only warn when variables with different array dimensions are declared in a single declaration, e.g.:
<pre><code>String s = "", array[];</code></pre>
</body>
</html>
@@ -1,5 +1,5 @@
package com.siyeh.igfixes.style.multiple_declaration;
public class SimpleStringBuffer {
int i = 0, j<caret> = 0;
int i<caret> = 0, j = 0;
}
@@ -2,6 +2,6 @@ package com.siyeh.igfixes.style.multiple_declaration;
public class SimpleStringBuffer {
String foo() {
int i = 0, j<caret> = 0;
int i<caret> = 0, j = 0;
}
}
@@ -1,21 +0,0 @@
package com.siyeh.igtest.style;
public class MultipleVariableDeclarationInspection
{
private int foo;
private int m_fooBaz, m_fooBar;
private int m_fooBaz2;
private int m_fooBar2;
public void fooBar()
{
int fooBaz, fooBar;
int fooBaz2;
int fooBar2;
for(int i =0, j=0;i<100;i++,j++)
{
}
}
}
@@ -1,12 +0,0 @@
package com.siyeh.igtest.style;
public class MultipleVariableTypeDeclarationInspection
{
private int m_fooBaz, m_fooBar[];
public void fooBar()
{
int fooBaz, // comment1
fooBar[]; //comment2
}
}
@@ -0,0 +1,21 @@
package com.siyeh.igtest.style;
public class MultipleVariableDeclaration
{
private int foo;
private int <warning descr="Multiple variables in one declaration">m_fooBaz</warning>, m_fooBar;
private int m_fooBaz2;
private int m_fooBar2;
public void fooBar()
{
int <warning descr="Multiple variables in one declaration">fooBaz</warning>, fooBar;
int fooBaz2;
int fooBar2;
for(int <warning descr="Multiple variables in one declaration">i</warning> =0, j=0;i<100;i++,j++)
{
}
}
}
@@ -0,0 +1,14 @@
package com.siyeh.igtest.style;
public class OnlyWarnArrayDimensions
{
private int <warning descr="Variables with different array dimension in one declaration">m_fooBaz</warning>, m_fooBar[];
public void fooBar()
{
int <warning descr="Variables with different array dimension in one declaration">fooBaz</warning>, // comment1
fooBar[]; //comment2
int i,j,k;
}
}
@@ -1,35 +0,0 @@
/*
* Copyright 2012 Bas Leijdekkers
*
* 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.siyeh.ig.fixes.style;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.IGQuickFixesTestCase;
import com.siyeh.ig.style.MultipleDeclarationInspection;
public class MultipleDeclarationFixTest extends IGQuickFixesTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
myFixture.enableInspections(new MultipleDeclarationInspection());
myRelativePath = "style/multiple_declaration";
myDefaultHint = InspectionGadgetsBundle.message("normalize.declaration.quickfix");
}
public void testLocalVariable() { doTest(); }
public void testField() { doTest(); }
}
@@ -0,0 +1,24 @@
// 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;
import com.siyeh.ig.IGQuickFixesTestCase;
import com.siyeh.ig.style.MultipleVariablesInDeclarationInspection;
/**
* @author Bas Leijdekkers
*/
public class MultipleVariablesInDeclarationFixTest extends IGQuickFixesTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
myFixture.enableInspections(new MultipleVariablesInDeclarationInspection());
myRelativePath = "style/multiple_declaration";
myDefaultHint = InspectionGadgetsBundle.message("normalize.declaration.quickfix");
}
public void testLocalVariable() { doTest(); }
public void testField() { doTest(); }
public void testMultipleDeclarationsLocalWithComments() { doTest(); }
}
@@ -0,0 +1,28 @@
// 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.style;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import org.jetbrains.annotations.Nullable;
/**
* @author Bas Leijdekkers
*/
public class MultipleVariablesInDeclarationInspectionTest extends LightInspectionTestCase {
public void testOnlyWarnArrayDimensions() { doTest(); }
public void testMultipleVariableDeclaration() { doTest(); }
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
MultipleVariablesInDeclarationInspection inspection = new MultipleVariablesInDeclarationInspection();
if ("OnlyWarnArrayDimensions".equals(getTestName(false))) {
inspection.onlyWarnArrayDimensions = true;
}
else {
inspection.ignoreForLoopDeclarations = false;
}
return inspection;
}
}