blob: fd441ed17a04ff7bf7321248f362baffac681df2 [file] [log] [blame]
/*
* 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.
*/
package com.intellij.codeInspection.defUse;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.*;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.DefUseUtil;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
public class DefUseInspectionBase extends BaseJavaBatchLocalInspectionTool {
public boolean REPORT_PREFIX_EXPRESSIONS = false;
public boolean REPORT_POSTFIX_EXPRESSIONS = true;
public boolean REPORT_REDUNDANT_INITIALIZER = true;
public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.unused.assignment.display.name");
@NonNls public static final String SHORT_NAME = "UnusedAssignment";
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override public void visitMethod(PsiMethod method) {
checkCodeBlock(method.getBody(), holder, isOnTheFly);
}
@Override public void visitClassInitializer(PsiClassInitializer initializer) {
checkCodeBlock(initializer.getBody(), holder, isOnTheFly);
}
};
}
private void checkCodeBlock(final PsiCodeBlock body,
final ProblemsHolder holder,
final boolean isOnTheFly) {
if (body == null) return;
final Set<PsiVariable> usedVariables = new THashSet<PsiVariable>();
List<DefUseUtil.Info> unusedDefs = DefUseUtil.getUnusedDefs(body, usedVariables);
if (unusedDefs != null && !unusedDefs.isEmpty()) {
Collections.sort(unusedDefs, new Comparator<DefUseUtil.Info>() {
@Override
public int compare(DefUseUtil.Info o1, DefUseUtil.Info o2) {
int offset1 = o1.getContext().getTextOffset();
int offset2 = o2.getContext().getTextOffset();
if (offset1 == offset2) return 0;
if (offset1 < offset2) return -1;
return 1;
}
});
for (DefUseUtil.Info info : unusedDefs) {
PsiElement context = info.getContext();
PsiVariable psiVariable = info.getVariable();
if (context instanceof PsiDeclarationStatement || context instanceof PsiResourceVariable) {
if (!info.isRead()) {
if (!isOnTheFly) {
holder.registerProblem(psiVariable.getNameIdentifier(),
InspectionsBundle.message("inspection.unused.assignment.problem.descriptor1", "<code>#ref</code> #loc"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL);
}
}
else {
if (REPORT_REDUNDANT_INITIALIZER) {
List<LocalQuickFix> fixes = ContainerUtil.createMaybeSingletonList(isOnTheFly ? createRemoveInitializerFix() : null);
holder.registerProblem(psiVariable.getInitializer(),
InspectionsBundle.message("inspection.unused.assignment.problem.descriptor2",
"<code>" + psiVariable.getName() + "</code>", "<code>#ref</code> #loc"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
fixes.toArray(new LocalQuickFix[fixes.size()])
);
}
}
}
else if (context instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignment = (PsiAssignmentExpression)context;
List<LocalQuickFix> fixes = ContainerUtil.createMaybeSingletonList(isOnTheFly ? createRemoveAssignmentFix() : null);
holder.registerProblem(assignment.getLExpression(),
InspectionsBundle.message("inspection.unused.assignment.problem.descriptor3",
assignment.getRExpression().getText(), "<code>#ref</code>" + " #loc"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL, fixes.toArray(new LocalQuickFix[fixes.size()])
);
}
else {
if (context instanceof PsiPrefixExpression && REPORT_PREFIX_EXPRESSIONS ||
context instanceof PsiPostfixExpression && REPORT_POSTFIX_EXPRESSIONS) {
holder.registerProblem(context,
InspectionsBundle.message("inspection.unused.assignment.problem.descriptor4", "<code>#ref</code> #loc"));
}
}
}
}
body.accept(new JavaRecursiveElementWalkingVisitor() {
@Override public void visitClass(PsiClass aClass) {
}
@Override public void visitLocalVariable(PsiLocalVariable variable) {
if (!usedVariables.contains(variable) && variable.getInitializer() == null && !isOnTheFly) {
holder.registerProblem(variable.getNameIdentifier(),
InspectionsBundle.message("inspection.unused.assignment.problem.descriptor5", "<code>#ref</code> #loc"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL);
}
}
});
}
protected LocalQuickFix createRemoveInitializerFix() {
return null;
}
protected LocalQuickFix createRemoveAssignmentFix() {
return null;
}
@Override
public JComponent createOptionsPanel() {
return new OptionsPanel();
}
private class OptionsPanel extends JPanel {
private final JCheckBox myReportPrefix;
private final JCheckBox myReportPostfix;
private final JCheckBox myReportInitializer;
private OptionsPanel() {
super(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.weighty = 0;
gc.weightx = 1;
gc.fill = GridBagConstraints.HORIZONTAL;
gc.anchor = GridBagConstraints.NORTHWEST;
myReportInitializer = new JCheckBox(InspectionsBundle.message("inspection.unused.assignment.option2"));
myReportInitializer.setSelected(REPORT_REDUNDANT_INITIALIZER);
myReportInitializer.getModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
REPORT_REDUNDANT_INITIALIZER = myReportInitializer.isSelected();
}
});
gc.insets = new Insets(0, 0, 15, 0);
gc.gridy = 0;
add(myReportInitializer, gc);
myReportPrefix = new JCheckBox(InspectionsBundle.message("inspection.unused.assignment.option"));
myReportPrefix.setSelected(REPORT_PREFIX_EXPRESSIONS);
myReportPrefix.getModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
REPORT_PREFIX_EXPRESSIONS = myReportPrefix.isSelected();
}
});
gc.insets = new Insets(0, 0, 0, 0);
gc.gridy++;
add(myReportPrefix, gc);
myReportPostfix = new JCheckBox(InspectionsBundle.message("inspection.unused.assignment.option1"));
myReportPostfix.setSelected(REPORT_POSTFIX_EXPRESSIONS);
myReportPostfix.getModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
REPORT_POSTFIX_EXPRESSIONS = myReportPostfix.isSelected();
}
});
gc.weighty = 1;
gc.gridy++;
add(myReportPostfix, gc);
}
}
@Override
@NotNull
public String getDisplayName() {
return DISPLAY_NAME;
}
@Override
@NotNull
public String getGroupDisplayName() {
return GroupNames.BUGS_GROUP_NAME;
}
@Override
@NotNull
public String getShortName() {
return SHORT_NAME;
}
}