Merge remote-tracking branch 'origin/master'

This commit is contained in:
Yann Cébron
2013-05-24 12:26:37 +02:00
149 changed files with 2127 additions and 1819 deletions
@@ -21,9 +21,9 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
@@ -40,45 +40,54 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class SimplifyBooleanExpressionFix implements IntentionAction {
public class SimplifyBooleanExpressionFix extends LocalQuickFixOnPsiElement {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.SimplifyBooleanExpression");
public static final String FAMILY_NAME = QuickFixBundle.message("simplify.boolean.expression.family");
private final PsiExpression mySubExpression;
private final Boolean mySubExpressionValue;
// subExpressionValue == Boolean.TRUE or Boolean.FALSE if subExpression evaluates to boolean constant and needs to be replaced
// otherwise subExpressionValue= null and we starting to simplify expression without any further knowledge
public SimplifyBooleanExpressionFix(PsiExpression subExpression, Boolean subExpressionValue) {
mySubExpression = subExpression;
public SimplifyBooleanExpressionFix(@NotNull PsiExpression subExpression, Boolean subExpressionValue) {
super(subExpression);
mySubExpressionValue = subExpressionValue;
}
@Override
@NotNull
public String getText() {
return QuickFixBundle.message("simplify.boolean.expression.text", mySubExpression.getText(), mySubExpressionValue);
PsiExpression expression = getSubExpression();
return QuickFixBundle.message("simplify.boolean.expression.text", expression.getText(), mySubExpressionValue);
}
@Override
@NotNull
public String getFamilyName() {
return QuickFixBundle.message("simplify.boolean.expression.family");
return FAMILY_NAME;
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return mySubExpression.isValid()
&& mySubExpression.getManager().isInProject(mySubExpression)
&& !PsiUtil.isAccessedForWriting(mySubExpression)
;
public boolean isAvailable() {
PsiExpression expression = getSubExpression();
return super.isAvailable()
&& expression != null
&& expression.isValid()
&& expression.getManager().isInProject(expression)
&& !PsiUtil.isAccessedForWriting(expression);
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
if (!isAvailable(project, editor, file)) return;
LOG.assertTrue(mySubExpression.isValid());
if (!FileModificationService.getInstance().preparePsiElementForWrite(mySubExpression)) return;
simplifyExpression(project, mySubExpression, mySubExpressionValue);
public void invoke(@NotNull final Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
if (!isAvailable()) return;
final PsiExpression expression = getSubExpression();
LOG.assertTrue(expression.isValid());
if (!FileModificationService.getInstance().preparePsiElementForWrite(expression)) return;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
simplifyExpression(project, expression, mySubExpressionValue);
}
});
}
public static void simplifyExpression(Project project, final PsiExpression subExpression, final Boolean subExpressionValue) {
@@ -226,6 +235,11 @@ public class SimplifyBooleanExpressionFix implements IntentionAction {
return canBeSimplified.get().booleanValue();
}
private PsiExpression getSubExpression() {
PsiElement element = getStartElement();
return element instanceof PsiExpression ? (PsiExpression)element : null;
}
private static class ExpressionVisitor extends JavaElementVisitor {
private PsiExpression resultExpression;
private final PsiExpression trueExpression;
@@ -420,9 +434,4 @@ public class SimplifyBooleanExpressionFix implements IntentionAction {
String text = operand.getText();
return PsiKeyword.TRUE.equals(text) ? Boolean.TRUE : PsiKeyword.FALSE.equals(text) ? Boolean.FALSE : null;
}
@Override
public boolean startInWriteAction() {
return true;
}
}
@@ -15,8 +15,9 @@
*/
package com.intellij.codeInsight.guess.impl;
import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInsight.JavaPsiEquivalenceUtil;
import com.intellij.codeInspection.dataFlow.DfaMemoryStateImpl;
import com.intellij.codeInspection.dataFlow.value.DfaInstanceofValue;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.openapi.diagnostic.Logger;
@@ -41,7 +42,7 @@ public class ExpressionTypeMemoryState extends DfaMemoryStateImpl {
@Override
public boolean equals(PsiExpression o1, PsiExpression o2) {
if (CodeInsightUtil.areExpressionsEquivalent(o1, o2)) {
if (JavaPsiEquivalenceUtil.areExpressionsEquivalent(o1, o2)) {
if (computeHashCode(o1) != computeHashCode(o2)) {
LOG.error("different hashCodes: " + o1 + "; " + o2 + "; " + computeHashCode(o1) + "!=" + computeHashCode(o2));
}
@@ -1,6 +1,6 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -22,6 +22,7 @@ import com.intellij.codeInspection.dataFlow.instructions.PushInstruction;
import com.intellij.codeInspection.dataFlow.instructions.TypeCastInstruction;
import com.intellij.codeInspection.dataFlow.instructions.InstanceofInstruction;
import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction;
import com.intellij.codeInspection.dataFlow.value.DfaInstanceofValue;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
@@ -140,7 +141,7 @@ public class GuessManagerImpl extends GuessManager {
@Nullable
private static Map<PsiExpression, PsiType> buildDataflowTypeMap(PsiExpression forPlace) {
PsiElement scope = DfaUtil.getTopmostBlockInSameClass(forPlace);
PsiElement scope = DfaPsiUtil.getTopmostBlockInSameClass(forPlace);
if (scope == null) {
PsiFile file = forPlace.getContainingFile();
if (!(file instanceof PsiCodeFragment)) {
@@ -23,14 +23,14 @@
package com.intellij.codeInsight.intention.impl;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
public class AddNullableNotNullAnnotationFix extends AddAnnotationFix {
public class AddNullableNotNullAnnotationFix extends AddAnnotationPsiFix {
public AddNullableNotNullAnnotationFix(@NotNull String fqn, @NotNull PsiModifierListOwner owner, @NotNull String... annotationToRemove) {
super(fqn, owner, annotationToRemove);
super(fqn, owner, PsiNameValuePair.EMPTY_ARRAY, annotationToRemove);
}
@Override
@@ -38,7 +38,7 @@ public class AddNullableNotNullAnnotationFix extends AddAnnotationFix {
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
if (!super.isAvailable(project, file, startElement, endElement)) {
if (!super.isAvailable(project, file, startElement, endElement)) {
return false;
}
PsiModifierListOwner owner = getContainer(startElement);
@@ -54,7 +54,7 @@ public class AddAssertStatementFix implements LocalQuickFix {
PsiElement anchorElement = PsiTreeUtil.getParentOfType(element, PsiStatement.class);
LOG.assertTrue(anchorElement != null);
PsiElement prev = PsiTreeUtil.skipSiblingsBackward(anchorElement, PsiWhiteSpace.class);
if (prev instanceof PsiComment && SuppressManager.getInstance().getSuppressedInspectionIdsIn(prev) != null) {
if (prev instanceof PsiComment && JavaSuppressionUtil.getSuppressedInspectionIdsIn(prev) != null) {
anchorElement = prev;
}
@@ -17,20 +17,18 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiNameValuePair;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
@@ -45,7 +43,7 @@ public class AnnotateMethodFix implements LocalQuickFix {
protected final String myAnnotation;
private final String[] myAnnotationsToRemove;
public AnnotateMethodFix(final String fqn, String... annotationsToRemove) {
public AnnotateMethodFix(@NotNull String fqn, @NotNull String... annotationsToRemove) {
myAnnotation = fqn;
myAnnotationsToRemove = annotationsToRemove;
}
@@ -68,7 +66,7 @@ public class AnnotateMethodFix implements LocalQuickFix {
for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) {
PsiMethod superMethod = superMethodSignature.getMethod();
if (!AnnotationUtil.isAnnotated(superMethod, myAnnotation, false, false) && superMethod.getManager().isInProject(superMethod)) {
int ret = annotateBaseMethod(method, superMethod, project);
int ret = shouldAnnotateBaseMethod(method, superMethod, project);
if (ret != 0 && ret != 1) return;
if (ret == 0) {
toAnnotate.add(superMethod);
@@ -91,15 +89,9 @@ public class AnnotateMethodFix implements LocalQuickFix {
UndoUtil.markPsiFileForUndo(method.getContainingFile());
}
public int annotateBaseMethod(final PsiMethod method, final PsiMethod superMethod, final Project project) {
String implement = !method.hasModifierProperty(PsiModifier.ABSTRACT) && superMethod.hasModifierProperty(PsiModifier.ABSTRACT)
? InspectionsBundle.message("inspection.annotate.quickfix.implements")
: InspectionsBundle.message("inspection.annotate.quickfix.overrides");
String message = InspectionsBundle.message("inspection.annotate.quickfix.overridden.method.messages",
UsageViewUtil.getDescriptiveName(method), implement,
UsageViewUtil.getDescriptiveName(superMethod));
String title = InspectionsBundle.message("inspection.annotate.quickfix.overridden.method.warning");
return Messages.showYesNoCancelDialog(project, message, title, Messages.getQuestionIcon());
// 0-annotate, 1-do not annotate, 2- cancel
public int shouldAnnotateBaseMethod(final PsiMethod method, final PsiMethod superMethod, final Project project) {
return 0;
}
protected boolean annotateOverriddenMethods() {
@@ -114,7 +106,8 @@ public class AnnotateMethodFix implements LocalQuickFix {
private void annotateMethod(@NotNull PsiMethod method) {
try {
new AddAnnotationFix(myAnnotation, method, myAnnotationsToRemove).invoke(method.getProject(), null, method.getContainingFile());
AddAnnotationPsiFix fix = new AddAnnotationPsiFix(myAnnotation, method, PsiNameValuePair.EMPTY_ARRAY, myAnnotationsToRemove);
fix.invoke(method.getProject(), method.getContainingFile(), method, method);
}
catch (IncorrectOperationException e) {
LOG.error(e);
@@ -16,14 +16,10 @@
package com.intellij.codeInspection;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtilBase;
import org.jetbrains.annotations.NotNull;
/**
@@ -66,22 +62,7 @@ public class ReplaceWithTernaryOperatorFix implements LocalQuickFix {
final PsiFile file = expression.getContainingFile();
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
final PsiConditionalExpression conditionalExpression = replaceWthConditionalExpression(project, myText + "!=null", expression, suggestDefaultValue(expression));
final PsiExpression elseExpression = conditionalExpression.getElseExpression();
if (elseExpression != null) {
selectInEditor(elseExpression);
}
}
private static void selectInEditor(@NotNull PsiElement element) {
final Editor editor = PsiUtilBase.findEditor(element);
if (editor == null) return;
final TextRange expressionRange = element.getTextRange();
editor.getCaretModel().moveToOffset(expressionRange.getStartOffset());
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
editor.getSelectionModel().setSelection(expressionRange.getStartOffset(), expressionRange.getEndOffset());
replaceWthConditionalExpression(project, myText + "!=null", expression, suggestDefaultValue(expression));
}
@NotNull
@@ -0,0 +1,107 @@
/*
* 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.codeInspection.accessStaticViaInstance;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil;
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil;
import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
public class AccessStaticViaInstanceBase extends BaseJavaBatchLocalInspectionTool {
@NonNls public static final String ACCESS_STATIC_VIA_INSTANCE = "AccessStaticViaInstance";
@Override
@NotNull
public String getGroupDisplayName() {
return "";
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("access.static.via.instance");
}
@Override
@NotNull
@NonNls
public String getShortName() {
return ACCESS_STATIC_VIA_INSTANCE;
}
@Override
public String getAlternativeID() {
return "static-access";
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
checkAccessStaticMemberViaInstanceReference(expression, holder, isOnTheFly);
}
};
}
private void checkAccessStaticMemberViaInstanceReference(PsiReferenceExpression expr, ProblemsHolder holder, boolean onTheFly) {
JavaResolveResult result = expr.advancedResolve(false);
PsiElement resolved = result.getElement();
if (!(resolved instanceof PsiMember)) return;
PsiExpression qualifierExpression = expr.getQualifierExpression();
if (qualifierExpression == null) return;
if (qualifierExpression instanceof PsiReferenceExpression) {
final PsiElement qualifierResolved = ((PsiReferenceExpression)qualifierExpression).resolve();
if (qualifierResolved instanceof PsiClass || qualifierResolved instanceof PsiPackage) {
return;
}
}
if (!((PsiMember)resolved).hasModifierProperty(PsiModifier.STATIC)) return;
String description = JavaErrorMessages.message("static.member.accessed.via.instance.reference",
JavaHighlightUtil.formatType(qualifierExpression.getType()),
HighlightMessageUtil.getSymbolName(resolved, result.getSubstitutor()));
if (!onTheFly) {
if (RemoveUnusedVariableUtil.checkSideEffects(qualifierExpression, null, new ArrayList<PsiElement>())) {
holder.registerProblem(expr, description);
return;
}
}
holder.registerProblem(expr, description, createAccessStaticViaInstanceFix(expr, onTheFly, result));
}
protected LocalQuickFix createAccessStaticViaInstanceFix(PsiReferenceExpression expr,
boolean onTheFly,
JavaResolveResult result) {
return null;
}
}
@@ -19,7 +19,7 @@
* User: max
* Date: Jan 11, 2002
* Time: 3:05:34 PM
* To change template for new class use
* To change template for new class use
* Code Style | Class Templates options (Tools | IDE Options).
*/
package com.intellij.codeInspection.dataFlow;
@@ -33,9 +33,10 @@ import com.intellij.psi.PsiVariable;
import gnu.trove.TObjectIntHashMap;
import java.util.ArrayList;
import java.util.List;
public class ControlFlow {
private final ArrayList<Instruction> myInstructions = new ArrayList<Instruction>();
private final List<Instruction> myInstructions = new ArrayList<Instruction>();
private final TObjectIntHashMap<PsiElement> myElementToStartOffsetMap = new TObjectIntHashMap<PsiElement>();
private final TObjectIntHashMap<PsiElement> myElementToEndOffsetMap = new TObjectIntHashMap<PsiElement>();
private DfaVariableValue[] myFields;
@@ -92,7 +93,7 @@ public class ControlFlow {
public String toString() {
StringBuilder result = new StringBuilder();
final ArrayList<Instruction> instructions = myInstructions;
final List<Instruction> instructions = myInstructions;
for (int i = 0; i < instructions.size(); i++) {
Instruction instruction = instructions.get(i);
@@ -1573,7 +1573,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
}
if (dfaValue == null) {
PsiType type = expression.getType();
return myFactory.createTypeValueWithNullability(type, DfaUtil.getElementNullability(type, field));
return myFactory.createTypeValueWithNullability(type, DfaPsiUtil.getElementNullability(type, field));
}
return dfaValue;
}
@@ -1610,7 +1610,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
return result;
}
if (DfaUtil.isFinalField(var) || DfaUtil.isPlainMutableField(var)) {
if (DfaPsiUtil.isFinalField(var) || DfaPsiUtil.isPlainMutableField(var)) {
DfaVariableValue qualifierValue = createChainedVariableValue(qualifier);
if (qualifierValue != null) {
return myFactory.getVarFactory().createVariableValue(var, refExpr.getType(), false, qualifierValue, isCall || qualifierValue.isViaMethods());
@@ -0,0 +1,590 @@
/*
* Copyright 2000-2012 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.
*/
/*
* Created by IntelliJ IDEA.
* User: max
* Date: Dec 24, 2001
* Time: 2:46:32 PM
* To change template for new class use
* Code Style | Class Templates options (Tools | IDE Options).
*/
package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.daemon.impl.quickfix.SimplifyBooleanExpressionFix;
import com.intellij.codeInsight.intention.impl.AddNullableAnnotationFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.DataFlowInspection");
@NonNls private static final String SHORT_NAME = "ConstantConditions";
public boolean SUGGEST_NULLABLE_ANNOTATIONS = false;
public boolean DONT_REPORT_TRUE_ASSERT_STATEMENTS = false;
@Override
public JComponent createOptionsPanel() {
throw new RuntimeException("no UI in headless mode");
}
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override
public void visitField(PsiField field) {
analyzeCodeBlock(field, holder);
}
@Override
public void visitMethod(PsiMethod method) {
analyzeCodeBlock(method.getBody(), holder);
}
@Override
public void visitClassInitializer(PsiClassInitializer initializer) {
analyzeCodeBlock(initializer.getBody(), holder);
}
};
}
private void analyzeCodeBlock(@Nullable final PsiElement scope, ProblemsHolder holder) {
if (scope == null) return;
final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner(SUGGEST_NULLABLE_ANNOTATIONS);
final StandardInstructionVisitor visitor = new DataFlowInstructionVisitor(dfaRunner);
final RunnerResult rc = dfaRunner.analyzeMethod(scope, visitor);
if (rc == RunnerResult.OK) {
if (dfaRunner.problemsDetected(visitor)) {
createDescription(dfaRunner, holder, visitor);
}
}
else if (rc == RunnerResult.TOO_COMPLEX) {
if (scope.getParent() instanceof PsiMethod) {
PsiMethod method = (PsiMethod)scope.getParent();
final PsiIdentifier name = method.getNameIdentifier();
if (name != null) { // Might be null for synthetic methods like JSP page.
holder.registerProblem(name, InspectionsBundle.message("dataflow.too.complex"), ProblemHighlightType.WEAK_WARNING);
}
}
}
}
@Nullable
private LocalQuickFix[] createNPEFixes(PsiExpression qualifier, PsiExpression expression) {
if (qualifier == null || expression == null) return null;
if (qualifier instanceof PsiMethodCallExpression) return null;
if (qualifier instanceof PsiLiteralExpression && ((PsiLiteralExpression)qualifier).getValue() == null) return null;
try {
final List<LocalQuickFix> fixes = new SmartList<LocalQuickFix>();
if (PsiUtil.getLanguageLevel(qualifier).isAtLeast(LanguageLevel.JDK_1_4)) {
final Project project = qualifier.getProject();
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
final PsiBinaryExpression binary = (PsiBinaryExpression)elementFactory.createExpressionFromText("a != null", null);
binary.getLOperand().replace(qualifier);
fixes.add(new AddAssertStatementFix(binary));
}
addSurroundWithIfFix(qualifier, fixes);
if (ReplaceWithTernaryOperatorFix.isAvailable(qualifier, expression)) {
fixes.add(new ReplaceWithTernaryOperatorFix(qualifier));
}
return fixes.toArray(new LocalQuickFix[fixes.size()]);
}
catch (IncorrectOperationException e) {
LOG.error(e);
return null;
}
}
protected void addSurroundWithIfFix(PsiExpression qualifier, List<LocalQuickFix> fixes) {
}
private void createDescription(StandardDataFlowRunner runner, ProblemsHolder holder, StandardInstructionVisitor visitor) {
Pair<Set<Instruction>, Set<Instruction>> constConditions = runner.getConstConditionalExpressions();
Set<Instruction> trueSet = constConditions.getFirst();
Set<Instruction> falseSet = constConditions.getSecond();
ArrayList<Instruction> allProblems = new ArrayList<Instruction>();
allProblems.addAll(trueSet);
allProblems.addAll(falseSet);
allProblems.addAll(runner.getNPEInstructions());
allProblems.addAll(runner.getCCEInstructions());
allProblems.addAll(StandardDataFlowRunner.getRedundantInstanceofs(runner, visitor));
Collections.sort(allProblems, new Comparator<Instruction>() {
@Override
public int compare(Instruction i1, Instruction i2) {
return i1.getIndex() - i2.getIndex();
}
});
HashSet<PsiElement> reportedAnchors = new HashSet<PsiElement>();
for (Instruction instruction : allProblems) {
if (instruction instanceof MethodCallInstruction) {
reportCallMayProduceNpe(holder, (MethodCallInstruction)instruction);
}
else if (instruction instanceof FieldReferenceInstruction) {
reportFieldAccessMayProduceNpe(holder, (FieldReferenceInstruction)instruction);
}
else if (instruction instanceof TypeCastInstruction) {
reportCastMayFail(holder, (TypeCastInstruction)instruction);
}
else if (instruction instanceof BranchingInstruction) {
handleBranchingInstruction(holder, visitor, trueSet, falseSet, reportedAnchors, (BranchingInstruction)instruction);
}
}
reportNullableArguments(runner, holder);
reportNullableAssignments(runner, holder);
reportUnboxedNullables(runner, holder);
reportNullableReturns(runner, holder);
reportNullableArgumentsPassedToNonAnnotated(runner, holder);
}
private void reportNullableArgumentsPassedToNonAnnotated(StandardDataFlowRunner runner, ProblemsHolder holder) {
Set<PsiExpression> exprs = runner.getNullableArgumentsPassedToNonAnnotatedParam();
for (PsiExpression expr : exprs) {
final String text = isNullLiteralExpression(expr)
? "Passing <code>null</code> argument to non annotated parameter"
: "Argument <code>#ref</code> #loc might be null but passed to non annotated parameter";
LocalQuickFix[] fixes = createNPEFixes(expr, expr);
final PsiElement parent = expr.getParent();
if (parent instanceof PsiExpressionList) {
final int idx = ArrayUtil.find(((PsiExpressionList)parent).getExpressions(), expr);
if (idx > -1) {
final PsiElement gParent = parent.getParent();
if (gParent instanceof PsiCallExpression) {
final PsiMethod psiMethod = ((PsiCallExpression)gParent).resolveMethod();
if (psiMethod != null && psiMethod.getManager().isInProject(psiMethod) && AnnotationUtil.isAnnotatingApplicable(psiMethod)) {
final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
if (idx < parameters.length) {
final AddNullableAnnotationFix addNullableAnnotationFix = new AddNullableAnnotationFix(parameters[idx]);
fixes = fixes == null ? new LocalQuickFix[]{addNullableAnnotationFix} : ArrayUtil.append(fixes, addNullableAnnotationFix);
holder.registerProblem(expr, text, fixes);
}
}
}
}
}
}
}
private void reportCallMayProduceNpe(ProblemsHolder holder, MethodCallInstruction mcInstruction) {
if (mcInstruction.getCallExpression() instanceof PsiMethodCallExpression) {
PsiMethodCallExpression callExpression = (PsiMethodCallExpression)mcInstruction.getCallExpression();
LocalQuickFix[] fix = createNPEFixes(callExpression.getMethodExpression().getQualifierExpression(), callExpression);
holder.registerProblem(callExpression,
InspectionsBundle.message("dataflow.message.npe.method.invocation"),
fix);
}
}
private void reportFieldAccessMayProduceNpe(ProblemsHolder holder, FieldReferenceInstruction frInstruction) {
PsiElement elementToAssert = frInstruction.getElementToAssert();
PsiExpression expression = frInstruction.getExpression();
if (expression instanceof PsiArrayAccessExpression) {
LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression);
holder.registerProblem(expression,
InspectionsBundle.message("dataflow.message.npe.array.access"),
fix);
}
else {
LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression);
holder.registerProblem(elementToAssert,
InspectionsBundle.message("dataflow.message.npe.field.access"),
fix);
}
}
private static void reportCastMayFail(ProblemsHolder holder, TypeCastInstruction instruction) {
PsiTypeCastExpression typeCast = instruction.getCastExpression();
holder.registerProblem(typeCast.getCastType(),
InspectionsBundle.message("dataflow.message.cce", typeCast.getOperand().getText()));
}
private void handleBranchingInstruction(ProblemsHolder holder,
StandardInstructionVisitor visitor,
Set<Instruction> trueSet,
Set<Instruction> falseSet, HashSet<PsiElement> reportedAnchors, BranchingInstruction instruction) {
PsiElement psiAnchor = instruction.getPsiAnchor();
boolean underBinary = isAtRHSOfBooleanAnd(psiAnchor);
if (instruction instanceof InstanceofInstruction && visitor.isInstanceofRedundant((InstanceofInstruction)instruction)) {
if (visitor.canBeNull((BinopInstruction)instruction)) {
holder.registerProblem(psiAnchor,
InspectionsBundle.message("dataflow.message.redundant.instanceof"),
new RedundantInstanceofFix());
}
else {
final LocalQuickFix localQuickFix = createSimplifyBooleanExpressionFix(psiAnchor, true);
holder.registerProblem(psiAnchor,
InspectionsBundle.message(underBinary ? "dataflow.message.constant.condition.when.reached" : "dataflow.message.constant.condition", Boolean.toString(true)),
localQuickFix == null ? null : new LocalQuickFix[]{localQuickFix});
}
}
else if (psiAnchor instanceof PsiSwitchLabelStatement) {
if (falseSet.contains(instruction)) {
holder.registerProblem(psiAnchor,
InspectionsBundle.message("dataflow.message.unreachable.switch.label"));
}
}
else if (psiAnchor != null && !reportedAnchors.contains(psiAnchor) && !isCompileConstantInIfCondition(psiAnchor)) {
boolean evaluatesToTrue = trueSet.contains(instruction);
if (onTheLeftSideOfConditionalAssignemnt(psiAnchor)) {
holder.registerProblem(
psiAnchor,
InspectionsBundle.message("dataflow.message.pointless.assignment.expression", Boolean.toString(evaluatesToTrue)),
createSimplifyToAssignmentFix()
);
}
else if (!skipReportingConstantCondition(visitor, psiAnchor, evaluatesToTrue)) {
final LocalQuickFix fix = createSimplifyBooleanExpressionFix(psiAnchor, evaluatesToTrue);
String message = InspectionsBundle.message(underBinary ?
"dataflow.message.constant.condition.when.reached" :
"dataflow.message.constant.condition", Boolean.toString(evaluatesToTrue));
holder.registerProblem(psiAnchor, message, fix == null ? null : new LocalQuickFix[]{fix});
}
reportedAnchors.add(psiAnchor);
}
}
private boolean skipReportingConstantCondition(StandardInstructionVisitor visitor, PsiElement psiAnchor, boolean evaluatesToTrue) {
return DONT_REPORT_TRUE_ASSERT_STATEMENTS && isAssertionEffectively(psiAnchor, evaluatesToTrue) ||
visitor.silenceConstantCondition(psiAnchor);
}
private void reportNullableArguments(StandardDataFlowRunner runner, ProblemsHolder holder) {
Set<PsiExpression> exprs = runner.getNullableArguments();
for (PsiExpression expr : exprs) {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.passing.null.argument")
: InspectionsBundle.message("dataflow.message.passing.nullable.argument");
LocalQuickFix[] fixes = createNPEFixes(expr, expr);
holder.registerProblem(expr, text, fixes);
}
}
private static void reportNullableAssignments(StandardDataFlowRunner runner, ProblemsHolder holder) {
for (PsiExpression expr : runner.getNullableAssignments()) {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.assigning.null")
: InspectionsBundle.message("dataflow.message.assigning.nullable");
holder.registerProblem(expr, text);
}
}
private static void reportUnboxedNullables(StandardDataFlowRunner runner, ProblemsHolder holder) {
for (PsiExpression expr : runner.getUnboxedNullables()) {
holder.registerProblem(expr, InspectionsBundle.message("dataflow.message.unboxing"));
}
}
private static void reportNullableReturns(StandardDataFlowRunner runner, ProblemsHolder holder) {
for (PsiReturnStatement statement : runner.getNullableReturns()) {
final PsiExpression expr = statement.getReturnValue();
if (runner.isInNotNullMethod()) {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.return.null.from.notnull")
: InspectionsBundle.message("dataflow.message.return.nullable.from.notnull");
holder.registerProblem(expr, text);
}
else if (AnnotationUtil.isAnnotatingApplicable(statement)) {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.return.null.from.notnullable")
: InspectionsBundle.message("dataflow.message.return.nullable.from.notnullable");
final NullableNotNullManager manager = NullableNotNullManager.getInstance(expr.getProject());
holder.registerProblem(expr, text, new AnnotateMethodFix(manager.getDefaultNullable(), ArrayUtil.toStringArray(manager.getNotNulls())){
@Override
public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) {
return 1;
}
});
}
}
}
private static boolean isAssertionEffectively(PsiElement psiAnchor, boolean evaluatesToTrue) {
PsiElement parent = psiAnchor.getParent();
if (parent instanceof PsiAssertStatement) {
return evaluatesToTrue;
}
if (parent instanceof PsiIfStatement && psiAnchor == ((PsiIfStatement)parent).getCondition()) {
PsiStatement thenBranch = ((PsiIfStatement)parent).getThenBranch();
if (thenBranch instanceof PsiThrowStatement) {
return !evaluatesToTrue;
}
if (thenBranch instanceof PsiBlockStatement) {
PsiStatement[] statements = ((PsiBlockStatement)thenBranch).getCodeBlock().getStatements();
if (statements.length == 1 && statements[0] instanceof PsiThrowStatement) {
return !evaluatesToTrue;
}
}
}
return false;
}
private static boolean isAtRHSOfBooleanAnd(PsiElement expr) {
PsiElement cur = expr;
while (cur != null && !(cur instanceof PsiMember)) {
PsiElement parent = cur.getParent();
if (parent instanceof PsiBinaryExpression && cur == ((PsiBinaryExpression)parent).getROperand()) {
return true;
}
cur = parent;
}
return false;
}
private static boolean isCompileConstantInIfCondition(PsiElement element) {
if (!(element instanceof PsiReferenceExpression)) return false;
PsiElement resolved = ((PsiReferenceExpression)element).resolve();
if (!(resolved instanceof PsiField)) return false;
PsiField field = (PsiField)resolved;
if (!field.hasModifierProperty(PsiModifier.FINAL)) return false;
if (!field.hasModifierProperty(PsiModifier.STATIC)) return false;
PsiElement parent = element.getParent();
if (parent instanceof PsiPrefixExpression && ((PsiPrefixExpression)parent).getOperationTokenType() == JavaTokenType.EXCL) {
element = parent;
parent = parent.getParent();
}
return parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getCondition() == element;
}
private static boolean isNullLiteralExpression(PsiExpression expr) {
if (expr instanceof PsiLiteralExpression) {
final PsiLiteralExpression literalExpression = (PsiLiteralExpression)expr;
return PsiType.NULL.equals(literalExpression.getType());
}
return false;
}
private static boolean onTheLeftSideOfConditionalAssignemnt(final PsiElement psiAnchor) {
final PsiElement parent = psiAnchor.getParent();
if (parent instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression expression = (PsiAssignmentExpression)parent;
if (expression.getLExpression() == psiAnchor) return true;
}
return false;
}
@Nullable
private static LocalQuickFix createSimplifyBooleanExpressionFix(PsiElement element, final boolean value) {
SimplifyBooleanExpressionFix fix = createIntention(element, value);
if (fix == null) return null;
final String text = fix.getText();
return new LocalQuickFix() {
@Override
@NotNull
public String getName() {
return text;
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement psiElement = descriptor.getPsiElement();
if (psiElement == null) return;
final SimplifyBooleanExpressionFix fix = createIntention(psiElement, value);
if (fix == null) return;
try {
LOG.assertTrue(psiElement.isValid());
fix.applyFix();
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
@Override
@NotNull
public String getFamilyName() {
return InspectionsBundle.message("inspection.data.flow.simplify.boolean.expression.quickfix");
}
};
}
@NotNull
private static LocalQuickFix createSimplifyToAssignmentFix() {
return new LocalQuickFix() {
@NotNull
@Override
public String getName() {
return InspectionsBundle.message("inspection.data.flow.simplify.to.assignment.quickfix.name");
}
@NotNull
@Override
public String getFamilyName() {
return InspectionsBundle.message("inspection.data.flow.simplify.boolean.expression.quickfix");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement psiElement = descriptor.getPsiElement();
if (psiElement == null) return;
final PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(psiElement, PsiAssignmentExpression.class);
if (assignmentExpression == null) {
return;
}
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final String lExpressionText = assignmentExpression.getLExpression().getText();
final PsiExpression rExpression = assignmentExpression.getRExpression();
final String rExpressionText = rExpression != null ? rExpression.getText() : "";
assignmentExpression.replace(factory.createExpressionFromText(lExpressionText + " = " + rExpressionText, psiElement));
}
};
}
private static SimplifyBooleanExpressionFix createIntention(PsiElement element, boolean value) {
if (!(element instanceof PsiExpression)) return null;
final PsiExpression expression = (PsiExpression)element;
while (element.getParent() instanceof PsiExpression) {
element = element.getParent();
}
final SimplifyBooleanExpressionFix fix = new SimplifyBooleanExpressionFix(expression, value);
// simplify intention already active
if (!fix.isAvailable() ||
SimplifyBooleanExpressionFix.canBeSimplified((PsiExpression)element)) {
return null;
}
return fix;
}
private static class RedundantInstanceofFix implements LocalQuickFix {
@Override
@NotNull
public String getName() {
return InspectionsBundle.message("inspection.data.flow.redundant.instanceof.quickfix");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(descriptor.getPsiElement())) return;
final PsiElement psiElement = descriptor.getPsiElement();
if (psiElement instanceof PsiInstanceOfExpression) {
try {
final PsiExpression compareToNull = JavaPsiFacade.getInstance(psiElement.getProject()).getElementFactory().
createExpressionFromText(((PsiInstanceOfExpression)psiElement).getOperand().getText() + " != null", psiElement.getParent());
psiElement.replace(compareToNull);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
@Override
@NotNull
public String getFamilyName() {
return getName();
}
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("inspection.data.flow.display.name");
}
@Override
@NotNull
public String getGroupDisplayName() {
return GroupNames.BUGS_GROUP_NAME;
}
@Override
@NotNull
public String getShortName() {
return SHORT_NAME;
}
private static class DataFlowInstructionVisitor extends StandardInstructionVisitor {
private final StandardDataFlowRunner myRunner;
private DataFlowInstructionVisitor(StandardDataFlowRunner runner) {
myRunner = runner;
}
@Override
protected void onAssigningToNotNullableVariable(AssignInstruction instruction) {
myRunner.onAssigningToNotNullableVariable(instruction.getRExpression());
}
@Override
protected void onNullableReturn(CheckReturnValueInstruction instruction) {
myRunner.onNullableReturn(instruction.getReturn());
}
@Override
protected void onInstructionProducesCCE(TypeCastInstruction instruction) {
myRunner.onInstructionProducesCCE(instruction);
}
@Override
protected void onInstructionProducesNPE(Instruction instruction) {
if (instruction instanceof MethodCallInstruction &&
((MethodCallInstruction)instruction).getMethodType() == MethodCallInstruction.MethodType.UNBOXING) {
myRunner.onUnboxingNullable(((MethodCallInstruction)instruction).getContext());
}
else {
myRunner.onInstructionProducesNPE(instruction);
}
}
@Override
protected void onPassingNullParameter(PsiExpression arg) {
myRunner.onPassingNullParameter(arg);
}
@Override
protected void onPassingNullParameterToNonAnnotated(DataFlowRunner runner, PsiExpression arg) {
myRunner.onPassingNullParameterToNonAnnotated(arg);
}
}
}
@@ -19,7 +19,7 @@
* User: max
* Date: Jan 28, 2002
* Time: 10:16:39 PM
* To change template for new class use
* To change template for new class use
* Code Style | Class Templates options (Tools | IDE Options).
*/
package com.intellij.codeInspection.dataFlow;
@@ -73,7 +73,7 @@ public class DataFlowRunner {
PsiClass containingClass = PsiTreeUtil.getParentOfType(psiBlock, PsiClass.class);
if (containingClass != null && PsiUtil.isLocalOrAnonymousClass(containingClass)) {
final PsiElement parent = containingClass.getParent();
final PsiCodeBlock block = DfaUtil.getTopmostBlockInSameClass(parent);
final PsiCodeBlock block = DfaPsiUtil.getTopmostBlockInSameClass(parent);
if ((parent instanceof PsiNewExpression || parent instanceof PsiDeclarationStatement) && block != null) {
final EnvironmentalInstructionVisitor envVisitor = new EnvironmentalInstructionVisitor(visitor, parent);
final RunnerResult result = analyzeMethod(block, envVisitor);
@@ -257,7 +257,7 @@ public class DataFlowRunner {
private void checkEnvironment(DataFlowRunner runner, DfaMemoryState memState, @Nullable PsiElement anchor) {
if (myClassParent == anchor) {
DfaMemoryStateImpl copy = (DfaMemoryStateImpl)memState.createCopy();
copy.flushFields(runner);
copy.flushFields(runner.getFields());
Set<DfaVariableValue> vars = new HashSet<DfaVariableValue>(copy.getVariableStates().keySet());
for (DfaVariableValue value : vars) {
copy.flushDependencies(value);
@@ -47,7 +47,7 @@ public interface DfaMemoryState {
boolean applyNotNull(DfaValue value);
void flushFields(DataFlowRunner runner);
void flushFields(DfaVariableValue[] fields);
void flushVariable(DfaVariableValue variable);
@@ -42,7 +42,7 @@ import java.util.*;
public class DfaMemoryStateImpl implements DfaMemoryState {
private final DfaValueFactory myFactory;
private final ArrayList<SortedIntSet> myEqClasses = new ArrayList<SortedIntSet>();
private final List<SortedIntSet> myEqClasses = new ArrayList<SortedIntSet>();
private int myStateSize = 0;
private final Stack<DfaValue> myStack = new Stack<DfaValue>();
private TIntStack myOffsetStack = new TIntStack(1);
@@ -691,7 +691,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
private static boolean isMaybeBoxedConstant(DfaValue val) {
return val instanceof DfaConstValue ||
(val instanceof DfaBoxedValue && ((DfaBoxedValue)val).getWrappedValue() instanceof DfaConstValue);
val instanceof DfaBoxedValue && ((DfaBoxedValue)val).getWrappedValue() instanceof DfaConstValue;
}
private boolean checkCompareWithBooleanLiteral(DfaValue dfaLeft, DfaValue dfaRight, boolean negated) {
@@ -788,7 +788,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
state.setNullable(false);
return state;
}
myVariableStates.put(dfaVar, state);
}
@@ -804,16 +804,16 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
@Override
public void flushFields(DataFlowRunner runner) {
public void flushFields(DfaVariableValue[] fields) {
Set<DfaVariableValue> allVars = new HashSet<DfaVariableValue>(myVariableStates.keySet());
Collections.addAll(allVars, runner.getFields());
Collections.addAll(allVars, fields);
Set<DfaVariableValue> dependencies = new HashSet<DfaVariableValue>();
for (DfaVariableValue variableValue : allVars) {
dependencies.addAll(myFactory.getVarFactory().getAllQualifiedBy(variableValue));
}
allVars.addAll(dependencies);
for (DfaVariableValue value : allVars) {
if (myVariableStates.containsKey(value) || getEqClassIndex(value) >= 0) {
if (value.isFlushableByCalls()) {
@@ -0,0 +1,249 @@
/*
* 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.codeInspection.dataFlow;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.NullableFunction;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class DfaPsiUtil {
public static boolean isPlainMutableField(PsiVariable var) {
return !var.hasModifierProperty(PsiModifier.FINAL) && !var.hasModifierProperty(PsiModifier.TRANSIENT) && !var.hasModifierProperty(PsiModifier.VOLATILE) && var instanceof PsiField;
}
public static boolean isFinalField(PsiVariable var) {
return var.hasModifierProperty(PsiModifier.FINAL) && !var.hasModifierProperty(PsiModifier.TRANSIENT) && var instanceof PsiField;
}
static PsiElement getEnclosingCodeBlock(final PsiVariable variable, final PsiElement context) {
PsiElement codeBlock;
if (variable instanceof PsiParameter) {
codeBlock = ((PsiParameter)variable).getDeclarationScope();
if (codeBlock instanceof PsiMethod) {
codeBlock = ((PsiMethod)codeBlock).getBody();
}
}
else if (variable instanceof PsiLocalVariable) {
codeBlock = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
}
else {
codeBlock = PsiTreeUtil.getParentOfType(context, PsiCodeBlock.class);
}
while (codeBlock != null) {
PsiAnonymousClass anon = PsiTreeUtil.getParentOfType(codeBlock, PsiAnonymousClass.class);
if (anon == null) break;
codeBlock = PsiTreeUtil.getParentOfType(anon, PsiCodeBlock.class);
}
return codeBlock;
}
@NotNull
public static Nullness getElementNullability(@Nullable PsiType resultType, @Nullable PsiModifierListOwner owner) {
if (owner == null) {
return Nullness.UNKNOWN;
}
if (NullableNotNullManager.isNullable(owner)) {
return Nullness.NULLABLE;
}
if (NullableNotNullManager.isNotNull(owner)) {
return Nullness.NOT_NULL;
}
if (resultType != null) {
NullableNotNullManager nnn = NullableNotNullManager.getInstance(owner.getProject());
for (PsiAnnotation annotation : resultType.getAnnotations()) {
String qualifiedName = annotation.getQualifiedName();
if (nnn.getNullables().contains(qualifiedName)) {
return Nullness.NULLABLE;
}
if (nnn.getNotNulls().contains(qualifiedName)) {
return Nullness.NOT_NULL;
}
}
}
return Nullness.UNKNOWN;
}
public static List<PsiExpression> findAllConstructorInitializers(PsiField field) {
final List<PsiExpression> result = ContainerUtil.createLockFreeCopyOnWriteList();
ContainerUtil.addIfNotNull(result, field.getInitializer());
PsiClass containingClass = field.getContainingClass();
if (containingClass != null) {
LocalSearchScope scope = new LocalSearchScope(containingClass.getConstructors());
ReferencesSearch.search(field, scope, false).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference reference) {
final PsiElement element = reference.getElement();
if (element instanceof PsiReferenceExpression) {
final PsiAssignmentExpression assignment = getAssignmentExpressionIfOnAssignmentLhs(element);
final PsiMethod method = PsiTreeUtil.getParentOfType(assignment, PsiMethod.class);
if (method != null && method.isConstructor() && assignment != null) {
ContainerUtil.addIfNotNull(result, assignment.getRExpression());
}
}
return true;
}
});
}
return result;
}
@Nullable
private static PsiAssignmentExpression getAssignmentExpressionIfOnAssignmentLhs(PsiElement expression) {
PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class);
if (!(parent instanceof PsiAssignmentExpression)) {
return null;
}
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
if (!PsiTreeUtil.isAncestor(assignmentExpression.getLExpression(), expression, false)) {
return null;
}
return assignmentExpression;
}
public static boolean isNullableInitialized(PsiVariable var, boolean nullable) {
if (!isFinalField(var)) {
return false;
}
List<PsiExpression> initializers = findAllConstructorInitializers((PsiField)var);
if (initializers.isEmpty()) {
return false;
}
for (PsiExpression expression : initializers) {
if (!(expression instanceof PsiReferenceExpression)) {
return false;
}
PsiElement target = ((PsiReferenceExpression)expression).resolve();
if (!(target instanceof PsiParameter)) {
return false;
}
if (nullable && NullableNotNullManager.isNullable((PsiParameter)target)) {
return true;
}
if (!nullable && !NullableNotNullManager.isNotNull((PsiParameter)target)) {
return false;
}
}
return !nullable;
}
@Nullable
public static PsiCodeBlock getTopmostBlockInSameClass(@NotNull PsiElement position) {
PsiCodeBlock block = PsiTreeUtil.getParentOfType(position, PsiCodeBlock.class, false, PsiMember.class, PsiFile.class);
if (block == null) {
return null;
}
PsiCodeBlock lastBlock = block;
while (true) {
block = PsiTreeUtil.getParentOfType(block, PsiCodeBlock.class, true, PsiMember.class, PsiFile.class);
if (block == null) {
return lastBlock;
}
lastBlock = block;
}
}
@NotNull
public static Collection<PsiExpression> getVariableAssignmentsInFile(@NotNull PsiVariable psiVariable,
final boolean literalsOnly,
final PsiElement place) {
final Ref<Boolean> modificationRef = Ref.create(Boolean.FALSE);
final PsiCodeBlock codeBlock = place == null? null : getTopmostBlockInSameClass(place);
final int placeOffset = codeBlock != null? place.getTextRange().getStartOffset() : 0;
List<PsiExpression> list = ContainerUtil.mapNotNull(
ReferencesSearch.search(psiVariable, new LocalSearchScope(new PsiElement[] {psiVariable.getContainingFile()}, null, true)).findAll(),
new NullableFunction<PsiReference, PsiExpression>() {
@Override
public PsiExpression fun(final PsiReference psiReference) {
if (modificationRef.get()) return null;
final PsiElement parent = psiReference.getElement().getParent();
if (parent instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
final IElementType operation = assignmentExpression.getOperationTokenType();
if (assignmentExpression.getLExpression() == psiReference) {
if (JavaTokenType.EQ.equals(operation)) {
final PsiExpression rValue = assignmentExpression.getRExpression();
if (!literalsOnly || allOperandsAreLiterals(rValue)) {
// if there's a codeBlock omit the values assigned later
if (codeBlock != null && PsiTreeUtil.isAncestor(codeBlock, parent, true)
&& placeOffset < parent.getTextRange().getStartOffset()) {
return null;
}
return rValue;
}
else {
modificationRef.set(Boolean.TRUE);
}
}
else if (JavaTokenType.PLUSEQ.equals(operation)) {
modificationRef.set(Boolean.TRUE);
}
}
}
return null;
}
});
if (modificationRef.get()) return Collections.emptyList();
PsiExpression initializer = psiVariable.getInitializer();
if (initializer != null && (!literalsOnly || allOperandsAreLiterals(initializer))) {
list = ContainerUtil.concat(list, Collections.singletonList(initializer));
}
return list;
}
public static boolean allOperandsAreLiterals(@Nullable final PsiExpression expression) {
if (expression == null) return false;
if (expression instanceof PsiLiteralExpression) return true;
if (expression instanceof PsiPolyadicExpression) {
Stack<PsiExpression> stack = new Stack<PsiExpression>();
stack.add(expression);
while (!stack.isEmpty()) {
PsiExpression psiExpression = stack.pop();
if (psiExpression instanceof PsiPolyadicExpression) {
PsiPolyadicExpression binaryExpression = (PsiPolyadicExpression)psiExpression;
for (PsiExpression op : binaryExpression.getOperands()) {
stack.push(op);
}
}
else if (!(psiExpression instanceof PsiLiteralExpression)) {
return false;
}
}
return true;
}
return false;
}
}
@@ -15,27 +15,18 @@
*/
package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInspection.dataFlow.instructions.AssignInstruction;
import com.intellij.codeInspection.dataFlow.instructions.Instruction;
import com.intellij.codeInspection.dataFlow.instructions.PushInstruction;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.nullable.NullableStuffInspection;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.MultiValuesMap;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -58,7 +49,7 @@ public class DfaUtil {
CachedValue<MultiValuesMap<PsiVariable, PsiExpression>> cachedValue = context.getUserData(DFA_VARIABLE_INFO_KEY);
if (cachedValue == null) {
final PsiElement codeBlock = getEnclosingCodeBlock(variable, context);
final PsiElement codeBlock = DfaPsiUtil.getEnclosingCodeBlock(variable, context);
cachedValue = CachedValuesManager.getManager(context.getProject()).createCachedValue(new CachedValueProvider<MultiValuesMap<PsiVariable, PsiExpression>>() {
@Override
public Result<MultiValuesMap<PsiVariable, PsiExpression>> compute() {
@@ -87,76 +78,11 @@ public class DfaUtil {
return expressions == null ? Collections.<PsiExpression>emptyList() : expressions;
}
@NotNull
public static Nullness getElementNullability(@Nullable PsiType resultType, @Nullable PsiModifierListOwner owner) {
if (owner == null) {
return Nullness.UNKNOWN;
}
if (NullableNotNullManager.isNullable(owner)) {
return Nullness.NULLABLE;
}
if (NullableNotNullManager.isNotNull(owner)) {
return Nullness.NOT_NULL;
}
if (resultType != null) {
NullableNotNullManager nnn = NullableNotNullManager.getInstance(owner.getProject());
for (PsiAnnotation annotation : resultType.getAnnotations()) {
String qualifiedName = annotation.getQualifiedName();
if (nnn.getNullables().contains(qualifiedName)) {
return Nullness.NULLABLE;
}
if (nnn.getNotNulls().contains(qualifiedName)) {
return Nullness.NOT_NULL;
}
}
}
return Nullness.UNKNOWN;
}
public static boolean isNullableInitialized(PsiVariable var, boolean nullable) {
if (!isFinalField(var)) {
return false;
}
List<PsiExpression> initializers = NullableStuffInspection.findAllConstructorInitializers((PsiField)var);
if (initializers.isEmpty()) {
return false;
}
for (PsiExpression expression : initializers) {
if (!(expression instanceof PsiReferenceExpression)) {
return false;
}
PsiElement target = ((PsiReferenceExpression)expression).resolve();
if (!(target instanceof PsiParameter)) {
return false;
}
if (nullable && NullableNotNullManager.isNullable((PsiParameter)target)) {
return true;
}
if (!nullable && !NullableNotNullManager.isNotNull((PsiParameter)target)) {
return false;
}
}
return !nullable;
}
public static boolean isPlainMutableField(PsiVariable var) {
return !var.hasModifierProperty(PsiModifier.FINAL) && !var.hasModifierProperty(PsiModifier.TRANSIENT) && !var.hasModifierProperty(PsiModifier.VOLATILE) && var instanceof PsiField;
}
public static boolean isFinalField(PsiVariable var) {
return var.hasModifierProperty(PsiModifier.FINAL) && !var.hasModifierProperty(PsiModifier.TRANSIENT) && var instanceof PsiField;
}
@NotNull
public static Nullness checkNullness(@Nullable final PsiVariable variable, @Nullable final PsiElement context) {
if (variable == null || context == null) return Nullness.UNKNOWN;
final PsiElement codeBlock = getEnclosingCodeBlock(variable, context);
final PsiElement codeBlock = DfaPsiUtil.getEnclosingCodeBlock(variable, context);
if (codeBlock == null) {
return Nullness.UNKNOWN;
}
@@ -170,45 +96,6 @@ public class DfaUtil {
return Nullness.UNKNOWN;
}
@Nullable
public static PsiCodeBlock getTopmostBlockInSameClass(@NotNull PsiElement position) {
PsiCodeBlock block = PsiTreeUtil.getParentOfType(position, PsiCodeBlock.class, false, PsiMember.class, PsiFile.class);
if (block == null) {
return null;
}
PsiCodeBlock lastBlock = block;
while (true) {
block = PsiTreeUtil.getParentOfType(block, PsiCodeBlock.class, true, PsiMember.class, PsiFile.class);
if (block == null) {
return lastBlock;
}
lastBlock = block;
}
}
private static PsiElement getEnclosingCodeBlock(final PsiVariable variable, final PsiElement context) {
PsiElement codeBlock;
if (variable instanceof PsiParameter) {
codeBlock = ((PsiParameter)variable).getDeclarationScope();
if (codeBlock instanceof PsiMethod) {
codeBlock = ((PsiMethod)codeBlock).getBody();
}
}
else if (variable instanceof PsiLocalVariable) {
codeBlock = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
}
else {
codeBlock = PsiTreeUtil.getParentOfType(context, PsiCodeBlock.class);
}
while (codeBlock != null) {
PsiAnonymousClass anon = PsiTreeUtil.getParentOfType(codeBlock, PsiAnonymousClass.class);
if (anon == null) break;
codeBlock = PsiTreeUtil.getParentOfType(anon, PsiCodeBlock.class);
}
return codeBlock;
}
@NotNull
public static Collection<? extends PsiElement> getPossibleInitializationElements(final PsiElement qualifierExpression) {
if (qualifierExpression instanceof PsiMethodCallExpression) {
@@ -221,7 +108,7 @@ public class DfaUtil {
}
final Collection<? extends PsiElement> variableValues = getCachedVariableValues((PsiVariable)targetElement, qualifierExpression);
if (variableValues == null || variableValues.isEmpty()) {
return getVariableAssignmentsInFile((PsiVariable)targetElement, false, qualifierExpression);
return DfaPsiUtil.getVariableAssignmentsInFile((PsiVariable)targetElement, false, qualifierExpression);
}
return variableValues;
}
@@ -231,77 +118,6 @@ public class DfaUtil {
return Collections.emptyList();
}
@NotNull
public static Collection<PsiExpression> getVariableAssignmentsInFile(@NotNull PsiVariable psiVariable,
final boolean literalsOnly,
final PsiElement place) {
final Ref<Boolean> modificationRef = Ref.create(Boolean.FALSE);
final PsiCodeBlock codeBlock = place == null? null : getTopmostBlockInSameClass(place);
final int placeOffset = codeBlock != null? place.getTextRange().getStartOffset() : 0;
List<PsiExpression> list = ContainerUtil.mapNotNull(
ReferencesSearch.search(psiVariable, new LocalSearchScope(new PsiElement[] {psiVariable.getContainingFile()}, null, true)).findAll(),
new NullableFunction<PsiReference, PsiExpression>() {
@Override
public PsiExpression fun(final PsiReference psiReference) {
if (modificationRef.get()) return null;
final PsiElement parent = psiReference.getElement().getParent();
if (parent instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
final IElementType operation = assignmentExpression.getOperationTokenType();
if (assignmentExpression.getLExpression() == psiReference) {
if (JavaTokenType.EQ.equals(operation)) {
final PsiExpression rValue = assignmentExpression.getRExpression();
if (!literalsOnly || allOperandsAreLiterals(rValue)) {
// if there's a codeBlock omit the values assigned later
if (codeBlock != null && PsiTreeUtil.isAncestor(codeBlock, parent, true)
&& placeOffset < parent.getTextRange().getStartOffset()) {
return null;
}
return rValue;
}
else {
modificationRef.set(Boolean.TRUE);
}
}
else if (JavaTokenType.PLUSEQ.equals(operation)) {
modificationRef.set(Boolean.TRUE);
}
}
}
return null;
}
});
if (modificationRef.get()) return Collections.emptyList();
PsiExpression initializer = psiVariable.getInitializer();
if (initializer != null && (!literalsOnly || allOperandsAreLiterals(initializer))) {
list = ContainerUtil.concat(list, Collections.singletonList(initializer));
}
return list;
}
public static boolean allOperandsAreLiterals(@Nullable final PsiExpression expression) {
if (expression == null) return false;
if (expression instanceof PsiLiteralExpression) return true;
if (expression instanceof PsiPolyadicExpression) {
Stack<PsiExpression> stack = new Stack<PsiExpression>();
stack.add(expression);
while (!stack.isEmpty()) {
PsiExpression psiExpression = stack.pop();
if (psiExpression instanceof PsiPolyadicExpression) {
PsiPolyadicExpression binaryExpression = (PsiPolyadicExpression)psiExpression;
for (PsiExpression op : binaryExpression.getOperands()) {
stack.push(op);
}
}
else if (!(psiExpression instanceof PsiLiteralExpression)) {
return false;
}
}
return true;
}
return false;
}
private static class ValuableInstructionVisitor extends StandardInstructionVisitor {
final MultiValuesMap<PsiVariable, PsiExpression> myValues = new MultiValuesMap<PsiVariable, PsiExpression>(true);
final Set<PsiVariable> myNulls = new THashSet<PsiVariable>();
@@ -121,7 +121,7 @@ public abstract class InstructionVisitor {
if (variable != null) {
memState.flushVariable(variable);
} else {
memState.flushFields(runner);
memState.flushFields(runner.getFields());
}
return nextInstruction(instruction, runner, memState);
}
@@ -55,7 +55,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
return Nullness.NOT_NULL;
}
return callExpression != null ? DfaUtil.getElementNullability(key.getResultType(), callExpression.resolveMethod()) : null;
return callExpression != null ? DfaPsiUtil.getElementNullability(key.getResultType(), callExpression.resolveMethod()) : null;
}
};
@@ -74,7 +74,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
Map<PsiExpression, Nullness> map = ContainerUtil.newHashMap();
for (int i = 0; i < checkedCount; i++) {
map.put(args[i], DfaUtil.getElementNullability(substitutor.substitute(parameters[i].getType()), parameters[i]));
map.put(args[i], DfaPsiUtil.getElementNullability(substitutor.substitute(parameters[i].getType()), parameters[i]));
}
return map;
}
@@ -112,7 +112,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
if (dfaDest instanceof DfaVariableValue) {
DfaVariableValue var = (DfaVariableValue) dfaDest;
final PsiVariable psiVariable = var.getPsiVariable();
if (DfaUtil.getElementNullability(var.getVariableType(), psiVariable) == Nullness.NOT_NULL) {
if (DfaPsiUtil.getElementNullability(var.getVariableType(), psiVariable) == Nullness.NOT_NULL) {
if (!memState.applyNotNull(dfaSource)) {
onAssigningToNotNullableVariable(instruction);
}
@@ -215,7 +215,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
finally {
memState.push(getMethodResultValue(instruction, qualifier, runner.getFactory()));
if (instruction.shouldFlushFields()) {
memState.flushFields(runner);
memState.flushFields(runner.getFields());
}
}
}
@@ -229,7 +229,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
final PsiType type = instruction.getResultType();
final MethodCallInstruction.MethodType methodType = instruction.getMethodType();
if (methodType == MethodCallInstruction.MethodType.UNBOXING) {
return factory.getBoxedFactory().createUnboxed(qualifierValue);
}
@@ -19,7 +19,7 @@
* User: max
* Date: Jan 26, 2002
* Time: 10:46:40 PM
* To change template for new class use
* To change template for new class use
* Code Style | Class Templates options (Tools | IDE Options).
*/
package com.intellij.codeInspection.dataFlow.instructions;
@@ -31,10 +31,11 @@ import com.intellij.codeInspection.dataFlow.InstructionVisitor;
import com.intellij.openapi.progress.ProgressManager;
import java.util.ArrayList;
import java.util.List;
public abstract class Instruction {
private int myIndex;
private final ArrayList<DfaMemoryState> myProcessedStates;
private final List<DfaMemoryState> myProcessedStates;
protected Instruction() {
myProcessedStates = new ArrayList<DfaMemoryState>();
@@ -13,10 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.guess.impl;
package com.intellij.codeInspection.dataFlow.value;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
@@ -24,7 +24,7 @@
*/
package com.intellij.codeInspection.dataFlow.value;
import com.intellij.codeInspection.dataFlow.DfaUtil;
import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
import com.intellij.codeInspection.dataFlow.Nullness;
import com.intellij.psi.*;
import com.intellij.util.containers.HashMap;
@@ -159,11 +159,11 @@ public class DfaVariableValue extends DfaValue {
}
PsiVariable var = getPsiVariable();
Nullness nullability = DfaUtil.getElementNullability(getVariableType(), var);
Nullness nullability = DfaPsiUtil.getElementNullability(getVariableType(), var);
if (nullability == Nullness.UNKNOWN && var != null) {
if (DfaUtil.isNullableInitialized(var, true)) {
if (DfaPsiUtil.isNullableInitialized(var, true)) {
nullability = Nullness.NULLABLE;
} else if (DfaUtil.isNullableInitialized(var, false)) {
} else if (DfaPsiUtil.isNullableInitialized(var, false)) {
nullability = Nullness.NOT_NULL;
}
}
@@ -172,7 +172,7 @@ public class DfaVariableValue extends DfaValue {
return nullability;
}
public boolean isLocalVariable() {
return myVariable instanceof PsiLocalVariable || myVariable instanceof PsiParameter;
}
@@ -17,7 +17,7 @@ package com.intellij.codeInspection.nullable;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
@@ -25,12 +25,13 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiNameValuePair;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
@@ -65,7 +66,7 @@ public class AnnotateOverriddenMethodParameterFix implements LocalQuickFix {
PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class);
if (method == null) return;
PsiParameter[] parameters = method.getParameterList().getParameters();
int index = ArrayUtil.find(parameters, parameter);
int index = ArrayUtilRt.find(parameters, parameter);
List<PsiParameter> toAnnotate = new ArrayList<PsiParameter>();
@@ -84,7 +85,8 @@ public class AnnotateOverriddenMethodParameterFix implements LocalQuickFix {
try {
assert psiParam != null : toAnnotate;
if (AnnotationUtil.isAnnotatingApplicable(psiParam, myAnnotation)) {
new AddAnnotationFix(myAnnotation, psiParam, myAnnosToRemove).invoke(project, null, psiParam.getContainingFile());
AddAnnotationPsiFix fix = new AddAnnotationPsiFix(myAnnotation, psiParam, PsiNameValuePair.EMPTY_ARRAY, myAnnosToRemove);
fix.invoke(project, psiParam.getContainingFile(), psiParam, psiParam);
}
}
catch (IncorrectOperationException e) {
@@ -59,7 +59,8 @@ class ChangeNullableDefaultsFix implements LocalQuickFix {
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (myNotNullName != null) {
myManager.setDefaultNotNull(myNotNullName);
} else {
}
else {
myManager.setDefaultNullable(myNullableName);
}
}
@@ -0,0 +1,469 @@
/*
* Copyright 2000-2011 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.nullable;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.codeInsight.intention.impl.AddNotNullAnnotationFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.List;
public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionTool {
// deprecated fields remain to minimize changes to users inspection profiles (which are often located in version control).
@Deprecated @SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL = true;
@SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL = true;
@SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE = true;
@Deprecated @SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL = true;
@SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOT_ANNOTATED_GETTER = true;
@Deprecated @SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOT_ANNOTATED_SETTER_PARAMETER = true;
@Deprecated @SuppressWarnings({"WeakerAccess"}) public boolean REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS = true; // remains for test
@SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD = true;
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.nullable.NullableStuffInspectionBase");
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override public void visitMethod(PsiMethod method) {
if (!PsiUtil.isLanguageLevel5OrHigher(method)) return;
checkNullableStuffForMethod(method, holder);
}
@Override public void visitField(PsiField field) {
if (!PsiUtil.isLanguageLevel5OrHigher(field)) return;
final PsiType type = field.getType();
final Annotated annotated = check(field, holder, type);
if (TypeConversionUtil.isPrimitiveAndNotNull(type)) {
return;
}
Project project = holder.getProject();
final NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
if (annotated.isDeclaredNotNull ^ annotated.isDeclaredNullable) {
final String anno = annotated.isDeclaredNotNull ? manager.getDefaultNotNull() : manager.getDefaultNullable();
final List<String> annoToRemove = annotated.isDeclaredNotNull ? manager.getNullables() : manager.getNotNulls();
if (!AnnotationUtil.isAnnotatingApplicable(field, anno)) {
final PsiAnnotation notNull = AnnotationUtil.findAnnotation(field, manager.getNotNulls());
final PsiAnnotation nullable = AnnotationUtil.findAnnotation(field, manager.getNullables());
holder.registerProblem(field.getNameIdentifier(), "Nullable/NotNull defaults are not accessible in current context",
new ChangeNullableDefaultsFix(notNull, nullable, manager));
return;
}
String propName = JavaCodeStyleManager.getInstance(project).variableNameToPropertyName(field.getName(), VariableKind.FIELD);
final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC);
final PsiMethod getter = PropertyUtil.findPropertyGetter(field.getContainingClass(), propName, isStatic, false);
final String nullableSimpleName = StringUtil.getShortName(manager.getDefaultNullable());
final String notNullSimpleName = StringUtil.getShortName(manager.getDefaultNotNull());
final PsiIdentifier nameIdentifier = getter == null ? null : getter.getNameIdentifier();
if (nameIdentifier != null && nameIdentifier.isPhysical()) {
if (PropertyUtil.isSimpleGetter(getter)) {
AnnotateMethodFix getterAnnoFix = new AnnotateMethodFix(anno, ArrayUtil.toStringArray(annoToRemove)) {
@Override
public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) {
return 1;
}
};
if (REPORT_NOT_ANNOTATED_GETTER) {
if (!AnnotationUtil.isAnnotated(getter, manager.getAllAnnotations(), false, false) &&
!TypeConversionUtil.isPrimitiveAndNotNull(getter.getReturnType())) {
holder.registerProblem(nameIdentifier, InspectionsBundle
.message("inspection.nullable.problems.annotated.field.getter.not.annotated", StringUtil.getShortName(anno)),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, getterAnnoFix);
}
}
if (annotated.isDeclaredNotNull && manager.isNullable(getter, false)) {
holder.registerProblem(nameIdentifier, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.getter.conflict", StringUtil.getShortName(anno), nullableSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, getterAnnoFix);
} else if (annotated.isDeclaredNullable && manager.isNotNull(getter, false)) {
holder.registerProblem(nameIdentifier, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.getter.conflict", StringUtil.getShortName(anno), notNullSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, getterAnnoFix);
}
}
}
final PsiClass containingClass = field.getContainingClass();
final PsiMethod setter = PropertyUtil.findPropertySetter(containingClass, propName, isStatic, false);
if (setter != null) {
final PsiParameter[] parameters = setter.getParameterList().getParameters();
assert parameters.length == 1 : setter.getText();
final PsiParameter parameter = parameters[0];
LOG.assertTrue(parameter != null, setter.getText());
AddAnnotationPsiFix addAnnoFix = new AddAnnotationPsiFix(anno, parameter, PsiNameValuePair.EMPTY_ARRAY, ArrayUtil.toStringArray(annoToRemove));
if (REPORT_NOT_ANNOTATED_GETTER && !AnnotationUtil.isAnnotated(parameter, manager.getAllAnnotations(), false, false) && !TypeConversionUtil.isPrimitiveAndNotNull(parameter.getType())) {
final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier();
assertValidElement(setter, parameter, nameIdentifier1);
holder.registerProblem(nameIdentifier1,
InspectionsBundle.message("inspection.nullable.problems.annotated.field.setter.parameter.not.annotated",
StringUtil.getShortName(anno)),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
addAnnoFix);
}
if (PropertyUtil.isSimpleSetter(setter)) {
if (annotated.isDeclaredNotNull && manager.isNullable(parameter, false)) {
final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier();
assertValidElement(setter, parameter, nameIdentifier1);
holder.registerProblem(nameIdentifier1, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.setter.parameter.conflict",
StringUtil.getShortName(anno), nullableSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
addAnnoFix);
}
else if (annotated.isDeclaredNullable && manager.isNotNull(parameter, false)) {
final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier();
assertValidElement(setter, parameter, nameIdentifier1);
holder.registerProblem(nameIdentifier1, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.setter.parameter.conflict", StringUtil.getShortName(anno), notNullSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
addAnnoFix);
}
}
}
for (PsiExpression rhs : DfaPsiUtil.findAllConstructorInitializers(field)) {
if (rhs instanceof PsiReferenceExpression) {
PsiElement target = ((PsiReferenceExpression)rhs).resolve();
if (target instanceof PsiParameter) {
PsiParameter parameter = (PsiParameter)target;
AddAnnotationPsiFix fix = new AddAnnotationPsiFix(anno, parameter, PsiNameValuePair.EMPTY_ARRAY, ArrayUtil.toStringArray(annoToRemove));
if (REPORT_NOT_ANNOTATED_GETTER && !AnnotationUtil.isAnnotated(parameter, manager.getAllAnnotations(), false, false) && !TypeConversionUtil.isPrimitiveAndNotNull(parameter.getType())) {
final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier();
assert nameIdentifier2 != null : parameter;
holder.registerProblem(nameIdentifier2, InspectionsBundle
.message("inspection.nullable.problems.annotated.field.constructor.parameter.not.annotated",
StringUtil.getShortName(anno)),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix);
continue;
}
if (annotated.isDeclaredNotNull && manager.isNullable(parameter, false)) {
final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier();
assert nameIdentifier2 != null : parameter;
holder.registerProblem(nameIdentifier2, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.constructor.parameter.conflict", StringUtil.getShortName(anno),
nullableSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
fix);
}
else if (annotated.isDeclaredNullable && manager.isNotNull(parameter, false)) {
boolean usedAsQualifier = !ReferencesSearch.search(parameter).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference reference) {
final PsiElement element = reference.getElement();
return !(element instanceof PsiReferenceExpression && element.getParent() instanceof PsiReferenceExpression);
}
});
if (!usedAsQualifier) {
final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier();
assert nameIdentifier2 != null : parameter;
holder.registerProblem(nameIdentifier2, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.constructor.parameter.conflict", StringUtil.getShortName(anno),
notNullSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
fix);
}
}
}
}
}
}
}
private void assertValidElement(PsiMethod setter, PsiParameter parameter, PsiIdentifier nameIdentifier1) {
LOG.assertTrue(nameIdentifier1 != null && nameIdentifier1.isPhysical(), setter.getText());
LOG.assertTrue(parameter.isPhysical(), setter.getText());
}
@Override public void visitParameter(PsiParameter parameter) {
if (!PsiUtil.isLanguageLevel5OrHigher(parameter)) return;
check(parameter, holder, parameter.getType());
}
};
}
private static class Annotated {
private final boolean isDeclaredNotNull;
private final boolean isDeclaredNullable;
private Annotated(final boolean isDeclaredNotNull, final boolean isDeclaredNullable) {
this.isDeclaredNotNull = isDeclaredNotNull;
this.isDeclaredNullable = isDeclaredNullable;
}
}
private static Annotated check(final PsiModifierListOwner parameter, final ProblemsHolder holder, PsiType type) {
final NullableNotNullManager manager = NullableNotNullManager.getInstance(holder.getProject());
PsiAnnotation isDeclaredNotNull = AnnotationUtil.findAnnotation(parameter, manager.getNotNulls());
PsiAnnotation isDeclaredNullable = AnnotationUtil.findAnnotation(parameter, manager.getNullables());
if (isDeclaredNullable != null && isDeclaredNotNull != null) {
reportNullableNotNullConflict(holder, parameter, isDeclaredNullable, isDeclaredNotNull);
}
if ((isDeclaredNotNull != null || isDeclaredNullable != null) && type != null && TypeConversionUtil.isPrimitive(type.getCanonicalText())) {
PsiAnnotation annotation = isDeclaredNotNull == null ? isDeclaredNullable : isDeclaredNotNull;
reportPrimitiveType(holder, annotation, annotation, parameter);
}
return new Annotated(isDeclaredNotNull != null,isDeclaredNullable != null);
}
private static void reportPrimitiveType(final ProblemsHolder holder, final PsiElement psiElement, final PsiAnnotation annotation,
final PsiModifierListOwner listOwner) {
holder.registerProblem(psiElement.isPhysical() ? psiElement : listOwner.getNavigationElement(),
InspectionsBundle.message("inspection.nullable.problems.primitive.type.annotation"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new RemoveAnnotationQuickFix(annotation, listOwner));
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("inspection.nullable.problems.display.name");
}
@Override
@NotNull
public String getGroupDisplayName() {
return GroupNames.BUGS_GROUP_NAME;
}
@Override
@NotNull
public String getShortName() {
return "NullableProblems";
}
private void checkNullableStuffForMethod(PsiMethod method, final ProblemsHolder holder) {
Annotated annotated = check(method, holder, method.getReturnType());
PsiParameter[] parameters = method.getParameterList().getParameters();
List<MethodSignatureBackedByPsiMethod> superMethodSignatures = method.findSuperMethodSignaturesIncludingStatic(true);
boolean reported_not_annotated_method_overrides_notnull = false;
boolean reported_nullable_method_overrides_notnull = false;
boolean[] reported_notnull_parameter_overrides_nullable = new boolean[parameters.length];
boolean[] reported_not_annotated_parameter_overrides_notnull = new boolean[parameters.length];
final NullableNotNullManager nullableManager = NullableNotNullManager.getInstance(holder.getProject());
for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) {
PsiMethod superMethod = superMethodSignature.getMethod();
if (!reported_nullable_method_overrides_notnull
&& REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE
&& annotated.isDeclaredNullable
&& NullableNotNullManager.isNotNull(superMethod)) {
reported_nullable_method_overrides_notnull = true;
holder.registerProblem(method.getNameIdentifier(),
InspectionsBundle.message("inspection.nullable.problems.Nullable.method.overrides.NotNull"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
if (!reported_not_annotated_method_overrides_notnull
&& REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL
&& !annotated.isDeclaredNullable
&& !annotated.isDeclaredNotNull
&& NullableNotNullManager.isNotNull(superMethod)) {
reported_not_annotated_method_overrides_notnull = true;
final String defaultNotNull = nullableManager.getDefaultNotNull();
final String[] annotationsToRemove = ArrayUtil.toStringArray(nullableManager.getNullables());
final LocalQuickFix fix = AnnotationUtil.isAnnotatingApplicable(method, defaultNotNull)
? createAnnotateMethodFix(defaultNotNull, annotationsToRemove)
: createChangeDefaultNotNullFix(nullableManager, superMethod);
holder.registerProblem(method.getNameIdentifier(),
InspectionsBundle.message("inspection.nullable.problems.method.overrides.NotNull"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
wrapFix(fix));
}
if (REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE || REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL) {
PsiParameter[] superParameters = superMethod.getParameterList().getParameters();
if (superParameters.length != parameters.length) {
continue;
}
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
PsiParameter superParameter = superParameters[i];
if (!reported_notnull_parameter_overrides_nullable[i] && REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE &&
nullableManager.isNotNull(parameter, false) &&
nullableManager.isNullable(superParameter, false)) {
reported_notnull_parameter_overrides_nullable[i] = true;
holder.registerProblem(parameter.getNameIdentifier(),
InspectionsBundle.message("inspection.nullable.problems.NotNull.parameter.overrides.Nullable"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
if (!reported_not_annotated_parameter_overrides_notnull[i] && REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL) {
if (!AnnotationUtil.isAnnotated(parameter, nullableManager.getAllAnnotations(), false, false) &&
nullableManager.isNotNull(superParameter, false)) {
reported_not_annotated_parameter_overrides_notnull[i] = true;
final LocalQuickFix fix = AnnotationUtil.isAnnotatingApplicable(parameter, nullableManager.getDefaultNotNull())
? new AddNotNullAnnotationFix(parameter)
: createChangeDefaultNotNullFix(nullableManager, superParameter);
holder.registerProblem(parameter.getNameIdentifier(),
InspectionsBundle.message("inspection.nullable.problems.parameter.overrides.NotNull"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
wrapFix(fix));
}
}
}
}
}
if (REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS) {
boolean[] parameterAnnotated = new boolean[parameters.length];
boolean[] parameterQuickFixSuggested = new boolean[parameters.length];
boolean hasAnnotatedParameter = false;
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
parameterAnnotated[i] = nullableManager.isNotNull(parameter, false);
hasAnnotatedParameter |= parameterAnnotated[i];
}
if (hasAnnotatedParameter || annotated.isDeclaredNotNull) {
PsiManager manager = method.getManager();
final String defaultNotNull = nullableManager.getDefaultNotNull();
final boolean superMethodApplicable = AnnotationUtil.isAnnotatingApplicable(method, defaultNotNull);
PsiMethod[] overridings =
OverridingMethodsSearch.search(method, GlobalSearchScope.allScope(manager.getProject()), true).toArray(PsiMethod.EMPTY_ARRAY);
boolean methodQuickFixSuggested = false;
for (PsiMethod overriding : overridings) {
if (!manager.isInProject(overriding)) continue;
final boolean applicable = AnnotationUtil.isAnnotatingApplicable(overriding, defaultNotNull);
if (!methodQuickFixSuggested
&& annotated.isDeclaredNotNull
&& !nullableManager.isNotNull(overriding, false)
&& (nullableManager.isNullable(overriding, false) || !nullableManager.isNullable(overriding, true))) {
method.getNameIdentifier(); //load tree
PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, nullableManager.getNotNulls());
final String[] annotationsToRemove = ArrayUtil.toStringArray(nullableManager.getNullables());
final LocalQuickFix fix;
if (applicable) {
fix = new MyAnnotateMethodFix(defaultNotNull, annotationsToRemove);
}
else {
fix = superMethodApplicable ? null : createChangeDefaultNotNullFix(nullableManager, method);
}
PsiElement psiElement = annotation;
if (!annotation.isPhysical()) {
psiElement = method.getNameIdentifier();
if (psiElement == null) continue;
}
holder.registerProblem(psiElement, InspectionsBundle.message("nullable.stuff.problems.overridden.methods.are.not.annotated"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
wrapFix(fix));
methodQuickFixSuggested = true;
}
if (hasAnnotatedParameter) {
PsiParameter[] psiParameters = overriding.getParameterList().getParameters();
for (int i = 0; i < psiParameters.length; i++) {
if (parameterQuickFixSuggested[i]) continue;
PsiParameter parameter = psiParameters[i];
if (parameterAnnotated[i] && !nullableManager.isNotNull(parameter, false) && !nullableManager.isNullable(parameter, false)) {
parameters[i].getNameIdentifier(); //be sure that corresponding tree element available
PsiAnnotation annotation = AnnotationUtil.findAnnotation(parameters[i], nullableManager.getNotNulls());
PsiElement psiElement = annotation;
if (!annotation.isPhysical()) {
psiElement = parameters[i].getNameIdentifier();
if (psiElement == null) continue;
}
holder.registerProblem(psiElement,
InspectionsBundle.message("nullable.stuff.problems.overridden.method.parameters.are.not.annotated"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
wrapFix(!applicable
? createChangeDefaultNotNullFix(nullableManager, parameters[i])
: new AnnotateOverriddenMethodParameterFix(defaultNotNull,
nullableManager.getDefaultNullable())));
parameterQuickFixSuggested[i] = true;
}
}
}
}
}
}
}
private static LocalQuickFix[] wrapFix(LocalQuickFix fix) {
if (fix == null) return LocalQuickFix.EMPTY_ARRAY;
return new LocalQuickFix[]{fix};
}
private static LocalQuickFix createChangeDefaultNotNullFix(NullableNotNullManager nullableManager, PsiModifierListOwner modifierListOwner) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(modifierListOwner, nullableManager.getNotNulls());
if (annotation != null) {
final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
if (referenceElement != null && referenceElement.resolve() != null) {
return new ChangeNullableDefaultsFix(annotation.getQualifiedName(), null, nullableManager);
}
}
return null;
}
protected AnnotateMethodFix createAnnotateMethodFix(final String defaultNotNull, final String[] annotationsToRemove) {
return new AnnotateMethodFix(defaultNotNull, annotationsToRemove);
}
private static void reportNullableNotNullConflict(final ProblemsHolder holder, final PsiModifierListOwner listOwner, final PsiAnnotation declaredNullable,
final PsiAnnotation declaredNotNull) {
holder.registerProblem(declaredNotNull.isPhysical() ? declaredNotNull : listOwner.getNavigationElement(),
InspectionsBundle.message("inspection.nullable.problems.Nullable.NotNull.conflict"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new RemoveAnnotationQuickFix(declaredNotNull, listOwner));
holder.registerProblem(declaredNullable.isPhysical() ? declaredNullable : listOwner.getNavigationElement(),
InspectionsBundle.message("inspection.nullable.problems.Nullable.NotNull.conflict"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new RemoveAnnotationQuickFix(declaredNullable, listOwner));
}
@Override
public JComponent createOptionsPanel() {
throw new RuntimeException("No UI in headless mode");
}
private static class MyAnnotateMethodFix extends AnnotateMethodFix {
public MyAnnotateMethodFix(String defaultNotNull, String[] annotationsToRemove) {
super(defaultNotNull, annotationsToRemove);
}
@Override
protected boolean annotateOverriddenMethods() {
return true;
}
@Override
public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) {
return 1;
}
@Override
@NotNull
public String getName() {
return InspectionsBundle.message("annotate.overridden.methods.as.notnull", ClassUtil.extractClassName(myAnnotation));
}
}
}
@@ -0,0 +1,125 @@
/*
* Copyright 2000-2009 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.wrongPackageStatement;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInspection.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* User: anna
* Date: 14-Nov-2005
*/
public class WrongPackageStatementInspectionBase extends BaseJavaBatchLocalInspectionTool {
@Override
@Nullable
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
// does not work in tests since CodeInsightTestCase copies file into temporary location
if (ApplicationManager.getApplication().isUnitTestMode()) return null;
if (file instanceof PsiJavaFile) {
if (isInJsp(file)) return null;
PsiJavaFile javaFile = (PsiJavaFile)file;
PsiDirectory directory = javaFile.getContainingDirectory();
if (directory == null) return null;
PsiPackage dirPackage = JavaDirectoryService.getInstance().getPackage(directory);
if (dirPackage == null) return null;
PsiPackageStatement packageStatement = javaFile.getPackageStatement();
// highlight the first class in the file only
PsiClass[] classes = javaFile.getClasses();
if (classes.length == 0 && packageStatement == null) return null;
String packageName = dirPackage.getQualifiedName();
if (!Comparing.strEqual(packageName, "", true) && packageStatement == null) {
String description = JavaErrorMessages.message("missing.package.statement", packageName);
return new ProblemDescriptor[]{manager.createProblemDescriptor(classes[0].getNameIdentifier(), description,
new AdjustPackageNameFix(packageName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly)};
}
if (packageStatement != null) {
final PsiJavaCodeReferenceElement packageReference = packageStatement.getPackageReference();
PsiPackage classPackage = (PsiPackage)packageReference.resolve();
List<LocalQuickFix> availableFixes = new ArrayList<LocalQuickFix>();
if (classPackage == null || !Comparing.equal(dirPackage.getQualifiedName(), packageReference.getQualifiedName(), true)) {
availableFixes.add(new AdjustPackageNameFix(packageName));
String packName = classPackage != null ? classPackage.getQualifiedName() : packageReference.getQualifiedName();
addMoveToPackageFix(file, packName, availableFixes);
}
if (!availableFixes.isEmpty()){
String description = JavaErrorMessages.message("package.name.file.path.mismatch",
packageReference.getQualifiedName(),
dirPackage.getQualifiedName());
LocalQuickFix[] fixes = availableFixes.toArray(new LocalQuickFix[availableFixes.size()]);
ProblemDescriptor descriptor =
manager.createProblemDescriptor(packageStatement.getPackageReference(), description, isOnTheFly,
fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
return new ProblemDescriptor[]{descriptor};
}
}
}
return null;
}
private static boolean isInJsp(PsiFile file) {
return PsiUtilCore.getTemplateLanguageFile(file) instanceof ServerPageFile;
}
protected void addMoveToPackageFix(PsiFile file, String packName, List<LocalQuickFix> availableFixes) {
}
@Override
@NotNull
public String getGroupDisplayName() {
return "";
}
@Override
@NotNull
public HighlightDisplayLevel getDefaultLevel() {
return HighlightDisplayLevel.ERROR;
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("wrong.package.statement");
}
@Override
@NotNull
@NonNls
public String getShortName() {
return "WrongPackageStatement";
}
@Override
public boolean isEnabledByDefault() {
return true;
}
}
@@ -30,7 +30,6 @@ import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiDiamondTypeElementImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.tree.IElementType;
@@ -203,7 +202,7 @@ public class CodeInsightUtil {
PsiElement[] children = scope.getChildren();
for (PsiElement child : children) {
if (child instanceof PsiExpression) {
if (areExpressionsEquivalent(RefactoringUtil.unparenthesizeExpression((PsiExpression)child), expr)) {
if (JavaPsiEquivalenceUtil.areExpressionsEquivalent(RefactoringUtil.unparenthesizeExpression((PsiExpression)child), expr)) {
array.add((PsiExpression)child);
continue;
}
@@ -233,30 +232,6 @@ public class CodeInsightUtil {
}
}
public static boolean areExpressionsEquivalent(PsiExpression expr1, PsiExpression expr2) {
return PsiEquivalenceUtil.areElementsEquivalent(expr1, expr2, new Comparator<PsiElement>() {
@Override
public int compare(PsiElement o1, PsiElement o2) {
if (o1 instanceof PsiParameter && o2 instanceof PsiParameter && ((PsiParameter)o1).getDeclarationScope() instanceof PsiMethod) {
return ((PsiParameter)o1).getName().compareTo(((PsiParameter)o2).getName());
}
return 1;
}
}, new Comparator<PsiElement>() {
@Override
public int compare(PsiElement o1, PsiElement o2) {
if (!o1.textMatches(o2)) return 1;
if (o1 instanceof PsiDiamondTypeElementImpl && o2 instanceof PsiDiamondTypeElementImpl) {
final PsiDiamondType.DiamondInferenceResult thisInferenceResult = new PsiDiamondTypeImpl(o1.getManager(), (PsiTypeElement)o1).resolveInferredTypes();
final PsiDiamondType.DiamondInferenceResult otherInferenceResult = new PsiDiamondTypeImpl(o2.getManager(), (PsiTypeElement)o2).resolveInferredTypes();
return thisInferenceResult.equals(otherInferenceResult) ? 0 : 1;
}
return 0;
}
}, null, false);
}
public static Editor positionCursor(final Project project, PsiFile targetFile, PsiElement element) {
TextRange range = element.getTextRange();
int textOffset = range.getStartOffset();
@@ -15,8 +15,8 @@
*/
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.JavaPsiEquivalenceUtil;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementWeigher;
import com.intellij.openapi.util.Comparing;
@@ -79,7 +79,7 @@ class RecursionWeigher extends LookupElementWeigher {
if (myCallQualifier != null &&
myPositionQualifier != null &&
myCallQualifier != myPositionQualifier &&
CodeInsightUtil.areExpressionsEquivalent(myCallQualifier, myPositionQualifier)) {
JavaPsiEquivalenceUtil.areExpressionsEquivalent(myCallQualifier, myPositionQualifier)) {
return false;
}
@@ -162,7 +162,7 @@ class RecursionWeigher extends LookupElementWeigher {
return Result.normal;
}
@Nullable
@Nullable
private String getSetterPropertyName(@Nullable PsiMethod calledMethod) {
if (PropertyUtil.isSimplePropertySetter(calledMethod)) {
assert calledMethod != null;
@@ -21,8 +21,6 @@ import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.highlighting.HighlightManager;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
@@ -96,7 +94,7 @@ public class AccessStaticViaInstanceFix extends LocalQuickFixAndIntentionActionO
final PsiExpression qualifierExpression = myExpression.getQualifierExpression();
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
if (qualifierExpression != null) {
if (!checkSideEffects(project, containingClass, qualifierExpression, factory, myExpression)) return;
if (!checkSideEffects(project, containingClass, qualifierExpression, factory, myExpression,editor)) return;
PsiElement newQualifier = qualifierExpression.replace(factory.createReferenceExpression(containingClass));
PsiElement qualifiedWithClassName = myExpression.copy();
newQualifier.delete();
@@ -110,69 +108,71 @@ public class AccessStaticViaInstanceFix extends LocalQuickFixAndIntentionActionO
}
}
private boolean checkSideEffects(final Project project, PsiClass containingClass, final PsiExpression qualifierExpression,
PsiElementFactory factory, final PsiElement myExpression) {
private boolean checkSideEffects(final Project project,
PsiClass containingClass,
final PsiExpression qualifierExpression,
PsiElementFactory factory,
final PsiElement myExpression,
Editor editor) {
final List<PsiElement> sideEffects = new ArrayList<PsiElement>();
boolean hasSideEffects = RemoveUnusedVariableUtil.checkSideEffects(qualifierExpression, null, sideEffects);
if (hasSideEffects && !myOnTheFly) return false;
if (hasSideEffects && !ApplicationManager.getApplication().isUnitTestMode()) {
final TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
final Editor editor = PlatformDataKeys.EDITOR.getData(DataManager.getInstance().getDataContext());
if (editor == null) {
return false;
}
HighlightManager.getInstance(project).addOccurrenceHighlights(editor, PsiUtilCore.toPsiElementArray(sideEffects), attributes, true,
null);
try {
hasSideEffects = PsiUtil.isStatement(factory.createStatementFromText(qualifierExpression.getText(), qualifierExpression));
}
catch (IncorrectOperationException e) {
hasSideEffects = false;
}
final PsiReferenceExpression qualifiedWithClassName = (PsiReferenceExpression)myExpression.copy();
qualifiedWithClassName.setQualifierExpression(factory.createReferenceExpression(containingClass));
final boolean canCopeWithSideEffects = hasSideEffects;
final SideEffectWarningDialog dialog =
new SideEffectWarningDialog(project, false, null, sideEffects.get(0).getText(), PsiExpressionTrimRenderer.render(qualifierExpression),
canCopeWithSideEffects){
@Override
protected String sideEffectsDescription() {
if (canCopeWithSideEffects) {
return "<html><body>" +
" There are possible side effects found in expression '" +
qualifierExpression.getText() +
"'<br>" +
" You can:<ul><li><b>Remove</b> class reference along with whole expressions involved, or</li>" +
" <li><b>Transform</b> qualified expression into the statement on its own.<br>" +
" That is,<br>" +
" <table border=1><tr><td><code>" +
myExpression.getText() +
"</code></td></tr></table><br> becomes: <br>" +
" <table border=1><tr><td><code>" +
qualifierExpression.getText() +
";<br>" +
qualifiedWithClassName.getText() +
" </code></td></tr></table></li>" +
" </body></html>";
} else {
return "<html><body> There are possible side effects found in expression '" + qualifierExpression.getText() + "'<br>" +
"You can:<ul><li><b>Remove</b> class reference along with whole expressions involved, or</li></body></html>";
}
if (!hasSideEffects || ApplicationManager.getApplication().isUnitTestMode()) {
return true;
}
if (editor == null) {
return false;
}
TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
HighlightManager.getInstance(project).addOccurrenceHighlights(editor, PsiUtilCore.toPsiElementArray(sideEffects), attributes, true, null);
try {
hasSideEffects = PsiUtil.isStatement(factory.createStatementFromText(qualifierExpression.getText(), qualifierExpression));
}
catch (IncorrectOperationException e) {
hasSideEffects = false;
}
final PsiReferenceExpression qualifiedWithClassName = (PsiReferenceExpression)myExpression.copy();
qualifiedWithClassName.setQualifierExpression(factory.createReferenceExpression(containingClass));
final boolean canCopeWithSideEffects = hasSideEffects;
final SideEffectWarningDialog dialog =
new SideEffectWarningDialog(project, false, null, sideEffects.get(0).getText(), PsiExpressionTrimRenderer.render(qualifierExpression),
canCopeWithSideEffects){
@Override
protected String sideEffectsDescription() {
if (canCopeWithSideEffects) {
return "<html><body>" +
" There are possible side effects found in expression '" +
qualifierExpression.getText() +
"'<br>" +
" You can:<ul><li><b>Remove</b> class reference along with whole expressions involved, or</li>" +
" <li><b>Transform</b> qualified expression into the statement on its own.<br>" +
" That is,<br>" +
" <table border=1><tr><td><code>" +
myExpression.getText() +
"</code></td></tr></table><br> becomes: <br>" +
" <table border=1><tr><td><code>" +
qualifierExpression.getText() +
";<br>" +
qualifiedWithClassName.getText() +
" </code></td></tr></table></li>" +
" </body></html>";
}
};
dialog.show();
int res = dialog.getExitCode();
if (res == RemoveUnusedVariableUtil.CANCEL) return false;
try {
if (res == RemoveUnusedVariableUtil.MAKE_STATEMENT) {
final PsiStatement statementFromText = factory.createStatementFromText(qualifierExpression.getText() + ";", null);
final PsiStatement statement = PsiTreeUtil.getParentOfType(myExpression, PsiStatement.class);
statement.getParent().addBefore(statementFromText, statement);
return "<html><body> There are possible side effects found in expression '" + qualifierExpression.getText() + "'<br>" +
"You can:<ul><li><b>Remove</b> class reference along with whole expressions involved, or</li></body></html>";
}
};
dialog.show();
int res = dialog.getExitCode();
if (res == RemoveUnusedVariableUtil.CANCEL) return false;
try {
if (res == RemoveUnusedVariableUtil.MAKE_STATEMENT) {
final PsiStatement statementFromText = factory.createStatementFromText(qualifierExpression.getText() + ";", null);
final PsiStatement statement = PsiTreeUtil.getParentOfType(myExpression, PsiStatement.class);
statement.getParent().addBefore(statementFromText, statement);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
return true;
}
@@ -39,7 +39,7 @@ public class SimplifyBooleanExpressionAction implements IntentionAction{
@Override
@NotNull
public String getFamilyName() {
return new SimplifyBooleanExpressionFix(null,null).getFamilyName();
return SimplifyBooleanExpressionFix.FAMILY_NAME;
}
@Override
@@ -99,10 +99,4 @@ public class MoveToPackageFix implements LocalQuickFix {
LOG.error(e);
}
}
public boolean startInWriteAction() {
return false;
}
}
@@ -60,7 +60,7 @@ public class SurroundWithIfFix implements LocalQuickFix {
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
PsiElement[] elements = {anchorStatement};
PsiElement prev = PsiTreeUtil.skipSiblingsBackward(anchorStatement, PsiWhiteSpace.class);
if (prev instanceof PsiComment && SuppressManager.getInstance().getSuppressedInspectionIdsIn(prev) != null) {
if (prev instanceof PsiComment && JavaSuppressionUtil.getSuppressedInspectionIdsIn(prev) != null) {
elements = new PsiElement[]{prev, anchorStatement};
}
try {
@@ -15,91 +15,19 @@
*/
package com.intellij.codeInspection.accessStaticViaInstance;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil;
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
import com.intellij.codeInsight.daemon.impl.quickfix.AccessStaticViaInstanceFix;
import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil;
import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import com.intellij.psi.JavaResolveResult;
import com.intellij.psi.PsiReferenceExpression;
/**
* User: anna
* Date: 15-Nov-2005
*/
public class AccessStaticViaInstance extends BaseJavaBatchLocalInspectionTool {
public static final String ACCESS_STATIC_VIA_INSTANCE = "AccessStaticViaInstance";
public class AccessStaticViaInstance extends AccessStaticViaInstanceBase {
@Override
@NotNull
public String getGroupDisplayName() {
return "";
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("access.static.via.instance");
}
@Override
@NotNull
@NonNls
public String getShortName() {
return ACCESS_STATIC_VIA_INSTANCE;
}
@Override
public String getAlternativeID() {
return "static-access";
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
checkAccessStaticMemberViaInstanceReference(expression, holder, isOnTheFly);
}
};
}
private static void checkAccessStaticMemberViaInstanceReference(PsiReferenceExpression expr, ProblemsHolder holder, boolean onTheFly) {
JavaResolveResult result = expr.advancedResolve(false);
PsiElement resolved = result.getElement();
if (!(resolved instanceof PsiMember)) return;
PsiExpression qualifierExpression = expr.getQualifierExpression();
if (qualifierExpression == null) return;
if (qualifierExpression instanceof PsiReferenceExpression) {
final PsiElement qualifierResolved = ((PsiReferenceExpression)qualifierExpression).resolve();
if (qualifierResolved instanceof PsiClass || qualifierResolved instanceof PsiPackage) {
return;
}
}
if (!((PsiMember)resolved).hasModifierProperty(PsiModifier.STATIC)) return;
String description = JavaErrorMessages.message("static.member.accessed.via.instance.reference",
JavaHighlightUtil.formatType(qualifierExpression.getType()),
HighlightMessageUtil.getSymbolName(resolved, result.getSubstitutor()));
if (!onTheFly) {
if (RemoveUnusedVariableUtil.checkSideEffects(qualifierExpression, null, new ArrayList<PsiElement>())) {
holder.registerProblem(expr, description);
return;
}
}
holder.registerProblem(expr, description, new AccessStaticViaInstanceFix(expr, result, onTheFly));
protected AccessStaticViaInstanceFix createAccessStaticViaInstanceFix(PsiReferenceExpression expr,
boolean onTheFly,
JavaResolveResult result) {
return new AccessStaticViaInstanceFix(expr, result, onTheFly);
}
}
@@ -46,13 +46,13 @@ import java.util.List;
*/
public class ConditionCheckDialog extends DialogWrapper {
private final Project myProject;
private final @NotNull Splitter mainSplitter;
private final @NotNull MethodsPanel myIsNullCheckMethodPanel;
private final @NotNull MethodsPanel myIsNotNullCheckMethodPanel;
private final @NotNull MethodsPanel myAssertIsNullMethodPanel;
private final @NotNull MethodsPanel myAssertIsNotNullMethodPanel;
private final @NotNull MethodsPanel myAssertTrueMethodPanel;
private final @NotNull MethodsPanel myAssertFalseMethodPanel;
@NotNull private final Splitter mainSplitter;
@NotNull private final MethodsPanel myIsNullCheckMethodPanel;
@NotNull private final MethodsPanel myIsNotNullCheckMethodPanel;
@NotNull private final MethodsPanel myAssertIsNullMethodPanel;
@NotNull private final MethodsPanel myAssertIsNotNullMethodPanel;
@NotNull private final MethodsPanel myAssertTrueMethodPanel;
@NotNull private final MethodsPanel myAssertFalseMethodPanel;
public ConditionCheckDialog(Project project, String mainDialogTitle) {
super(project, true);
@@ -140,12 +140,12 @@ public class ConditionCheckDialog extends DialogWrapper {
* Is Null, Is Not Null, Assert True and Assert False Method Panel at the top of the main Dialog.
*/
class MethodsPanel {
private final @NotNull JBList myList;
private final @NotNull JPanel myPanel;
private final @NotNull Project myProject;
@NotNull private final JBList myList;
@NotNull private final JPanel myPanel;
@NotNull private final Project myProject;
private Set<MethodsPanel> otherPanels;
public MethodsPanel(final List<ConditionChecker> checkers, final ConditionChecker.Type type, final @NotNull Project myProject) {
public MethodsPanel(final List<ConditionChecker> checkers, final ConditionChecker.Type type, @NotNull final Project myProject) {
this.myProject = myProject;
myList = new JBList(new CollectionListModel<ConditionChecker>(checkers));
myPanel = new JPanel(new BorderLayout());
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* 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.
@@ -13,43 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created by IntelliJ IDEA.
* User: max
* Date: Dec 24, 2001
* Time: 2:46:32 PM
* To change template for new class use
* Code Style | Class Templates options (Tools | IDE Options).
*/
package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.NullableNotNullDialog;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.daemon.impl.quickfix.SimplifyBooleanExpressionFix;
import com.intellij.codeInsight.intention.impl.AddNullableAnnotationFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.SurroundWithIfFix;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.psi.PsiExpression;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
@@ -57,497 +31,20 @@ import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
public class DataFlowInspection extends BaseLocalInspectionTool {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.DataFlowInspection");
@NonNls private static final String SHORT_NAME = "ConstantConditions";
public boolean SUGGEST_NULLABLE_ANNOTATIONS = false;
public boolean DONT_REPORT_TRUE_ASSERT_STATEMENTS = false;
public class DataFlowInspection extends DataFlowInspectionBase {
@Override
protected void addSurroundWithIfFix(PsiExpression qualifier, List<LocalQuickFix> fixes) {
if (SurroundWithIfFix.isAvailable(qualifier)) {
fixes.add(new SurroundWithIfFix(qualifier));
}
}
@Override
public JComponent createOptionsPanel() {
return new OptionsPanel();
}
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override
public void visitField(PsiField field) {
analyzeCodeBlock(field, holder);
}
@Override
public void visitMethod(PsiMethod method) {
analyzeCodeBlock(method.getBody(), holder);
}
@Override
public void visitClassInitializer(PsiClassInitializer initializer) {
analyzeCodeBlock(initializer.getBody(), holder);
}
};
}
private void analyzeCodeBlock(@Nullable final PsiElement scope, ProblemsHolder holder) {
if (scope == null) return;
final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner(SUGGEST_NULLABLE_ANNOTATIONS);
final StandardInstructionVisitor visitor = new DataFlowInstructionVisitor(dfaRunner);
final RunnerResult rc = dfaRunner.analyzeMethod(scope, visitor);
if (rc == RunnerResult.OK) {
if (dfaRunner.problemsDetected(visitor)) {
createDescription(dfaRunner, holder, visitor);
}
}
else if (rc == RunnerResult.TOO_COMPLEX) {
if (scope.getParent() instanceof PsiMethod) {
PsiMethod method = (PsiMethod)scope.getParent();
final PsiIdentifier name = method.getNameIdentifier();
if (name != null) { // Might be null for synthetic methods like JSP page.
holder.registerProblem(name, InspectionsBundle.message("dataflow.too.complex"), ProblemHighlightType.WEAK_WARNING);
}
}
}
}
@Nullable
private static LocalQuickFix[] createNPEFixes(PsiExpression qualifier, PsiExpression expression) {
if (qualifier == null || expression == null) return null;
if (qualifier instanceof PsiMethodCallExpression) return null;
if (qualifier instanceof PsiLiteralExpression && ((PsiLiteralExpression)qualifier).getValue() == null) return null;
try {
final List<LocalQuickFix> fixes = new SmartList<LocalQuickFix>();
if (PsiUtil.getLanguageLevel(qualifier).isAtLeast(LanguageLevel.JDK_1_4)) {
final Project project = qualifier.getProject();
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
final PsiBinaryExpression binary = (PsiBinaryExpression)elementFactory.createExpressionFromText("a != null", null);
binary.getLOperand().replace(qualifier);
fixes.add(new AddAssertStatementFix(binary));
}
if (SurroundWithIfFix.isAvailable(qualifier)) {
fixes.add(new SurroundWithIfFix(qualifier));
}
if (ReplaceWithTernaryOperatorFix.isAvailable(qualifier, expression)) {
fixes.add(new ReplaceWithTernaryOperatorFix(qualifier));
}
return fixes.toArray(new LocalQuickFix[fixes.size()]);
}
catch (IncorrectOperationException e) {
LOG.error(e);
return null;
}
}
private void createDescription(StandardDataFlowRunner runner, ProblemsHolder holder, StandardInstructionVisitor visitor) {
Pair<Set<Instruction>, Set<Instruction>> constConditions = runner.getConstConditionalExpressions();
Set<Instruction> trueSet = constConditions.getFirst();
Set<Instruction> falseSet = constConditions.getSecond();
ArrayList<Instruction> allProblems = new ArrayList<Instruction>();
allProblems.addAll(trueSet);
allProblems.addAll(falseSet);
allProblems.addAll(runner.getNPEInstructions());
allProblems.addAll(runner.getCCEInstructions());
allProblems.addAll(StandardDataFlowRunner.getRedundantInstanceofs(runner, visitor));
Collections.sort(allProblems, new Comparator<Instruction>() {
@Override
public int compare(Instruction i1, Instruction i2) {
return i1.getIndex() - i2.getIndex();
}
});
HashSet<PsiElement> reportedAnchors = new HashSet<PsiElement>();
for (Instruction instruction : allProblems) {
if (instruction instanceof MethodCallInstruction) {
reportCallMayProduceNpe(holder, (MethodCallInstruction)instruction);
}
else if (instruction instanceof FieldReferenceInstruction) {
reportFieldAccessMayProduceNpe(holder, (FieldReferenceInstruction)instruction);
}
else if (instruction instanceof TypeCastInstruction) {
reportCastMayFail(holder, (TypeCastInstruction)instruction);
}
else if (instruction instanceof BranchingInstruction) {
handleBranchingInstruction(holder, visitor, trueSet, falseSet, reportedAnchors, (BranchingInstruction)instruction);
}
}
reportNullableArguments(runner, holder);
reportNullableAssignments(runner, holder);
reportUnboxedNullables(runner, holder);
reportNullableReturns(runner, holder);
reportNullableArgumentsPassedToNonAnnotated(runner, holder);
}
private static void reportNullableArgumentsPassedToNonAnnotated(StandardDataFlowRunner runner, ProblemsHolder holder) {
Set<PsiExpression> exprs = runner.getNullableArgumentsPassedToNonAnnotatedParam();
for (PsiExpression expr : exprs) {
final String text = isNullLiteralExpression(expr)
? "Passing <code>null</code> argument to non annotated parameter"
: "Argument <code>#ref</code> #loc might be null but passed to non annotated parameter";
LocalQuickFix[] fixes = createNPEFixes(expr, expr);
final PsiElement parent = expr.getParent();
if (parent instanceof PsiExpressionList) {
final int idx = ArrayUtil.find(((PsiExpressionList)parent).getExpressions(), expr);
if (idx > -1) {
final PsiElement gParent = parent.getParent();
if (gParent instanceof PsiCallExpression) {
final PsiMethod psiMethod = ((PsiCallExpression)gParent).resolveMethod();
if (psiMethod != null && psiMethod.getManager().isInProject(psiMethod) && AnnotationUtil.isAnnotatingApplicable(psiMethod)) {
final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
if (idx < parameters.length) {
final AddNullableAnnotationFix addNullableAnnotationFix = new AddNullableAnnotationFix(parameters[idx]);
fixes = fixes == null ? new LocalQuickFix[]{addNullableAnnotationFix} : ArrayUtil.append(fixes, addNullableAnnotationFix);
holder.registerProblem(expr, text, fixes);
}
}
}
}
}
}
}
private static void reportCallMayProduceNpe(ProblemsHolder holder, MethodCallInstruction mcInstruction) {
if (mcInstruction.getCallExpression() instanceof PsiMethodCallExpression) {
PsiMethodCallExpression callExpression = (PsiMethodCallExpression)mcInstruction.getCallExpression();
LocalQuickFix[] fix = createNPEFixes(callExpression.getMethodExpression().getQualifierExpression(), callExpression);
holder.registerProblem(callExpression,
InspectionsBundle.message("dataflow.message.npe.method.invocation"),
fix);
}
}
private static void reportFieldAccessMayProduceNpe(ProblemsHolder holder, FieldReferenceInstruction frInstruction) {
PsiElement elementToAssert = frInstruction.getElementToAssert();
PsiExpression expression = frInstruction.getExpression();
if (expression instanceof PsiArrayAccessExpression) {
LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression);
holder.registerProblem(expression,
InspectionsBundle.message("dataflow.message.npe.array.access"),
fix);
}
else {
LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression);
holder.registerProblem(elementToAssert,
InspectionsBundle.message("dataflow.message.npe.field.access"),
fix);
}
}
private static void reportCastMayFail(ProblemsHolder holder, TypeCastInstruction instruction) {
PsiTypeCastExpression typeCast = instruction.getCastExpression();
holder.registerProblem(typeCast.getCastType(),
InspectionsBundle.message("dataflow.message.cce", typeCast.getOperand().getText()));
}
private void handleBranchingInstruction(ProblemsHolder holder,
StandardInstructionVisitor visitor,
Set<Instruction> trueSet,
Set<Instruction> falseSet, HashSet<PsiElement> reportedAnchors, BranchingInstruction instruction) {
PsiElement psiAnchor = instruction.getPsiAnchor();
boolean underBinary = isAtRHSOfBooleanAnd(psiAnchor);
if (instruction instanceof InstanceofInstruction && visitor.isInstanceofRedundant((InstanceofInstruction)instruction)) {
if (visitor.canBeNull((BinopInstruction)instruction)) {
holder.registerProblem(psiAnchor,
InspectionsBundle.message("dataflow.message.redundant.instanceof"),
new RedundantInstanceofFix());
}
else {
final LocalQuickFix localQuickFix = createSimplifyBooleanExpressionFix(psiAnchor, true);
holder.registerProblem(psiAnchor,
InspectionsBundle.message(underBinary ? "dataflow.message.constant.condition.when.reached" : "dataflow.message.constant.condition", Boolean.toString(true)),
localQuickFix == null ? null : new LocalQuickFix[]{localQuickFix});
}
}
else if (psiAnchor instanceof PsiSwitchLabelStatement) {
if (falseSet.contains(instruction)) {
holder.registerProblem(psiAnchor,
InspectionsBundle.message("dataflow.message.unreachable.switch.label"));
}
}
else if (psiAnchor != null && !reportedAnchors.contains(psiAnchor) && !isCompileConstantInIfCondition(psiAnchor)) {
boolean evaluatesToTrue = trueSet.contains(instruction);
if (onTheLeftSideOfConditionalAssignemnt(psiAnchor)) {
holder.registerProblem(
psiAnchor,
InspectionsBundle.message("dataflow.message.pointless.assignment.expression", Boolean.toString(evaluatesToTrue)),
createSimplifyToAssignmentFix()
);
}
else if (!skipReportingConstantCondition(visitor, psiAnchor, evaluatesToTrue)) {
final LocalQuickFix fix = createSimplifyBooleanExpressionFix(psiAnchor, evaluatesToTrue);
String message = InspectionsBundle.message(underBinary ?
"dataflow.message.constant.condition.when.reached" :
"dataflow.message.constant.condition", Boolean.toString(evaluatesToTrue));
holder.registerProblem(psiAnchor, message, fix == null ? null : new LocalQuickFix[]{fix});
}
reportedAnchors.add(psiAnchor);
}
}
private boolean skipReportingConstantCondition(StandardInstructionVisitor visitor, PsiElement psiAnchor, boolean evaluatesToTrue) {
return DONT_REPORT_TRUE_ASSERT_STATEMENTS && isAssertionEffectively(psiAnchor, evaluatesToTrue) ||
visitor.silenceConstantCondition(psiAnchor);
}
private static void reportNullableArguments(StandardDataFlowRunner runner, ProblemsHolder holder) {
Set<PsiExpression> exprs = runner.getNullableArguments();
for (PsiExpression expr : exprs) {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.passing.null.argument")
: InspectionsBundle.message("dataflow.message.passing.nullable.argument");
LocalQuickFix[] fixes = createNPEFixes(expr, expr);
holder.registerProblem(expr, text, fixes);
}
}
private static void reportNullableAssignments(StandardDataFlowRunner runner, ProblemsHolder holder) {
for (PsiExpression expr : runner.getNullableAssignments()) {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.assigning.null")
: InspectionsBundle.message("dataflow.message.assigning.nullable");
holder.registerProblem(expr, text);
}
}
private static void reportUnboxedNullables(StandardDataFlowRunner runner, ProblemsHolder holder) {
for (PsiExpression expr : runner.getUnboxedNullables()) {
holder.registerProblem(expr, InspectionsBundle.message("dataflow.message.unboxing"));
}
}
private static void reportNullableReturns(StandardDataFlowRunner runner, ProblemsHolder holder) {
for (PsiReturnStatement statement : runner.getNullableReturns()) {
final PsiExpression expr = statement.getReturnValue();
if (runner.isInNotNullMethod()) {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.return.null.from.notnull")
: InspectionsBundle.message("dataflow.message.return.nullable.from.notnull");
holder.registerProblem(expr, text);
}
else if (AnnotationUtil.isAnnotatingApplicable(statement)) {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.return.null.from.notnullable")
: InspectionsBundle.message("dataflow.message.return.nullable.from.notnullable");
final NullableNotNullManager manager = NullableNotNullManager.getInstance(expr.getProject());
holder.registerProblem(expr, text, new AnnotateMethodFix(manager.getDefaultNullable(), ArrayUtil.toStringArray(manager.getNotNulls())));
}
}
}
private static boolean isAssertionEffectively(PsiElement psiAnchor, boolean evaluatesToTrue) {
PsiElement parent = psiAnchor.getParent();
if (parent instanceof PsiAssertStatement) {
return evaluatesToTrue;
}
if (parent instanceof PsiIfStatement && psiAnchor == ((PsiIfStatement)parent).getCondition()) {
PsiStatement thenBranch = ((PsiIfStatement)parent).getThenBranch();
if (thenBranch instanceof PsiThrowStatement) {
return !evaluatesToTrue;
}
if (thenBranch instanceof PsiBlockStatement) {
PsiStatement[] statements = ((PsiBlockStatement)thenBranch).getCodeBlock().getStatements();
if (statements.length == 1 && statements[0] instanceof PsiThrowStatement) {
return !evaluatesToTrue;
}
}
}
return false;
}
private static boolean isAtRHSOfBooleanAnd(PsiElement expr) {
PsiElement cur = expr;
while (cur != null && !(cur instanceof PsiMember)) {
PsiElement parent = cur.getParent();
if (parent instanceof PsiBinaryExpression && cur == ((PsiBinaryExpression)parent).getROperand()) {
return true;
}
cur = parent;
}
return false;
}
private static boolean isCompileConstantInIfCondition(PsiElement element) {
if (!(element instanceof PsiReferenceExpression)) return false;
PsiElement resolved = ((PsiReferenceExpression)element).resolve();
if (!(resolved instanceof PsiField)) return false;
PsiField field = (PsiField)resolved;
if (!field.hasModifierProperty(PsiModifier.FINAL)) return false;
if (!field.hasModifierProperty(PsiModifier.STATIC)) return false;
PsiElement parent = element.getParent();
if (parent instanceof PsiPrefixExpression && ((PsiPrefixExpression)parent).getOperationTokenType() == JavaTokenType.EXCL) {
element = parent;
parent = parent.getParent();
}
return parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getCondition() == element;
}
private static boolean isNullLiteralExpression(PsiExpression expr) {
if (expr instanceof PsiLiteralExpression) {
final PsiLiteralExpression literalExpression = (PsiLiteralExpression)expr;
return PsiType.NULL.equals(literalExpression.getType());
}
return false;
}
private static boolean onTheLeftSideOfConditionalAssignemnt(final PsiElement psiAnchor) {
final PsiElement parent = psiAnchor.getParent();
if (parent instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression expression = (PsiAssignmentExpression)parent;
if (expression.getLExpression() == psiAnchor) return true;
}
return false;
}
@Nullable
private static LocalQuickFix createSimplifyBooleanExpressionFix(PsiElement element, final boolean value) {
SimplifyBooleanExpressionFix fix = createIntention(element, value);
if (fix == null) return null;
final String text = fix.getText();
return new LocalQuickFix() {
@Override
@NotNull
public String getName() {
return text;
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement psiElement = descriptor.getPsiElement();
if (psiElement == null) return;
final SimplifyBooleanExpressionFix fix = createIntention(psiElement, value);
if (fix == null) return;
try {
LOG.assertTrue(psiElement.isValid());
fix.invoke(project, null, psiElement.getContainingFile());
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
@Override
@NotNull
public String getFamilyName() {
return InspectionsBundle.message("inspection.data.flow.simplify.boolean.expression.quickfix");
}
};
}
@NotNull
private static LocalQuickFix createSimplifyToAssignmentFix() {
return new LocalQuickFix() {
@NotNull
@Override
public String getName() {
return InspectionsBundle.message("inspection.data.flow.simplify.to.assignment.quickfix.name");
}
@NotNull
@Override
public String getFamilyName() {
return InspectionsBundle.message("inspection.data.flow.simplify.boolean.expression.quickfix");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement psiElement = descriptor.getPsiElement();
if (psiElement == null) return;
final PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(psiElement, PsiAssignmentExpression.class);
if (assignmentExpression == null) {
return;
}
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final String lExpressionText = assignmentExpression.getLExpression().getText();
final PsiExpression rExpression = assignmentExpression.getRExpression();
final String rExpressionText = rExpression != null ? rExpression.getText() : "";
assignmentExpression.replace(factory.createExpressionFromText(lExpressionText + " = " + rExpressionText, psiElement));
}
};
}
private static SimplifyBooleanExpressionFix createIntention(PsiElement element, boolean value) {
if (!(element instanceof PsiExpression)) return null;
final PsiExpression expression = (PsiExpression)element;
while (element.getParent() instanceof PsiExpression) {
element = element.getParent();
}
final SimplifyBooleanExpressionFix fix = new SimplifyBooleanExpressionFix(expression, value);
// simplify intention already active
if (!fix.isAvailable(element.getProject(), null, element.getContainingFile()) ||
SimplifyBooleanExpressionFix.canBeSimplified((PsiExpression)element)) {
return null;
}
return fix;
}
private static class RedundantInstanceofFix implements LocalQuickFix {
@Override
@NotNull
public String getName() {
return InspectionsBundle.message("inspection.data.flow.redundant.instanceof.quickfix");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(descriptor.getPsiElement())) return;
final PsiElement psiElement = descriptor.getPsiElement();
if (psiElement instanceof PsiInstanceOfExpression) {
try {
final PsiExpression compareToNull = JavaPsiFacade.getInstance(psiElement.getProject()).getElementFactory().
createExpressionFromText(((PsiInstanceOfExpression)psiElement).getOperand().getText() + " != null", psiElement.getParent());
psiElement.replace(compareToNull);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
@Override
@NotNull
public String getFamilyName() {
return getName();
}
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("inspection.data.flow.display.name");
}
@Override
@NotNull
public String getGroupDisplayName() {
return GroupNames.BUGS_GROUP_NAME;
}
@Override
@NotNull
public String getShortName() {
return SHORT_NAME;
}
private class OptionsPanel extends JPanel {
private final JCheckBox mySuggestNullables;
private final JCheckBox myDontReportTrueAsserts;
@@ -627,47 +124,4 @@ public class DataFlowInspection extends BaseLocalInspectionTool {
}
}
private static class DataFlowInstructionVisitor extends StandardInstructionVisitor {
private final StandardDataFlowRunner myRunner;
private DataFlowInstructionVisitor(StandardDataFlowRunner runner) {
myRunner = runner;
}
@Override
protected void onAssigningToNotNullableVariable(AssignInstruction instruction) {
myRunner.onAssigningToNotNullableVariable(instruction.getRExpression());
}
@Override
protected void onNullableReturn(CheckReturnValueInstruction instruction) {
myRunner.onNullableReturn(instruction.getReturn());
}
@Override
protected void onInstructionProducesCCE(TypeCastInstruction instruction) {
myRunner.onInstructionProducesCCE(instruction);
}
@Override
protected void onInstructionProducesNPE(Instruction instruction) {
if (instruction instanceof MethodCallInstruction &&
((MethodCallInstruction)instruction).getMethodType() == MethodCallInstruction.MethodType.UNBOXING) {
myRunner.onUnboxingNullable(((MethodCallInstruction)instruction).getContext());
}
else {
myRunner.onInstructionProducesNPE(instruction);
}
}
@Override
protected void onPassingNullParameter(PsiExpression arg) {
myRunner.onPassingNullParameter(arg);
}
@Override
protected void onPassingNullParameterToNonAnnotated(DataFlowRunner runner, PsiExpression arg) {
myRunner.onPassingNullParameterToNonAnnotated(arg);
}
}
}
@@ -39,17 +39,17 @@ import static com.intellij.codeInsight.ConditionChecker.Type.*;
* Dialog that appears when the user clicks the Add Button or double clicks a row item in a MethodsPanel. The MethodsPanel is accessed from the ConditionCheckDialog
*/
class MethodCheckerDetailsDialog extends DialogWrapper implements PropertyChangeListener, ItemListener {
private final @NotNull ConditionChecker.Type myType;
private final @NotNull Project myProject;
private final @NotNull ParameterDropDown parameterDropDown;
private final @NotNull MethodDropDown methodDropDown;
private final @NotNull ClassField classField;
private final @NotNull Set<ConditionChecker> myOtherCheckers;
private final @Nullable ConditionChecker myPreviouslySelectedChecker;
@NotNull private final ConditionChecker.Type myType;
@NotNull private final Project myProject;
@NotNull private final ParameterDropDown parameterDropDown;
@NotNull private final MethodDropDown methodDropDown;
@NotNull private final ClassField classField;
@NotNull private final Set<ConditionChecker> myOtherCheckers;
@Nullable private final ConditionChecker myPreviouslySelectedChecker;
/**
* Set by the OK and/or Cancel actions so that the caller can retrieve it via a call to getMethodIsNullIsNotNullChecker
*/
private @Nullable ConditionChecker mySelectedChecker;
@Nullable private ConditionChecker mySelectedChecker;
MethodCheckerDetailsDialog(@Nullable ConditionChecker previouslySelectedChecker,
@NotNull ConditionChecker.Type type,
@@ -263,8 +263,8 @@ class MethodCheckerDetailsDialog extends DialogWrapper implements PropertyChange
*/
static class ClassField extends EditorTextFieldWithBrowseButton implements ActionListener, DocumentListener {
public static final String PROPERTY_PSICLASS = "ClassField.myPsiClass";
private final @NotNull Project myProject;
private @Nullable PsiClass myPsiClass;
@NotNull private final Project myProject;
@Nullable private PsiClass myPsiClass;
public ClassField(@NotNull Project project, @Nullable PsiClass psiClass) {
super(project, true, buildVisibilityChecker());
@@ -341,9 +341,9 @@ class MethodCheckerDetailsDialog extends DialogWrapper implements PropertyChange
* Drop Down for picking Method Name
*/
static class MethodDropDown extends JComboBox implements PropertyChangeListener {
private final @NotNull ConditionChecker.Type myType;
private final @NotNull SortedComboBoxModel<MethodWrapper> myModel;
private @Nullable PsiClass myPsiClass;
@NotNull private final ConditionChecker.Type myType;
@NotNull private final SortedComboBoxModel<MethodWrapper> myModel;
@Nullable private PsiClass myPsiClass;
MethodDropDown(@Nullable PsiClass psiClass,
@Nullable PsiMethod psiMethod,
@@ -478,9 +478,9 @@ class MethodCheckerDetailsDialog extends DialogWrapper implements PropertyChange
* Drop Down for picking Parameter Name
*/
static class ParameterDropDown extends JComboBox implements PropertyChangeListener, ItemListener {
private final @NotNull SortedComboBoxModel<ParameterWrapper> myModel;
private final @NotNull ConditionChecker.Type myType;
private @Nullable PsiMethod myPsiMethod;
@NotNull private final SortedComboBoxModel<ParameterWrapper> myModel;
@NotNull private final ConditionChecker.Type myType;
@Nullable private PsiMethod myPsiMethod;
public ParameterDropDown(@Nullable PsiMethod psiMethod,
@Nullable PsiParameter psiParameter,
@@ -582,8 +582,8 @@ class MethodCheckerDetailsDialog extends DialogWrapper implements PropertyChange
}
class ParameterWrapper implements Comparable<ParameterWrapper> {
private final @NotNull String id;
private final @NotNull PsiParameter psiParameter;
@NotNull private final String id;
@NotNull private final PsiParameter psiParameter;
private final int index;
ParameterWrapper(@NotNull PsiParameter psiParameter, int index) {
@@ -624,8 +624,8 @@ class MethodCheckerDetailsDialog extends DialogWrapper implements PropertyChange
}
static class MethodWrapper implements Comparable<MethodWrapper> {
private final @NotNull PsiMethod myPsiMethod;
private final @NotNull String myId;
@NotNull private final PsiMethod myPsiMethod;
@NotNull private final String myId;
MethodWrapper(@NotNull PsiMethod psiMethod) {
this.myPsiMethod = psiMethod;
@@ -15,473 +15,23 @@
*/
package com.intellij.codeInspection.nullable;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.NullableNotNullDialog;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInsight.intention.impl.AddNotNullAnnotationFix;
import com.intellij.codeInsight.intention.impl.AddNullableAnnotationFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
public class NullableStuffInspection extends BaseLocalInspectionTool {
// deprecated fields remain to minimize changes to users inspection profiles (which are often located in version control).
@Deprecated @SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL = true;
@SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL = true;
@SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE = true;
@Deprecated @SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL = true;
@SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOT_ANNOTATED_GETTER = true;
@Deprecated @SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NOT_ANNOTATED_SETTER_PARAMETER = true;
@Deprecated @SuppressWarnings({"WeakerAccess"}) public boolean REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS = true; // remains for test
@SuppressWarnings({"WeakerAccess"}) public boolean REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD = true;
private static final Logger LOG = Logger.getInstance("#" + NullableStuffInspection.class.getName());
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override public void visitMethod(PsiMethod method) {
if (!PsiUtil.isLanguageLevel5OrHigher(method)) return;
checkNullableStuffForMethod(method, holder);
}
@Override public void visitField(PsiField field) {
if (!PsiUtil.isLanguageLevel5OrHigher(field)) return;
final PsiType type = field.getType();
final Annotated annotated = check(field, holder, type);
if (TypeConversionUtil.isPrimitiveAndNotNull(type)) {
return;
}
Project project = holder.getProject();
final NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
if (annotated.isDeclaredNotNull ^ annotated.isDeclaredNullable) {
final String anno = annotated.isDeclaredNotNull ? manager.getDefaultNotNull() : manager.getDefaultNullable();
final List<String> annoToRemove = annotated.isDeclaredNotNull ? manager.getNullables() : manager.getNotNulls();
if (!AnnotationUtil.isAnnotatingApplicable(field, anno)) {
final PsiAnnotation notNull = AnnotationUtil.findAnnotation(field, manager.getNotNulls());
final PsiAnnotation nullable = AnnotationUtil.findAnnotation(field, manager.getNullables());
holder.registerProblem(field.getNameIdentifier(), "Nullable/NotNull defaults are not accessible in current context",
new ChangeNullableDefaultsFix(notNull, nullable, manager));
return;
}
String propName = JavaCodeStyleManager.getInstance(project).variableNameToPropertyName(field.getName(), VariableKind.FIELD);
final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC);
final PsiMethod getter = PropertyUtil.findPropertyGetter(field.getContainingClass(), propName, isStatic, false);
final String nullableSimpleName = StringUtil.getShortName(manager.getDefaultNullable());
final String notNullSimpleName = StringUtil.getShortName(manager.getDefaultNotNull());
final PsiIdentifier nameIdentifier = getter == null ? null : getter.getNameIdentifier();
if (nameIdentifier != null && nameIdentifier.isPhysical()) {
if (PropertyUtil.isSimpleGetter(getter)) {
if (REPORT_NOT_ANNOTATED_GETTER) {
if (!AnnotationUtil.isAnnotated(getter, manager.getAllAnnotations(), false, false) &&
!TypeConversionUtil.isPrimitiveAndNotNull(getter.getReturnType())) {
holder.registerProblem(nameIdentifier, InspectionsBundle
.message("inspection.nullable.problems.annotated.field.getter.not.annotated", StringUtil.getShortName(anno)),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AnnotateMethodFix(anno, ArrayUtil.toStringArray(annoToRemove)));
}
}
if (annotated.isDeclaredNotNull && manager.isNullable(getter, false)) {
holder.registerProblem(nameIdentifier, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.getter.conflict", StringUtil.getShortName(anno), nullableSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AnnotateMethodFix(anno, ArrayUtil.toStringArray(annoToRemove)));
} else if (annotated.isDeclaredNullable && manager.isNotNull(getter, false)) {
holder.registerProblem(nameIdentifier, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.getter.conflict", StringUtil.getShortName(anno), notNullSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AnnotateMethodFix(anno, ArrayUtil.toStringArray(annoToRemove)));
}
}
}
final PsiClass containingClass = field.getContainingClass();
final PsiMethod setter = PropertyUtil.findPropertySetter(containingClass, propName, isStatic, false);
if (setter != null) {
final PsiParameter[] parameters = setter.getParameterList().getParameters();
assert parameters.length == 1 : setter.getText();
final PsiParameter parameter = parameters[0];
LOG.assertTrue(parameter != null, setter.getText());
if (REPORT_NOT_ANNOTATED_GETTER && !AnnotationUtil.isAnnotated(parameter, manager.getAllAnnotations(), false, false) && !TypeConversionUtil.isPrimitiveAndNotNull(parameter.getType())) {
final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier();
assertValidElement(setter, parameter, nameIdentifier1);
holder.registerProblem(nameIdentifier1,
InspectionsBundle.message("inspection.nullable.problems.annotated.field.setter.parameter.not.annotated",
StringUtil.getShortName(anno)),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove)));
}
if (PropertyUtil.isSimpleSetter(setter)) {
if (annotated.isDeclaredNotNull && manager.isNullable(parameter, false)) {
final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier();
assertValidElement(setter, parameter, nameIdentifier1);
holder.registerProblem(nameIdentifier1, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.setter.parameter.conflict",
StringUtil.getShortName(anno), nullableSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove)));
}
else if (annotated.isDeclaredNullable && manager.isNotNull(parameter, false)) {
final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier();
assertValidElement(setter, parameter, nameIdentifier1);
holder.registerProblem(nameIdentifier1, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.setter.parameter.conflict", StringUtil.getShortName(anno), notNullSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove)));
}
}
}
for (PsiExpression rhs : findAllConstructorInitializers(field)) {
if (rhs instanceof PsiReferenceExpression) {
PsiElement target = ((PsiReferenceExpression)rhs).resolve();
if (target instanceof PsiParameter) {
PsiParameter parameter = (PsiParameter)target;
if (REPORT_NOT_ANNOTATED_GETTER && !AnnotationUtil.isAnnotated(parameter, manager.getAllAnnotations(), false, false) && !TypeConversionUtil.isPrimitiveAndNotNull(parameter.getType())) {
final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier();
assert nameIdentifier2 != null : parameter;
holder.registerProblem(nameIdentifier2, InspectionsBundle
.message("inspection.nullable.problems.annotated.field.constructor.parameter.not.annotated",
StringUtil.getShortName(anno)),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove)));
continue;
}
if (annotated.isDeclaredNotNull && manager.isNullable(parameter, false)) {
final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier();
assert nameIdentifier2 != null : parameter;
holder.registerProblem(nameIdentifier2, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.constructor.parameter.conflict", StringUtil.getShortName(anno),
nullableSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove)));
}
else if (annotated.isDeclaredNullable && manager.isNotNull(parameter, false)) {
boolean usedAsQualifier = !ReferencesSearch.search(parameter).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference reference) {
final PsiElement element = reference.getElement();
if (element instanceof PsiReferenceExpression && element.getParent() instanceof PsiReferenceExpression) {
return false;
}
return true;
}
});
if (!usedAsQualifier) {
final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier();
assert nameIdentifier2 != null : parameter;
holder.registerProblem(nameIdentifier2, InspectionsBundle.message(
"inspection.nullable.problems.annotated.field.constructor.parameter.conflict", StringUtil.getShortName(anno),
notNullSimpleName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove)));
}
}
}
}
}
}
}
private void assertValidElement(PsiMethod setter, PsiParameter parameter, PsiIdentifier nameIdentifier1) {
LOG.assertTrue(nameIdentifier1 != null && nameIdentifier1.isPhysical(), setter.getText());
LOG.assertTrue(parameter.isPhysical(), setter.getText());
}
@Override public void visitParameter(PsiParameter parameter) {
if (!PsiUtil.isLanguageLevel5OrHigher(parameter)) return;
check(parameter, holder, parameter.getType());
}
};
}
private static class Annotated {
private final boolean isDeclaredNotNull;
private final boolean isDeclaredNullable;
private Annotated(final boolean isDeclaredNotNull, final boolean isDeclaredNullable) {
this.isDeclaredNotNull = isDeclaredNotNull;
this.isDeclaredNullable = isDeclaredNullable;
}
}
private static Annotated check(final PsiModifierListOwner parameter, final ProblemsHolder holder, PsiType type) {
final NullableNotNullManager manager = NullableNotNullManager.getInstance(holder.getProject());
PsiAnnotation isDeclaredNotNull = AnnotationUtil.findAnnotation(parameter, manager.getNotNulls());
PsiAnnotation isDeclaredNullable = AnnotationUtil.findAnnotation(parameter, manager.getNullables());
if (isDeclaredNullable != null && isDeclaredNotNull != null) {
reportNullableNotNullConflict(holder, parameter, isDeclaredNullable, isDeclaredNotNull);
}
if ((isDeclaredNotNull != null || isDeclaredNullable != null) && type != null && TypeConversionUtil.isPrimitive(type.getCanonicalText())) {
PsiAnnotation annotation = isDeclaredNotNull == null ? isDeclaredNullable : isDeclaredNotNull;
reportPrimitiveType(holder, annotation, annotation, parameter);
}
return new Annotated(isDeclaredNotNull != null,isDeclaredNullable != null);
}
private static void reportPrimitiveType(final ProblemsHolder holder, final PsiElement psiElement, final PsiAnnotation annotation,
final PsiModifierListOwner listOwner) {
holder.registerProblem(psiElement.isPhysical() ? psiElement : listOwner.getNavigationElement(),
InspectionsBundle.message("inspection.nullable.problems.primitive.type.annotation"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new RemoveAnnotationQuickFix(annotation, listOwner));
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("inspection.nullable.problems.display.name");
}
@Override
@NotNull
public String getGroupDisplayName() {
return GroupNames.BUGS_GROUP_NAME;
}
@Override
@NotNull
public String getShortName() {
return "NullableProblems";
}
private void checkNullableStuffForMethod(PsiMethod method, final ProblemsHolder holder) {
Annotated annotated = check(method, holder, method.getReturnType());
PsiParameter[] parameters = method.getParameterList().getParameters();
List<MethodSignatureBackedByPsiMethod> superMethodSignatures = method.findSuperMethodSignaturesIncludingStatic(true);
boolean reported_not_annotated_method_overrides_notnull = false;
boolean reported_nullable_method_overrides_notnull = false;
boolean[] reported_notnull_parameter_overrides_nullable = new boolean[parameters.length];
boolean[] reported_not_annotated_parameter_overrides_notnull = new boolean[parameters.length];
final NullableNotNullManager nullableManager = NullableNotNullManager.getInstance(holder.getProject());
for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) {
PsiMethod superMethod = superMethodSignature.getMethod();
if (!reported_nullable_method_overrides_notnull
&& REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE
&& annotated.isDeclaredNullable
&& NullableNotNullManager.isNotNull(superMethod)) {
reported_nullable_method_overrides_notnull = true;
holder.registerProblem(method.getNameIdentifier(),
InspectionsBundle.message("inspection.nullable.problems.Nullable.method.overrides.NotNull"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
if (!reported_not_annotated_method_overrides_notnull
&& REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL
&& !annotated.isDeclaredNullable
&& !annotated.isDeclaredNotNull
&& NullableNotNullManager.isNotNull(superMethod)) {
reported_not_annotated_method_overrides_notnull = true;
final String defaultNotNull = nullableManager.getDefaultNotNull();
final String[] annotationsToRemove = ArrayUtil.toStringArray(nullableManager.getNullables());
final LocalQuickFix fix = AnnotationUtil.isAnnotatingApplicable(method, defaultNotNull)
? createAnnotateMethodFix(defaultNotNull, annotationsToRemove)
: createChangeDefaultNotNullFix(nullableManager, superMethod);
holder.registerProblem(method.getNameIdentifier(),
InspectionsBundle.message("inspection.nullable.problems.method.overrides.NotNull"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
wrapFix(fix));
}
if (REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE || REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL) {
PsiParameter[] superParameters = superMethod.getParameterList().getParameters();
if (superParameters.length != parameters.length) {
continue;
}
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
PsiParameter superParameter = superParameters[i];
if (!reported_notnull_parameter_overrides_nullable[i] && REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE &&
nullableManager.isNotNull(parameter, false) &&
nullableManager.isNullable(superParameter, false)) {
reported_notnull_parameter_overrides_nullable[i] = true;
holder.registerProblem(parameter.getNameIdentifier(),
InspectionsBundle.message("inspection.nullable.problems.NotNull.parameter.overrides.Nullable"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
if (!reported_not_annotated_parameter_overrides_notnull[i] && REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL) {
if (!AnnotationUtil.isAnnotated(parameter, nullableManager.getAllAnnotations(), false, false) &&
nullableManager.isNotNull(superParameter, false)) {
reported_not_annotated_parameter_overrides_notnull[i] = true;
final LocalQuickFix fix = AnnotationUtil.isAnnotatingApplicable(parameter, nullableManager.getDefaultNotNull())
? new AddNotNullAnnotationFix(parameter)
: createChangeDefaultNotNullFix(nullableManager, superParameter);
holder.registerProblem(parameter.getNameIdentifier(),
InspectionsBundle.message("inspection.nullable.problems.parameter.overrides.NotNull"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
wrapFix(fix));
}
}
}
}
}
if (REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS) {
boolean[] parameterAnnotated = new boolean[parameters.length];
boolean[] parameterQuickFixSuggested = new boolean[parameters.length];
boolean hasAnnotatedParameter = false;
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
parameterAnnotated[i] = nullableManager.isNotNull(parameter, false);
hasAnnotatedParameter |= parameterAnnotated[i];
}
if (hasAnnotatedParameter || annotated.isDeclaredNotNull) {
PsiManager manager = method.getManager();
final String defaultNotNull = nullableManager.getDefaultNotNull();
final boolean superMethodApplicable = AnnotationUtil.isAnnotatingApplicable(method, defaultNotNull);
PsiMethod[] overridings =
OverridingMethodsSearch.search(method, GlobalSearchScope.allScope(manager.getProject()), true).toArray(PsiMethod.EMPTY_ARRAY);
boolean methodQuickFixSuggested = false;
for (PsiMethod overriding : overridings) {
if (!manager.isInProject(overriding)) continue;
final boolean applicable = AnnotationUtil.isAnnotatingApplicable(overriding, defaultNotNull);
if (!methodQuickFixSuggested
&& annotated.isDeclaredNotNull
&& !nullableManager.isNotNull(overriding, false)
&& (nullableManager.isNullable(overriding, false) || !nullableManager.isNullable(overriding, true))) {
method.getNameIdentifier(); //load tree
PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, nullableManager.getNotNulls());
final String[] annotationsToRemove = ArrayUtil.toStringArray(nullableManager.getNullables());
final LocalQuickFix fix;
if (applicable) {
fix = new MyAnnotateMethodFix(defaultNotNull, annotationsToRemove);
}
else {
fix = superMethodApplicable ? null : createChangeDefaultNotNullFix(nullableManager, method);
}
PsiElement psiElement = annotation;
if (!annotation.isPhysical()) {
psiElement = method.getNameIdentifier();
if (psiElement == null) continue;
}
holder.registerProblem(psiElement, InspectionsBundle.message("nullable.stuff.problems.overridden.methods.are.not.annotated"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
wrapFix(fix));
methodQuickFixSuggested = true;
}
if (hasAnnotatedParameter) {
PsiParameter[] psiParameters = overriding.getParameterList().getParameters();
for (int i = 0; i < psiParameters.length; i++) {
if (parameterQuickFixSuggested[i]) continue;
PsiParameter parameter = psiParameters[i];
if (parameterAnnotated[i] && !nullableManager.isNotNull(parameter, false) && !nullableManager.isNullable(parameter, false)) {
parameters[i].getNameIdentifier(); //be sure that corresponding tree element available
PsiAnnotation annotation = AnnotationUtil.findAnnotation(parameters[i], nullableManager.getNotNulls());
PsiElement psiElement = annotation;
if (!annotation.isPhysical()) {
psiElement = parameters[i].getNameIdentifier();
if (psiElement == null) continue;
}
holder.registerProblem(psiElement,
InspectionsBundle.message("nullable.stuff.problems.overridden.method.parameters.are.not.annotated"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
wrapFix(!applicable
? createChangeDefaultNotNullFix(nullableManager, parameters[i])
: new AnnotateOverriddenMethodParameterFix(defaultNotNull,
nullableManager.getDefaultNullable())));
parameterQuickFixSuggested[i] = true;
}
}
}
}
}
}
}
private static LocalQuickFix[] wrapFix(LocalQuickFix fix) {
if (fix == null) return LocalQuickFix.EMPTY_ARRAY;
return new LocalQuickFix[]{fix};
}
private static LocalQuickFix createChangeDefaultNotNullFix(NullableNotNullManager nullableManager, PsiModifierListOwner modifierListOwner) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(modifierListOwner, nullableManager.getNotNulls());
if (annotation != null) {
final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
if (referenceElement != null && referenceElement.resolve() != null) {
return new ChangeNullableDefaultsFix(annotation.getQualifiedName(), null, nullableManager);
}
}
return null;
}
protected AnnotateMethodFix createAnnotateMethodFix(final String defaultNotNull, final String[] annotationsToRemove) {
return new AnnotateMethodFix(defaultNotNull, annotationsToRemove);
}
private static void reportNullableNotNullConflict(final ProblemsHolder holder, final PsiModifierListOwner listOwner, final PsiAnnotation declaredNullable,
final PsiAnnotation declaredNotNull) {
holder.registerProblem(declaredNotNull.isPhysical() ? declaredNotNull : listOwner.getNavigationElement(),
InspectionsBundle.message("inspection.nullable.problems.Nullable.NotNull.conflict"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new RemoveAnnotationQuickFix(declaredNotNull, listOwner));
holder.registerProblem(declaredNullable.isPhysical() ? declaredNullable : listOwner.getNavigationElement(),
InspectionsBundle.message("inspection.nullable.problems.Nullable.NotNull.conflict"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new RemoveAnnotationQuickFix(declaredNullable, listOwner));
}
public class NullableStuffInspection extends NullableStuffInspectionBase {
@Override
public JComponent createOptionsPanel() {
return new OptionsPanel();
}
private static class MyAddNullableAnnotationFix extends AddNullableAnnotationFix {
public MyAddNullableAnnotationFix(PsiParameter parameter) {
super(parameter);
}
@Override
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
return true;
}
}
private static class MyAnnotateMethodFix extends AnnotateMethodFix {
public MyAnnotateMethodFix(String defaultNotNull, String[] annotationsToRemove) {
super(defaultNotNull, annotationsToRemove);
}
@Override
protected boolean annotateOverriddenMethods() {
return true;
}
@Override
@NotNull
public String getName() {
return InspectionsBundle.message("annotate.overridden.methods.as.notnull", ClassUtil.extractClassName(myAnnotation));
}
}
private class OptionsPanel extends JPanel {
private JCheckBox myNNParameterOverridesN;
private JCheckBox myNAMethodOverridesNN;
@@ -527,42 +77,4 @@ public class NullableStuffInspection extends BaseLocalInspectionTool {
REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS = REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL;
}
}
public static List<PsiExpression> findAllConstructorInitializers(PsiField field) {
final List<PsiExpression> result = ContainerUtil.createLockFreeCopyOnWriteList();
ContainerUtil.addIfNotNull(result, field.getInitializer());
PsiClass containingClass = field.getContainingClass();
if (containingClass != null) {
LocalSearchScope scope = new LocalSearchScope(containingClass.getConstructors());
ReferencesSearch.search(field, scope, false).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference reference) {
final PsiElement element = reference.getElement();
if (element instanceof PsiReferenceExpression) {
final PsiAssignmentExpression assignment = getAssignmentExpressionIfOnAssignmentLhs(element);
final PsiMethod method = PsiTreeUtil.getParentOfType(assignment, PsiMethod.class);
if (method != null && method.isConstructor() && assignment != null) {
ContainerUtil.addIfNotNull(result, assignment.getRExpression());
}
}
return true;
}
});
}
return result;
}
@Nullable
private static PsiAssignmentExpression getAssignmentExpressionIfOnAssignmentLhs(PsiElement expression) {
PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class);
if (!(parent instanceof PsiAssignmentExpression)) {
return null;
}
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
if (!PsiTreeUtil.isAncestor(assignmentExpression.getLExpression(), expression, false)) {
return null;
}
return assignmentExpression;
}
}
@@ -15,105 +15,22 @@
*/
package com.intellij.codeInspection.wrongPackageStatement;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInspection.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.MoveToPackageFix;
import com.intellij.psi.PsiFile;
import java.util.ArrayList;
import java.util.List;
/**
* User: anna
* Date: 14-Nov-2005
*/
public class WrongPackageStatementInspection extends BaseJavaLocalInspectionTool {
public class WrongPackageStatementInspection extends WrongPackageStatementInspectionBase {
@Override
@Nullable
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
// does not work in tests since CodeInsightTestCase copies file into temporary location
if (ApplicationManager.getApplication().isUnitTestMode()) return null;
if (file instanceof PsiJavaFile) {
if (JspPsiUtil.isInJspFile(file)) return null;
PsiJavaFile javaFile = (PsiJavaFile)file;
PsiDirectory directory = javaFile.getContainingDirectory();
if (directory == null) return null;
PsiPackage dirPackage = JavaDirectoryService.getInstance().getPackage(directory);
if (dirPackage == null) return null;
PsiPackageStatement packageStatement = javaFile.getPackageStatement();
// highlight the first class in the file only
PsiClass[] classes = javaFile.getClasses();
if (classes.length == 0 && packageStatement == null) return null;
String packageName = dirPackage.getQualifiedName();
if (!Comparing.strEqual(packageName, "", true) && packageStatement == null) {
String description = JavaErrorMessages.message("missing.package.statement", packageName);
return new ProblemDescriptor[]{manager.createProblemDescriptor(classes[0].getNameIdentifier(), description,
new AdjustPackageNameFix(packageName),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly)};
}
if (packageStatement != null) {
final PsiJavaCodeReferenceElement packageReference = packageStatement.getPackageReference();
PsiPackage classPackage = (PsiPackage)packageReference.resolve();
List<LocalQuickFix> availableFixes = new ArrayList<LocalQuickFix>();
if (classPackage == null || !Comparing.equal(dirPackage.getQualifiedName(), packageReference.getQualifiedName(), true)) {
availableFixes.add(new AdjustPackageNameFix(packageName));
MoveToPackageFix moveToPackageFix = new MoveToPackageFix(classPackage != null ? classPackage.getQualifiedName() : packageReference.getQualifiedName());
if (moveToPackageFix.isAvailable(file)) {
availableFixes.add(moveToPackageFix);
}
}
if (!availableFixes.isEmpty()){
String description = JavaErrorMessages.message("package.name.file.path.mismatch",
packageReference.getQualifiedName(),
dirPackage.getQualifiedName());
LocalQuickFix[] fixes = availableFixes.toArray(new LocalQuickFix[availableFixes.size()]);
ProblemDescriptor descriptor =
manager.createProblemDescriptor(packageStatement.getPackageReference(), description, isOnTheFly,
fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
return new ProblemDescriptor[]{descriptor};
}
}
protected void addMoveToPackageFix(PsiFile file, String packName, List<LocalQuickFix> availableFixes) {
MoveToPackageFix moveToPackageFix = new MoveToPackageFix(packName);
if (moveToPackageFix.isAvailable(file)) {
availableFixes.add(moveToPackageFix);
}
return null;
}
@Override
@NotNull
public String getGroupDisplayName() {
return "";
}
@Override
@NotNull
public HighlightDisplayLevel getDefaultLevel() {
return HighlightDisplayLevel.ERROR;
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("wrong.package.statement");
}
@Override
@NotNull
@NonNls
public String getShortName() {
return "WrongPackageStatement";
}
@Override
public boolean isEnabledByDefault() {
return true;
}
}
@@ -15,9 +15,12 @@
*/
package com.intellij.ide.util;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
@@ -27,7 +30,6 @@ import com.intellij.psi.presentation.java.SymbolPresentationUtil;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.search.searches.DeepestSuperMethodsSearch;
import com.intellij.ui.components.JBList;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
@@ -68,7 +70,7 @@ public class SuperMethodWarningUtil {
}
SuperMethodWarningDialog dialog =
new SuperMethodWarningDialog(method.getProject(), UsageViewUtil.getDescriptiveName(method), actionString, superAbstract,
new SuperMethodWarningDialog(method.getProject(), DescriptiveNameUtil.getDescriptiveName(method), actionString, superAbstract,
parentInterface, aClass.isInterface(), ArrayUtil.toStringArray(superClasses));
dialog.show();
@@ -97,7 +99,7 @@ public class SuperMethodWarningUtil {
SuperMethodWarningDialog dialog =
new SuperMethodWarningDialog(
method.getProject(),
UsageViewUtil.getDescriptiveName(method), actionString, containingClass.isInterface() || superMethod.hasModifierProperty(PsiModifier.ABSTRACT),
DescriptiveNameUtil.getDescriptiveName(method), actionString, containingClass.isInterface() || superMethod.hasModifierProperty(PsiModifier.ABSTRACT),
containingClass.isInterface(), aClass.isInterface(), containingClass.getQualifiedName()
);
dialog.show();
@@ -154,4 +156,16 @@ public class SuperMethodWarningUtil {
}
}).createPopup().showInBestPositionFor(editor);
}
public static int askWhetherShouldAnnotateBaseMethod(@NotNull PsiMethod method, @NotNull PsiMethod superMethod) {
String implement = !method.hasModifierProperty(PsiModifier.ABSTRACT) && superMethod.hasModifierProperty(PsiModifier.ABSTRACT)
? InspectionsBundle.message("inspection.annotate.quickfix.implements")
: InspectionsBundle.message("inspection.annotate.quickfix.overrides");
String message = InspectionsBundle.message("inspection.annotate.quickfix.overridden.method.messages",
DescriptiveNameUtil.getDescriptiveName(method), implement,
DescriptiveNameUtil.getDescriptiveName(superMethod));
String title = InspectionsBundle.message("inspection.annotate.quickfix.overridden.method.warning");
return Messages.showYesNoCancelDialog(method.getProject(), message, title, Messages.getQuestionIcon());
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.changeClassSignature;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
@@ -27,7 +28,6 @@ import com.intellij.refactoring.ui.StringTableCellEditor;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.ui.*;
import com.intellij.ui.table.JBTable;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.EditableModel;
import org.jetbrains.annotations.NotNull;
@@ -116,7 +116,7 @@ public class ChangeClassSignatureDialog extends RefactoringDialog {
}
protected JComponent createNorthPanel() {
return new JLabel(RefactoringBundle.message("changeClassSignature.class.label.text", UsageViewUtil.getDescriptiveName(myClass)));
return new JLabel(RefactoringBundle.message("changeClassSignature.class.label.text", DescriptiveNameUtil.getDescriptiveName(myClass)));
}
@Override
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.changeSignature;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
@@ -25,7 +26,6 @@ import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CanonicalTypes;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import org.jetbrains.annotations.NotNull;
@@ -288,7 +288,7 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl {
temporallyRevertChanges(method, oldText);
doRefactor(processor);
}
}, RefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(currentMethod)), null);
}, RefactoringBundle.message("changing.signature.of.0", DescriptiveNameUtil.getDescriptiveName(currentMethod)), null);
}
private void doRefactor(BaseRefactoringProcessor processor) {
@@ -16,6 +16,7 @@
*/
package com.intellij.refactoring.encapsulateFields;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
@@ -75,7 +76,7 @@ public class EncapsulateFieldsProcessor extends BaseRefactoringProcessor {
}
protected String getCommandName() {
return RefactoringBundle.message("encapsulate.fields.command.name", UsageViewUtil.getDescriptiveName(myClass));
return RefactoringBundle.message("encapsulate.fields.command.name", DescriptiveNameUtil.getDescriptiveName(myClass));
}
protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
@@ -17,6 +17,7 @@ package com.intellij.refactoring.extractInterface;
import com.intellij.history.LocalHistory;
import com.intellij.history.LocalHistoryAction;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
@@ -34,7 +35,6 @@ import com.intellij.refactoring.memberPullUp.PullUpHelper;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.DocCommentPolicy;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.MultiMap;
@@ -150,7 +150,7 @@ public class ExtractInterfaceHandler implements RefactoringActionHandler, Elemen
}
private String getCommandName() {
return RefactoringBundle.message("extract.interface.command.name", myInterfaceName, UsageViewUtil.getDescriptiveName(myClass));
return RefactoringBundle.message("extract.interface.command.name", myInterfaceName, DescriptiveNameUtil.getDescriptiveName(myClass));
}
public boolean isEnabledOnElements(PsiElement[] elements) {
@@ -1054,7 +1054,7 @@ public class ExtractMethodProcessor implements MatchProvider {
final PsiClass nullableAnnotationClass =
JavaPsiFacade.getInstance(myProject).findClass(manager.getDefaultNullable(), GlobalSearchScope.allScope(myProject));
if (nullableAnnotationClass != null) {
new AddNullableAnnotationFix(newMethod).invoke(myProject, myEditor, myTargetClass.getContainingFile());
new AddNullableAnnotationFix(newMethod).invoke(myProject, myTargetClass.getContainingFile(), newMethod, newMethod);
}
}
}
@@ -22,6 +22,7 @@ package com.intellij.refactoring.extractSuperclass;
import com.intellij.history.LocalHistory;
import com.intellij.history.LocalHistoryAction;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
@@ -41,7 +42,6 @@ import com.intellij.refactoring.memberPullUp.PullUpConflictsUtil;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.DocCommentPolicy;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.MultiMap;
@@ -182,7 +182,7 @@ public class ExtractSuperclassHandler implements RefactoringActionHandler, Extra
}
private String getCommandName(final PsiClass subclass, String newName) {
return RefactoringBundle.message("extract.superclass.command.name", newName, UsageViewUtil.getDescriptiveName(subclass));
return RefactoringBundle.message("extract.superclass.command.name", newName, DescriptiveNameUtil.getDescriptiveName(subclass));
}
public boolean isEnabledOnElements(PsiElement[] elements) {
@@ -53,6 +53,7 @@ import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.ContainerUtil;
@@ -320,7 +321,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
super.performRefactoring(usageInfos);
if (myNewVisibility == null) return;
for (PsiMember member : members) {
VisibilityUtil.fixVisibility(usageInfos, member, myNewVisibility);
VisibilityUtil.fixVisibility(UsageViewUtil.toElements(usageInfos), member, myNewVisibility);
}
}
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
import com.intellij.codeInsight.generation.GenerateMembersUtil;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
@@ -44,7 +45,6 @@ import com.intellij.refactoring.util.classRefs.ClassReferenceScanner;
import com.intellij.refactoring.util.classRefs.ClassReferenceSearchingScanner;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.usages.UsageInfoToUsageConverter;
import com.intellij.usages.UsageTarget;
import com.intellij.usages.UsageViewManager;
@@ -906,7 +906,7 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
protected String getCommandName() {
return RefactoringBundle.message("replace.inheritance.with.delegation.command", UsageViewUtil.getDescriptiveName(myClass));
return RefactoringBundle.message("replace.inheritance.with.delegation.command", DescriptiveNameUtil.getDescriptiveName(myClass));
}
private Set<PsiMember> getAllBaseClassMembers() {
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.inline;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
@@ -30,7 +31,6 @@ import com.intellij.refactoring.rename.NonCodeUsageInfoFactory;
import com.intellij.refactoring.util.*;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
@@ -179,8 +179,8 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor {
} else if (initializer1 instanceof PsiMethodCallExpression) {
referenceExpression = ((PsiMethodCallExpression)initializer1).getMethodExpression();
}
if (referenceExpression != null &&
referenceExpression.getQualifierExpression() == null &&
if (referenceExpression != null &&
referenceExpression.getQualifierExpression() == null &&
!(referenceExpression.advancedResolve(false).getCurrentFileResolveScope() instanceof PsiImportStaticStatement)) {
referenceExpression.setQualifierExpression(qExpression);
}
@@ -212,7 +212,7 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor {
}
protected String getCommandName() {
return RefactoringBundle.message("inline.field.command", UsageViewUtil.getDescriptiveName(myField));
return RefactoringBundle.message("inline.field.command", DescriptiveNameUtil.getDescriptiveName(myField));
}
protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.ChangeContextUtil;
import com.intellij.history.LocalHistory;
import com.intellij.history.LocalHistoryAction;
import com.intellij.lang.Language;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.lang.refactoring.InlineHandler;
import com.intellij.openapi.diagnostic.Logger;
@@ -51,7 +52,6 @@ import com.intellij.refactoring.rename.RenameJavaVariableProcessor;
import com.intellij.refactoring.util.*;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashMap;
@@ -110,7 +110,7 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
myCodeStyleManager = CodeStyleManager.getInstance(myProject);
myJavaCodeStyle = JavaCodeStyleManager.getInstance(myProject);
myDescriptiveName = UsageViewUtil.getDescriptiveName(myMethod);
myDescriptiveName = DescriptiveNameUtil.getDescriptiveName(myMethod);
}
protected String getCommandName() {
@@ -25,6 +25,7 @@
package com.intellij.refactoring.introduceParameter;
import com.intellij.codeInsight.ChangeContextUtil;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
@@ -535,7 +536,7 @@ public class IntroduceParameterProcessor extends BaseRefactoringProcessor implem
}
protected String getCommandName() {
return RefactoringBundle.message("introduce.parameter.command", UsageViewUtil.getDescriptiveName(myMethodToReplaceIn));
return RefactoringBundle.message("introduce.parameter.command", DescriptiveNameUtil.getDescriptiveName(myMethodToReplaceIn));
}
@Nullable
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.refactoring.util.FixableUsageInfo;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
@@ -46,9 +47,9 @@ public class BeanClassVisibilityUsageInfo extends FixableUsageInfo {
@Override
public void fixUsage() throws IncorrectOperationException {
VisibilityUtil.fixVisibility(usages, existingClass, myNewVisibility);
VisibilityUtil.fixVisibility(UsageViewUtil.toElements(usages), existingClass, myNewVisibility);
if (myExistingClassCompatibleConstructor != null) {
VisibilityUtil.fixVisibility(usages, myExistingClassCompatibleConstructor, myNewVisibility);
VisibilityUtil.fixVisibility(UsageViewUtil.toElements(usages), myExistingClassCompatibleConstructor, myNewVisibility);
}
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.invertBoolean;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.help.HelpManager;
import com.intellij.psi.PsiNamedElement;
@@ -47,7 +48,7 @@ public class InvertBooleanDialog extends RefactoringDialog {
myLabel.setText(RefactoringBundle.message("invert.boolean.name.of.inverted.element", typeString));
myCaptionLabel.setText(RefactoringBundle.message("invert.0.1",
typeString,
UsageViewUtil.getDescriptiveName(myElement)));
DescriptiveNameUtil.getDescriptiveName(myElement)));
setTitle(InvertBooleanHandler.REFACTORING_NAME);
init();
@@ -24,6 +24,7 @@
*/
package com.intellij.refactoring.makeStatic;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
@@ -274,7 +275,7 @@ public abstract class MakeMethodOrClassStaticProcessor<T extends PsiTypeParamete
}
protected String getCommandName() {
return RefactoringBundle.message("make.static.command", UsageViewUtil.getDescriptiveName(myMember));
return RefactoringBundle.message("make.static.command", DescriptiveNameUtil.getDescriptiveName(myMember));
}
public T getMember() {
@@ -24,6 +24,7 @@
*/
package com.intellij.refactoring.makeStatic;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
@@ -34,7 +35,6 @@ import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.ParameterTablePanel;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.usageView.UsageViewUtil;
import javax.swing.*;
@@ -222,7 +222,8 @@ public class MakeParameterizedStaticDialog extends AbstractMakeStaticDialog {
if (isMakeClassParameter()) {
final PsiMethod methodWithParameter = checkParameterDoesNotExist();
if (methodWithParameter != null) {
String who = methodWithParameter == myMember ? RefactoringBundle.message("this.method") : UsageViewUtil.getDescriptiveName(methodWithParameter);
String who = methodWithParameter == myMember ? RefactoringBundle.message("this.method") : DescriptiveNameUtil
.getDescriptiveName(methodWithParameter);
String message = RefactoringBundle.message("0.already.has.parameter.named.1.use.this.name.anyway", who, getClassParameterName());
ret = Messages.showYesNoDialog(myProject, message, RefactoringBundle.message("warning.title"), Messages.getWarningIcon());
myClassParameterNameInputField.requestFocusInWindow();

Some files were not shown because too many files have changed in this diff Show More