diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java similarity index 90% rename from java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java index 83395efd8316..612c6c6a9837 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java @@ -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; - } } diff --git a/java/java-impl/src/com/intellij/codeInsight/guess/GuessManager.java b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/GuessManager.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInsight/guess/GuessManager.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/guess/GuessManager.java diff --git a/java/java-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java similarity index 94% rename from java/java-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java index 9e30492d0412..7a7478340a51 100644 --- a/java/java-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java @@ -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)); } diff --git a/java/java-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java similarity index 99% rename from java/java-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java index c6716c3b0f4c..39d7520852c3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java @@ -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 buildDataflowTypeMap(PsiExpression forPlace) { - PsiElement scope = DfaUtil.getTopmostBlockInSameClass(forPlace); + PsiElement scope = DfaPsiUtil.getTopmostBlockInSameClass(forPlace); if (scope == null) { PsiFile file = forPlace.getContainingFile(); if (!(file instanceof PsiCodeFragment)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/guess/impl/MethodPattern.java b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/MethodPattern.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInsight/guess/impl/MethodPattern.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/MethodPattern.java diff --git a/java/java-impl/src/com/intellij/codeInsight/guess/impl/MethodPatternMap.java b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/MethodPatternMap.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInsight/guess/impl/MethodPatternMap.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/MethodPatternMap.java diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationFix.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationFix.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationFix.java diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationFix.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationFix.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationFix.java diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java similarity index 89% rename from java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java index 8ab713b41fe6..6684613f0ab0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java @@ -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); diff --git a/java/java-impl/src/com/intellij/codeInspection/AddAssertStatementFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AddAssertStatementFix.java similarity index 96% rename from java/java-impl/src/com/intellij/codeInspection/AddAssertStatementFix.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/AddAssertStatementFix.java index d57631fff05d..4bdf0586d869 100644 --- a/java/java-impl/src/com/intellij/codeInspection/AddAssertStatementFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AddAssertStatementFix.java @@ -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; } diff --git a/java/java-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java similarity index 73% rename from java/java-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java index 45e8c7be6b12..6d4ac0cebcfa 100644 --- a/java/java-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java @@ -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); diff --git a/java/java-impl/src/com/intellij/codeInspection/RemoveAnnotationQuickFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/RemoveAnnotationQuickFix.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/RemoveAnnotationQuickFix.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/RemoveAnnotationQuickFix.java diff --git a/java/java-impl/src/com/intellij/codeInspection/ReplaceWithTernaryOperatorFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/ReplaceWithTernaryOperatorFix.java similarity index 78% rename from java/java-impl/src/com/intellij/codeInspection/ReplaceWithTernaryOperatorFix.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/ReplaceWithTernaryOperatorFix.java index d492b7b6cb5e..a6417fa07022 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ReplaceWithTernaryOperatorFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/ReplaceWithTernaryOperatorFix.java @@ -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 diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstanceBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstanceBase.java new file mode 100644 index 000000000000..6c75f8be8e7d --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstanceBase.java @@ -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())) { + holder.registerProblem(expr, description); + return; + } + } + holder.registerProblem(expr, description, createAccessStaticViaInstanceFix(expr, onTheFly, result)); + } + + protected LocalQuickFix createAccessStaticViaInstanceFix(PsiReferenceExpression expr, + boolean onTheFly, + JavaResolveResult result) { + return null; + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/AnnotationsAwareDataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/AnnotationsAwareDataFlowRunner.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/AnnotationsAwareDataFlowRunner.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/AnnotationsAwareDataFlowRunner.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java similarity index 94% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java index 537d6566839f..8f901b606d26 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java @@ -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 myInstructions = new ArrayList(); + private final List myInstructions = new ArrayList(); private final TObjectIntHashMap myElementToStartOffsetMap = new TObjectIntHashMap(); private final TObjectIntHashMap myElementToEndOffsetMap = new TObjectIntHashMap(); private DfaVariableValue[] myFields; @@ -92,7 +93,7 @@ public class ControlFlow { public String toString() { StringBuilder result = new StringBuilder(); - final ArrayList instructions = myInstructions; + final List instructions = myInstructions; for (int i = 0; i < instructions.size(); i++) { Instruction instruction = instructions.get(i); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java similarity index 99% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 0bce6ced94c2..369f6ece05d4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -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()); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java new file mode 100644 index 000000000000..391fa1b5a8dc --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -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 fixes = new SmartList(); + + 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 fixes) { + } + + private void createDescription(StandardDataFlowRunner runner, ProblemsHolder holder, StandardInstructionVisitor visitor) { + Pair, Set> constConditions = runner.getConstConditionalExpressions(); + Set trueSet = constConditions.getFirst(); + Set falseSet = constConditions.getSecond(); + + ArrayList allProblems = new ArrayList(); + 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() { + @Override + public int compare(Instruction i1, Instruction i2) { + return i1.getIndex() - i2.getIndex(); + } + }); + + HashSet reportedAnchors = new HashSet(); + + 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 exprs = runner.getNullableArgumentsPassedToNonAnnotatedParam(); + for (PsiExpression expr : exprs) { + final String text = isNullLiteralExpression(expr) + ? "Passing null argument to non annotated parameter" + : "Argument #ref #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 trueSet, + Set falseSet, HashSet 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 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); + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java similarity index 98% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java index ed6e36dca3d1..4e30cdd0964c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java @@ -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 vars = new HashSet(copy.getVariableStates().keySet()); for (DfaVariableValue value : vars) { copy.flushDependencies(value); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DelegatingInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DelegatingInstructionVisitor.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/DelegatingInstructionVisitor.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DelegatingInstructionVisitor.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java similarity index 97% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java index deb51a220e67..455aaf329156 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java @@ -47,7 +47,7 @@ public interface DfaMemoryState { boolean applyNotNull(DfaValue value); - void flushFields(DataFlowRunner runner); + void flushFields(DfaVariableValue[] fields); void flushVariable(DfaVariableValue variable); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java similarity index 98% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 44c2c31735c9..b7a0b51a640f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -42,7 +42,7 @@ import java.util.*; public class DfaMemoryStateImpl implements DfaMemoryState { private final DfaValueFactory myFactory; - private final ArrayList myEqClasses = new ArrayList(); + private final List myEqClasses = new ArrayList(); private int myStateSize = 0; private final Stack myStack = new Stack(); 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 allVars = new HashSet(myVariableStates.keySet()); - Collections.addAll(allVars, runner.getFields()); - + Collections.addAll(allVars, fields); + Set dependencies = new HashSet(); 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()) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java new file mode 100644 index 000000000000..da25f91d5c62 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java @@ -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 findAllConstructorInitializers(PsiField field) { + final List 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() { + @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 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 getVariableAssignmentsInFile(@NotNull PsiVariable psiVariable, + final boolean literalsOnly, + final PsiElement place) { + final Ref modificationRef = Ref.create(Boolean.FALSE); + final PsiCodeBlock codeBlock = place == null? null : getTopmostBlockInSameClass(place); + final int placeOffset = codeBlock != null? place.getTextRange().getStartOffset() : 0; + List list = ContainerUtil.mapNotNull( + ReferencesSearch.search(psiVariable, new LocalSearchScope(new PsiElement[] {psiVariable.getContainingFile()}, null, true)).findAll(), + new NullableFunction() { + @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 stack = new Stack(); + 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; + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java similarity index 54% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java index a5abf15f9744..808872f4edf4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java @@ -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> 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>() { @Override public Result> compute() { @@ -87,76 +78,11 @@ public class DfaUtil { return expressions == null ? Collections.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 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 getPossibleInitializationElements(final PsiElement qualifierExpression) { if (qualifierExpression instanceof PsiMethodCallExpression) { @@ -221,7 +108,7 @@ public class DfaUtil { } final Collection 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 getVariableAssignmentsInFile(@NotNull PsiVariable psiVariable, - final boolean literalsOnly, - final PsiElement place) { - final Ref modificationRef = Ref.create(Boolean.FALSE); - final PsiCodeBlock codeBlock = place == null? null : getTopmostBlockInSameClass(place); - final int placeOffset = codeBlock != null? place.getTextRange().getStartOffset() : 0; - List list = ContainerUtil.mapNotNull( - ReferencesSearch.search(psiVariable, new LocalSearchScope(new PsiElement[] {psiVariable.getContainingFile()}, null, true)).findAll(), - new NullableFunction() { - @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 stack = new Stack(); - 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 myValues = new MultiValuesMap(true); final Set myNulls = new THashSet(); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java similarity index 99% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java index 92f1ede861bf..b1d3203414a9 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java @@ -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); } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/Nullness.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/Nullness.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/Nullness.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/Nullness.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/RunnerResult.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/RunnerResult.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/RunnerResult.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/RunnerResult.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/SortedIntSet.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/SortedIntSet.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/SortedIntSet.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/SortedIntSet.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardDataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardDataFlowRunner.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardDataFlowRunner.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardDataFlowRunner.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java similarity index 97% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 14bffccec716..fc10e2edafb0 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -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 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); } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/WorkingTimeMeasurer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/WorkingTimeMeasurer.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/WorkingTimeMeasurer.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/WorkingTimeMeasurer.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/AssignInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/AssignInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/AssignInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/AssignInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/CheckReturnValueInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/CheckReturnValueInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/CheckReturnValueInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/CheckReturnValueInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/ConditionalGotoInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ConditionalGotoInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/ConditionalGotoInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ConditionalGotoInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/DupInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/DupInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/DupInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/DupInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/EmptyInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/EmptyInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/EmptyInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/EmptyInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/EmptyStackInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/EmptyStackInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/EmptyStackInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/EmptyStackInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/FieldReferenceInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FieldReferenceInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/FieldReferenceInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FieldReferenceInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/FlushVariableInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FlushVariableInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/FlushVariableInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FlushVariableInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/GosubInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GosubInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/GosubInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GosubInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/GotoInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GotoInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/GotoInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GotoInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/InstanceofInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/InstanceofInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/InstanceofInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/InstanceofInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java similarity index 94% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java index 505deaa0a034..5514268233cd 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java @@ -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 myProcessedStates; + private final List myProcessedStates; protected Instruction() { myProcessedStates = new ArrayList(); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/NotInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/NotInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/NotInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/NotInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/PopInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/PopInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/PopInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/PopInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/PushInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/PushInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/PushInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/PushInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/ReturnFromSubInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ReturnFromSubInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/ReturnFromSubInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ReturnFromSubInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/ReturnInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ReturnInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/ReturnInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ReturnInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/SwapInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/SwapInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/SwapInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/SwapInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/TypeCastInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/TypeCastInstruction.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/TypeCastInstruction.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/TypeCastInstruction.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaBoxedValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaBoxedValue.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaBoxedValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaBoxedValue.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaConstValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaConstValue.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaConstValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaConstValue.java diff --git a/java/java-impl/src/com/intellij/codeInsight/guess/impl/DfaInstanceofValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaInstanceofValue.java similarity index 90% rename from java/java-impl/src/com/intellij/codeInsight/guess/impl/DfaInstanceofValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaInstanceofValue.java index 574fa5eeb92c..833f5037f265 100644 --- a/java/java-impl/src/com/intellij/codeInsight/guess/impl/DfaInstanceofValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaInstanceofValue.java @@ -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; diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaNotNullValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaNotNullValue.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaNotNullValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaNotNullValue.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaTypeValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaTypeValue.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaTypeValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaTypeValue.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaUnboxedValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaUnboxedValue.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaUnboxedValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaUnboxedValue.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaUnknownValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaUnknownValue.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaUnknownValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaUnknownValue.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValue.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValue.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java similarity index 95% rename from java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java index d7606b701b11..39541bf6ca60 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java @@ -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; } diff --git a/java/java-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java similarity index 89% rename from java/java-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java index 56cd621e8fa9..c1dbdbf78f0e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java @@ -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 toAnnotate = new ArrayList(); @@ -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) { diff --git a/java/java-impl/src/com/intellij/codeInspection/nullable/ChangeNullableDefaultsFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/ChangeNullableDefaultsFix.java similarity index 99% rename from java/java-impl/src/com/intellij/codeInspection/nullable/ChangeNullableDefaultsFix.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/nullable/ChangeNullableDefaultsFix.java index 53b439f0d2d5..aa3f0d087de8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/nullable/ChangeNullableDefaultsFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/ChangeNullableDefaultsFix.java @@ -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); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java new file mode 100644 index 000000000000..8014acd5b5de --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java @@ -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 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() { + @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 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)); + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/wrongPackageStatement/AdjustPackageNameFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/AdjustPackageNameFix.java similarity index 100% rename from java/java-impl/src/com/intellij/codeInspection/wrongPackageStatement/AdjustPackageNameFix.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/AdjustPackageNameFix.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspectionBase.java new file mode 100644 index 000000000000..8efcc458c2d3 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspectionBase.java @@ -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 availableFixes = new ArrayList(); + 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 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; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java index 50f48cb626e2..0c1dae659599 100644 --- a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java @@ -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() { - @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() { - @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(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java index 79a8b0423c64..6d03085d0344 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java @@ -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; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java index 858c0a70c013..9841643b1c93 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java @@ -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 sideEffects = new ArrayList(); 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 "" + - " There are possible side effects found in expression '" + - qualifierExpression.getText() + - "'
" + - " You can:
  • Remove class reference along with whole expressions involved, or
  • " + - "
  • Transform qualified expression into the statement on its own.
    " + - " That is,
    " + - "
    " + - myExpression.getText() + - "

    becomes:
    " + - "
    " + - qualifierExpression.getText() + - ";
    " + - qualifiedWithClassName.getText() + - "
  • " + - " "; - } else { - return " There are possible side effects found in expression '" + qualifierExpression.getText() + "'
    " + - "You can:
    • Remove class reference along with whole expressions involved, or
    • "; - } + 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 "" + + " There are possible side effects found in expression '" + + qualifierExpression.getText() + + "'
      " + + " You can:
      • Remove class reference along with whole expressions involved, or
      • " + + "
      • Transform qualified expression into the statement on its own.
        " + + " That is,
        " + + "
        " + + myExpression.getText() + + "

        becomes:
        " + + "
        " + + qualifierExpression.getText() + + ";
        " + + qualifiedWithClassName.getText() + + "
      • " + + " "; } - }; - 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 " There are possible side effects found in expression '" + qualifierExpression.getText() + "'
        " + + "You can:
        • Remove class reference along with whole expressions involved, or
        • "; } + }; + 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; } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SimplifyBooleanExpressionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SimplifyBooleanExpressionAction.java index 8b9881691c41..3ae3ddcf7498 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SimplifyBooleanExpressionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SimplifyBooleanExpressionAction.java @@ -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 diff --git a/java/java-impl/src/com/intellij/codeInspection/MoveToPackageFix.java b/java/java-impl/src/com/intellij/codeInspection/MoveToPackageFix.java index 983c4fa6f55b..3fd32c34212b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/MoveToPackageFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/MoveToPackageFix.java @@ -99,10 +99,4 @@ public class MoveToPackageFix implements LocalQuickFix { LOG.error(e); } } - - public boolean startInWriteAction() { - return false; - } - - } diff --git a/java/java-impl/src/com/intellij/codeInspection/SurroundWithIfFix.java b/java/java-impl/src/com/intellij/codeInspection/SurroundWithIfFix.java index 72aaf616e0e9..3bdbc7c067fd 100644 --- a/java/java-impl/src/com/intellij/codeInspection/SurroundWithIfFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/SurroundWithIfFix.java @@ -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 { diff --git a/java/java-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstance.java b/java/java-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstance.java index 2ae5b8849b72..46994c990f1d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstance.java +++ b/java/java-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstance.java @@ -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())) { - 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); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ConditionCheckDialog.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ConditionCheckDialog.java index 4e05e24660cf..3363d94ba5fe 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ConditionCheckDialog.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ConditionCheckDialog.java @@ -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 otherPanels; - public MethodsPanel(final List checkers, final ConditionChecker.Type type, final @NotNull Project myProject) { + public MethodsPanel(final List checkers, final ConditionChecker.Type type, @NotNull final Project myProject) { this.myProject = myProject; myList = new JBList(new CollectionListModel(checkers)); myPanel = new JPanel(new BorderLayout()); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java index c4b90e746834..348d3dfc5fa5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java @@ -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 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 fixes = new SmartList(); - - 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> constConditions = runner.getConstConditionalExpressions(); - Set trueSet = constConditions.getFirst(); - Set falseSet = constConditions.getSecond(); - - ArrayList allProblems = new ArrayList(); - 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() { - @Override - public int compare(Instruction i1, Instruction i2) { - return i1.getIndex() - i2.getIndex(); - } - }); - - HashSet reportedAnchors = new HashSet(); - - 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 exprs = runner.getNullableArgumentsPassedToNonAnnotatedParam(); - for (PsiExpression expr : exprs) { - final String text = isNullLiteralExpression(expr) - ? "Passing null argument to non annotated parameter" - : "Argument #ref #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 trueSet, - Set falseSet, HashSet 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 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); - } - } } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/MethodCheckerDetailsDialog.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/MethodCheckerDetailsDialog.java index 154ad1836ad7..008ae770153a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/MethodCheckerDetailsDialog.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/MethodCheckerDetailsDialog.java @@ -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 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 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 myModel; - private @Nullable PsiClass myPsiClass; + @NotNull private final ConditionChecker.Type myType; + @NotNull private final SortedComboBoxModel 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 myModel; - private final @NotNull ConditionChecker.Type myType; - private @Nullable PsiMethod myPsiMethod; + @NotNull private final SortedComboBoxModel 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 { - 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 { - 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; diff --git a/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java b/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java index a6280bd62599..7e8448ec49a2 100644 --- a/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java @@ -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 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() { - @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 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 findAllConstructorInitializers(PsiField field) { - final List 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() { - @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; - } } diff --git a/java/java-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspection.java b/java/java-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspection.java index e6fc02673bb9..3f4bd058a1fc 100644 --- a/java/java-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspection.java @@ -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 availableFixes = new ArrayList(); - 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 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; } } diff --git a/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java b/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java index 5ac29a8c7231..efb05d72f0f9 100644 --- a/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java +++ b/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java @@ -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()); + + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureDialog.java b/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureDialog.java index f8ff36b886ba..f8e27c444245 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureDialog.java @@ -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 diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/DetectedJavaChangeInfo.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/DetectedJavaChangeInfo.java index e1ad62fa1868..250efce2a1f1 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/DetectedJavaChangeInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/DetectedJavaChangeInfo.java @@ -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) { diff --git a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java index c3b911b4b3b1..180e28dd0e6d 100644 --- a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java @@ -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 refUsages) { diff --git a/java/java-impl/src/com/intellij/refactoring/extractInterface/ExtractInterfaceHandler.java b/java/java-impl/src/com/intellij/refactoring/extractInterface/ExtractInterfaceHandler.java index 1e2448ef1a5c..061d04e70a58 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractInterface/ExtractInterfaceHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractInterface/ExtractInterfaceHandler.java @@ -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) { diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index dd5a00a22db4..d7771f66d672 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -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); } } } diff --git a/java/java-impl/src/com/intellij/refactoring/extractSuperclass/ExtractSuperclassHandler.java b/java/java-impl/src/com/intellij/refactoring/extractSuperclass/ExtractSuperclassHandler.java index 4352e96f4683..4a4e8d80ec5e 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractSuperclass/ExtractSuperclassHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractSuperclass/ExtractSuperclassHandler.java @@ -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) { diff --git a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java index 8aaf9412074c..d096db58b1cf 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java @@ -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); } } diff --git a/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java b/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java index 8af5d69717b8..28650c7d769f 100644 --- a/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java @@ -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 getAllBaseClassMembers() { diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineConstantFieldProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineConstantFieldProcessor.java index bcf0b354990f..edb86b456e90 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineConstantFieldProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineConstantFieldProcessor.java @@ -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 refUsages) { diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java index 7c55aaefe14b..1659cac04161 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java @@ -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() { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java index 189fe820b87f..8f0f5fb556e9 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java @@ -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 diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/BeanClassVisibilityUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/BeanClassVisibilityUsageInfo.java index 31613801b54e..fab0644eeb22 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/BeanClassVisibilityUsageInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/BeanClassVisibilityUsageInfo.java @@ -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); } } } diff --git a/java/java-impl/src/com/intellij/refactoring/invertBoolean/InvertBooleanDialog.java b/java/java-impl/src/com/intellij/refactoring/invertBoolean/InvertBooleanDialog.java index c230a87d813a..48702418c8ea 100644 --- a/java/java-impl/src/com/intellij/refactoring/invertBoolean/InvertBooleanDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/invertBoolean/InvertBooleanDialog.java @@ -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(); diff --git a/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeMethodOrClassStaticProcessor.java b/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeMethodOrClassStaticProcessor.java index ac618d822b4a..2e6467b3a06a 100644 --- a/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeMethodOrClassStaticProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeMethodOrClassStaticProcessor.java @@ -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 refUsages) { diff --git a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java index 2f7af4714a5c..202a990b76b7 100644 --- a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.replaceConstructorWithFactory; +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.util.ConflictsUtil; import com.intellij.refactoring.util.RefactoringUIUtil; 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.MultiMap; @@ -300,11 +300,11 @@ public class ReplaceConstructorWithFactoryProcessor extends BaseRefactoringProce protected String getCommandName() { if (myConstructor != null) { return RefactoringBundle.message("replace.constructor.0.with.a.factory.method", - UsageViewUtil.getDescriptiveName(myConstructor)); + DescriptiveNameUtil.getDescriptiveName(myConstructor)); } else { return RefactoringBundle.message("replace.default.constructor.of.0.with.a.factory.method", - UsageViewUtil.getDescriptiveName(myOriginalClass)); + DescriptiveNameUtil.getDescriptiveName(myOriginalClass)); } } diff --git a/java/java-impl/src/com/intellij/refactoring/turnRefsToSuper/TurnRefsToSuperProcessor.java b/java/java-impl/src/com/intellij/refactoring/turnRefsToSuper/TurnRefsToSuperProcessor.java index 90372d77c47a..210b8d36313d 100644 --- a/java/java-impl/src/com/intellij/refactoring/turnRefsToSuper/TurnRefsToSuperProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/turnRefsToSuper/TurnRefsToSuperProcessor.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.turnRefsToSuper; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -52,7 +53,7 @@ public class TurnRefsToSuperProcessor extends TurnRefsToSuperProcessorBase { protected String getCommandName() { return RefactoringBundle.message("turn.refs.to.super.command", - UsageViewUtil.getDescriptiveName(myClass), UsageViewUtil.getDescriptiveName(mySuper)); + DescriptiveNameUtil.getDescriptiveName(myClass), DescriptiveNameUtil.getDescriptiveName(mySuper)); } @NotNull diff --git a/java/java-impl/src/com/intellij/refactoring/typeCook/TypeCookDialog.java b/java/java-impl/src/com/intellij/refactoring/typeCook/TypeCookDialog.java index c176555283d4..9c723f4c7273 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeCook/TypeCookDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/typeCook/TypeCookDialog.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.typeCook; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -63,7 +64,7 @@ public class TypeCookDialog extends RefactoringDialog { PsiElement element = elements[i]; name.append(StringUtil.capitalize(UsageViewUtil.getType(element))); name.append(" "); - name.append(UsageViewUtil.getDescriptiveName(element)); + name.append(DescriptiveNameUtil.getDescriptiveName(element)); if (i < elements.length - 1) { name.append("
          "); } diff --git a/java/java-impl/src/com/intellij/refactoring/util/ConflictsUtil.java b/java/java-impl/src/com/intellij/refactoring/util/ConflictsUtil.java index f21c11ad813a..7f139233f5f4 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/ConflictsUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/ConflictsUtil.java @@ -20,13 +20,13 @@ */ package com.intellij.refactoring.util; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.FileContextUtil; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.RefactoringBundle; -import com.intellij.usageView.UsageViewUtil; import com.intellij.util.Processor; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; @@ -74,7 +74,7 @@ public class ConflictsUtil { } else { // method somewhere in base class if (JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(method, aClass, null)) { - String className = CommonRefactoringUtil.htmlEmphasize(UsageViewUtil.getDescriptiveName(method.getContainingClass())); + String className = CommonRefactoringUtil.htmlEmphasize(DescriptiveNameUtil.getDescriptiveName(method.getContainingClass())); if (PsiUtil.getAccessLevel(prototype.getModifierList()) >= PsiUtil.getAccessLevel(method.getModifierList()) ) { boolean isMethodAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); boolean isMyMethodAbstract = refactoredMethod != null && refactoredMethod.hasModifierProperty(PsiModifier.ABSTRACT); diff --git a/java/java-impl/src/com/intellij/refactoring/util/JavaRefactoringElementDescriptionProvider.java b/java/java-impl/src/com/intellij/refactoring/util/JavaRefactoringElementDescriptionProvider.java index 8e691a6a9ec5..2b0163cda726 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/JavaRefactoringElementDescriptionProvider.java +++ b/java/java-impl/src/com/intellij/refactoring/util/JavaRefactoringElementDescriptionProvider.java @@ -15,10 +15,10 @@ */ package com.intellij.refactoring.util; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; import com.intellij.refactoring.RefactoringBundle; -import com.intellij.usageView.UsageViewUtil; import org.jetbrains.annotations.NotNull; public class JavaRefactoringElementDescriptionProvider implements ElementDescriptionProvider { @@ -71,7 +71,8 @@ public class JavaRefactoringElementDescriptionProvider implements ElementDescrip if ((element instanceof PsiClass)) { //TODO : local & anonymous PsiClass psiClass = (PsiClass) element; - return RefactoringBundle.message("class.description", CommonRefactoringUtil.htmlEmphasize(UsageViewUtil.getDescriptiveName(psiClass))); + return RefactoringBundle.message("class.description", CommonRefactoringUtil.htmlEmphasize( + DescriptiveNameUtil.getDescriptiveName(psiClass))); } return null; } diff --git a/java/java-impl/src/com/intellij/codeInsight/ConditionCheckManager.java b/java/java-indexing-impl/src/com/intellij/codeInsight/ConditionCheckManager.java similarity index 92% rename from java/java-impl/src/com/intellij/codeInsight/ConditionCheckManager.java rename to java/java-indexing-impl/src/com/intellij/codeInsight/ConditionCheckManager.java index f7edb1e3b250..1fec41cea4e6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ConditionCheckManager.java +++ b/java/java-indexing-impl/src/com/intellij/codeInsight/ConditionCheckManager.java @@ -40,14 +40,14 @@ public class ConditionCheckManager implements PersistentStateComponent myIsNullCheckMethods = new ArrayList(); - private List myIsNotNullCheckMethods = new ArrayList(); + private final List myIsNullCheckMethods = new ArrayList(); + private final List myIsNotNullCheckMethods = new ArrayList(); - private List myAssertIsNullMethods = new ArrayList(); - private List myAssertIsNotNullMethods = new ArrayList(); + private final List myAssertIsNullMethods = new ArrayList(); + private final List myAssertIsNotNullMethods = new ArrayList(); - private List myAssertTrueMethods = new ArrayList(); - private List myAssertFalseMethods = new ArrayList(); + private final List myAssertTrueMethods = new ArrayList(); + private final List myAssertFalseMethods = new ArrayList(); public static ConditionCheckManager getInstance(Project project) { return ServiceManager.getService(project, ConditionCheckManager.class); diff --git a/java/openapi/src/com/intellij/util/VisibilityUtil.java b/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java similarity index 92% rename from java/openapi/src/com/intellij/util/VisibilityUtil.java rename to java/java-psi-api/src/com/intellij/util/VisibilityUtil.java index ed443049cf0d..373e5befe7c7 100644 --- a/java/openapi/src/com/intellij/util/VisibilityUtil.java +++ b/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java @@ -19,7 +19,7 @@ * User: dsl * Date: 07.06.2002 * Time: 18:48:01 - * 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.util; @@ -28,7 +28,6 @@ import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.usageView.UsageInfo; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; @@ -46,7 +45,7 @@ public class VisibilityUtil { } public static int compare(@PsiModifier.ModifierConstant String v1, @PsiModifier.ModifierConstant String v2) { - return ArrayUtil.find(visibilityModifiers, v2) - ArrayUtil.find(visibilityModifiers, v1); + return ArrayUtilRt.find(visibilityModifiers, v2) - ArrayUtilRt.find(visibilityModifiers, v1); } @PsiModifier.ModifierConstant @@ -123,11 +122,10 @@ public class VisibilityUtil { return PsiBundle.visibilityPresentation(modifier); } - public static void fixVisibility(UsageInfo[] usageInfos, PsiMember member, @PsiModifier.ModifierConstant String newVisibility) { + public static void fixVisibility(PsiElement[] elements, PsiMember member, @PsiModifier.ModifierConstant String newVisibility) { if (newVisibility == null) return; if (ESCALATE_VISIBILITY.equals(newVisibility)) { - for (UsageInfo info : usageInfos) { - final PsiElement element = info.getElement(); + for (PsiElement element : elements) { if (element != null) { escalateVisibility(member, element); } diff --git a/java/java-impl/src/com/intellij/codeInsight/ConditionChecker.java b/java/java-psi-impl/src/com/intellij/codeInsight/ConditionChecker.java similarity index 96% rename from java/java-impl/src/com/intellij/codeInsight/ConditionChecker.java rename to java/java-psi-impl/src/com/intellij/codeInsight/ConditionChecker.java index de3871d0e61b..22769dda4b2f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ConditionChecker.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/ConditionChecker.java @@ -56,7 +56,7 @@ import java.util.*; * Creation Date: 8/14/12 */ public class ConditionChecker implements Serializable { - private final @NotNull Type myConditionCheckType; + @NotNull private final Type myConditionCheckType; public enum Type { IS_NULL_METHOD("IsNull Method"), @@ -77,9 +77,9 @@ public class ConditionChecker implements Serializable { } } - private final @NotNull String myClassName; - private final @NotNull String myMethodName; - private final @NotNull List myParameterClassList; + @NotNull private final String myClassName; + @NotNull private final String myMethodName; + @NotNull private final List myParameterClassList; private final int myCheckedParameterIndex; private final String myFullName; @@ -217,8 +217,8 @@ public class ConditionChecker implements Serializable { static class FromConfigBuilder extends Builder { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.ConditionCheck.FromConfigBuilder"); - private final @NotNull String serializedRepresentation; - private final @NotNull Type type; + @NotNull private final String serializedRepresentation; + @NotNull private final Type type; FromConfigBuilder(@NotNull String serializedRepresentation, @NotNull Type type) { this.serializedRepresentation = serializedRepresentation; @@ -265,7 +265,7 @@ public class ConditionChecker implements Serializable { throw new IllegalArgumentException( "Name should contain 1+ parameter (between opening and closing parenthesis). " + serializedRepresentation); } - else if (allParametersSubString.contains("*") && allParametersSubString.indexOf("*") == allParametersSubString.lastIndexOf("*")) { + if (allParametersSubString.contains("*") && allParametersSubString.indexOf("*") == allParametersSubString.lastIndexOf("*")) { throw new IllegalArgumentException("Selected Parameter should be surrounded by asterisks. " + serializedRepresentation); } @@ -303,9 +303,9 @@ public class ConditionChecker implements Serializable { public static class FromPsiBuilder extends Builder { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.ConditionCheck.FromPsiBuilder"); - private final @NotNull PsiMethod psiMethod; - private final @NotNull PsiParameter psiParameter; - private final @NotNull Type type; + @NotNull private final PsiMethod psiMethod; + @NotNull private final PsiParameter psiParameter; + @NotNull private final Type type; public FromPsiBuilder(@NotNull PsiMethod psiMethod, @NotNull PsiParameter psiParameter, @NotNull Type type) { this.psiMethod = psiMethod; diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/JavaPsiEquivalenceUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/JavaPsiEquivalenceUtil.java new file mode 100644 index 000000000000..730820392b67 --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/codeInsight/JavaPsiEquivalenceUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight; + +import com.intellij.psi.*; +import com.intellij.psi.impl.source.PsiDiamondTypeElementImpl; + +import java.util.Comparator; + +public class JavaPsiEquivalenceUtil { + public static boolean areExpressionsEquivalent(PsiExpression expr1, PsiExpression expr2) { + return PsiEquivalenceUtil.areElementsEquivalent(expr1, expr2, new Comparator() { + @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() { + @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); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AnnotateMethodTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AnnotateMethodTest.java index f285ee489727..1b92a0cdbb5b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AnnotateMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AnnotateMethodTest.java @@ -24,7 +24,7 @@ public class AnnotateMethodTest extends LightQuickFix15TestCase { protected AnnotateMethodFix createAnnotateMethodFix(String defaultNotNull, String[] annotationsToRemove) { return new AnnotateMethodFix(defaultNotNull, annotationsToRemove){ @Override - public int annotateBaseMethod(final PsiMethod method, final PsiMethod superMethod, final Project project) { + public int shouldAnnotateBaseMethod(final PsiMethod method, final PsiMethod superMethod, final Project project) { @NonNls String name = method.getName(); int ret = name.startsWith("annotateBase") ? 0 // yes, annotate all : name.startsWith("dontAnnotateBase") ? 1 // do not annotate base diff --git a/java/openapi/src/com/intellij/patterns/PsiJavaElementPattern.java b/java/openapi/src/com/intellij/patterns/PsiJavaElementPattern.java index e91eb8790919..e72731b2bd2b 100644 --- a/java/openapi/src/com/intellij/patterns/PsiJavaElementPattern.java +++ b/java/openapi/src/com/intellij/patterns/PsiJavaElementPattern.java @@ -24,7 +24,7 @@ import org.jetbrains.annotations.NotNull; * @author peter */ public class PsiJavaElementPattern> extends PsiElementPattern { - private static final @NonNls String VALUE = "value"; + @NonNls private static final String VALUE = "value"; public PsiJavaElementPattern(final Class aClass) { super(aClass); @@ -61,11 +61,12 @@ public class PsiJavaElementPattern aClass) { - return nameIdentifierOf(PsiJavaPatterns.instanceOf(aClass)); + return nameIdentifierOf(StandardPatterns.instanceOf(aClass)); } - + public Self nameIdentifierOf(final ElementPattern pattern) { return with(new PatternCondition("nameIdentifierOf") { + @Override public boolean accepts(@NotNull final T t, final ProcessingContext context) { if (!(t instanceof PsiIdentifier)) return false; @@ -81,6 +82,7 @@ public class PsiJavaElementPattern methodPattern) { return with(new PatternCondition("methodCallParameter") { + @Override public boolean accepts(@NotNull final T literal, final ProcessingContext context) { final PsiElement parent = literal.getParent(); if (parent instanceof PsiExpressionList) { @@ -106,6 +108,7 @@ public class PsiJavaElementPattern("methodCallParameter") { + @Override public boolean accepts(@NotNull final T literal, final ProcessingContext context) { final PsiElement parent = literal.getParent(); if (parent instanceof PsiExpressionList) { diff --git a/lib/groovy-all-2.0.6.jar b/lib/groovy-all-2.1.3.jar similarity index 65% rename from lib/groovy-all-2.0.6.jar rename to lib/groovy-all-2.1.3.jar index ed8e33ae660f..9e434a5f0c9f 100644 Binary files a/lib/groovy-all-2.0.6.jar and b/lib/groovy-all-2.1.3.jar differ diff --git a/lib/src/groovy-all-2.1.3-sources.jar b/lib/src/groovy-all-2.1.3-sources.jar new file mode 100644 index 000000000000..50d60232d744 Binary files /dev/null and b/lib/src/groovy-all-2.1.3-sources.jar differ diff --git a/lib/src/groovy-src-2.0.6.zip b/lib/src/groovy-src-2.0.6.zip deleted file mode 100644 index acdd4bd16284..000000000000 Binary files a/lib/src/groovy-src-2.0.6.zip and /dev/null differ diff --git a/platform/lang-api/src/com/intellij/codeInsight/PsiEquivalenceUtil.java b/platform/core-api/src/com/intellij/codeInsight/PsiEquivalenceUtil.java similarity index 100% rename from platform/lang-api/src/com/intellij/codeInsight/PsiEquivalenceUtil.java rename to platform/core-api/src/com/intellij/codeInsight/PsiEquivalenceUtil.java diff --git a/platform/indexing-api/src/com/intellij/lang/findUsages/DescriptiveNameUtil.java b/platform/indexing-api/src/com/intellij/lang/findUsages/DescriptiveNameUtil.java new file mode 100644 index 000000000000..4f18abcf10b1 --- /dev/null +++ b/platform/indexing-api/src/com/intellij/lang/findUsages/DescriptiveNameUtil.java @@ -0,0 +1,48 @@ +/* + * 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.lang.findUsages; + +import com.intellij.lang.Language; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.meta.PsiMetaData; +import com.intellij.psi.meta.PsiMetaOwner; +import org.jetbrains.annotations.NotNull; + +public class DescriptiveNameUtil { + private static final Logger LOG = Logger.getInstance("#com.intellij.lang.findUsages.DescriptiveNameUtil"); + + public static String getMetaDataName(final PsiMetaData metaData) { + final String name = metaData.getName(); + return StringUtil.isEmpty(name) ? "''" : name; + } + + public static String getDescriptiveName(@NotNull PsiElement psiElement) { + LOG.assertTrue(psiElement.isValid()); + + if (psiElement instanceof PsiMetaOwner) { + final PsiMetaOwner psiMetaOwner = (PsiMetaOwner)psiElement; + final PsiMetaData metaData = psiMetaOwner.getMetaData(); + if (metaData != null) return getMetaDataName(metaData); + } + + final Language lang = psiElement.getLanguage(); + final FindUsagesProvider provider = LanguageFindUsages.INSTANCE.forLanguage(lang); + assert provider != null : lang; + return provider.getDescriptiveName(psiElement); + } +} diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/CommonFindUsagesDialog.java b/platform/lang-impl/src/com/intellij/find/findUsages/CommonFindUsagesDialog.java index 3b43ac03bf0a..a38dcced6135 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/CommonFindUsagesDialog.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/CommonFindUsagesDialog.java @@ -16,6 +16,7 @@ package com.intellij.find.findUsages; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -67,7 +68,7 @@ public class CommonFindUsagesDialog extends AbstractFindUsagesDialog { public void configureLabelComponent(@NotNull SimpleColoredComponent coloredComponent) { coloredComponent.append(StringUtil.capitalize(UsageViewUtil.getType(myPsiElement))); coloredComponent.append(" "); - coloredComponent.append(UsageViewUtil.getDescriptiveName(myPsiElement), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + coloredComponent.append(DescriptiveNameUtil.getDescriptiveName(myPsiElement), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/impl/ShowRecentFindUsagesAction.java b/platform/lang-impl/src/com/intellij/find/impl/ShowRecentFindUsagesAction.java index d43daf9bc660..1b9e66e50d2f 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/ShowRecentFindUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/impl/ShowRecentFindUsagesAction.java @@ -19,6 +19,7 @@ package com.intellij.find.impl; import com.intellij.find.FindBundle; import com.intellij.find.FindManager; import com.intellij.find.findUsages.FindUsagesManager; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -92,7 +93,7 @@ public class ShowRecentFindUsagesAction extends AnAction { String scopeString = data.myOptions.searchScope == null ? null : data.myOptions.searchScope.getDisplayName(); return FindBundle.message("recent.find.usages.action.description", StringUtil.capitalize(UsageViewUtil.getType(psiElement)), - UsageViewUtil.getDescriptiveName(psiElement), + DescriptiveNameUtil.getDescriptiveName(psiElement), scopeString == null ? ProjectScope.getAllScope(psiElement.getProject()).getDisplayName() : scopeString); } diff --git a/platform/lang-impl/src/com/intellij/find/impl/ShowRecentFindUsagesGroup.java b/platform/lang-impl/src/com/intellij/find/impl/ShowRecentFindUsagesGroup.java index 8c5a7d4a6e48..09715d21fae4 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/ShowRecentFindUsagesGroup.java +++ b/platform/lang-impl/src/com/intellij/find/impl/ShowRecentFindUsagesGroup.java @@ -19,6 +19,7 @@ package com.intellij.find.impl; import com.intellij.find.FindBundle; import com.intellij.find.FindManager; import com.intellij.find.findUsages.FindUsagesManager; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -66,7 +67,7 @@ public class ShowRecentFindUsagesGroup extends ActionGroup { if (psiElement == null) continue; String scopeString = data.myOptions.searchScope == null ? null : data.myOptions.searchScope.getDisplayName(); String text = FindBundle.message("recent.find.usages.action.popup", StringUtil.capitalize(UsageViewUtil.getType(psiElement)), - UsageViewUtil.getDescriptiveName(psiElement), + DescriptiveNameUtil.getDescriptiveName(psiElement), scopeString == null ? ProjectScope.getAllScope(psiElement.getProject()).getDisplayName() : scopeString); AnAction action = new AnAction(text, description, psiElement.getIcon(0)) { @Override diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java index 5aa3f7502c6f..ca0693111b1d 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java @@ -16,6 +16,7 @@ package com.intellij.refactoring.changeSignature; import com.intellij.ide.actions.CopyReferenceAction; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.command.undo.BasicUndoableAction; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.command.undo.UndoableAction; @@ -32,7 +33,6 @@ import com.intellij.refactoring.rename.ResolveSnapshotProvider; import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; import com.intellij.refactoring.util.MoveRenameUsageInfo; import com.intellij.usageView.UsageInfo; -import com.intellij.usageView.UsageViewUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.hash.HashMap; @@ -182,7 +182,7 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces @Override protected String getCommandName() { - return RefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(myChangeInfo.getMethod())); + return RefactoringBundle.message("changing.signature.of.0", DescriptiveNameUtil.getDescriptiveName(myChangeInfo.getMethod())); } public ChangeInfo getChangeInfo() { diff --git a/platform/lang-impl/src/com/intellij/refactoring/listeners/impl/RefactoringTransaction.java b/platform/lang-impl/src/com/intellij/refactoring/listeners/impl/RefactoringTransaction.java index c79c515d1f9b..a44c05b73fbd 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/listeners/impl/RefactoringTransaction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/listeners/impl/RefactoringTransaction.java @@ -26,8 +26,6 @@ public interface RefactoringTransaction { /** * Returns listener for element (element must belong to set of affected elements). * Refactorings should call appropriate methods of a listener, giving a modified (or new) element. - * @param element - * @return */ RefactoringElementListener getElementListener(PsiElement element); diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java index 071453c80b78..b22067e5dc0c 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java @@ -16,6 +16,7 @@ package com.intellij.refactoring.rename; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -119,7 +120,7 @@ public class RenameDialog extends RefactoringDialog { } private String getFullName() { - final String name = UsageViewUtil.getDescriptiveName(myPsiElement); + final String name = DescriptiveNameUtil.getDescriptiveName(myPsiElement); return (UsageViewUtil.getType(myPsiElement) + " " + name).trim(); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameProcessor.java index cd0051811994..4c7b562b95aa 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameProcessor.java @@ -16,6 +16,7 @@ package com.intellij.refactoring.rename; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; @@ -254,7 +255,7 @@ public class RenameProcessor extends BaseRefactoringProcessor { myNewName = newName; myAllRenames.put(myPrimaryElement, newName); myCommandName = RefactoringBundle - .message("renaming.0.1.to.2", UsageViewUtil.getType(myPrimaryElement), UsageViewUtil.getDescriptiveName(myPrimaryElement), newName); + .message("renaming.0.1.to.2", UsageViewUtil.getType(myPrimaryElement), DescriptiveNameUtil.getDescriptiveName(myPrimaryElement), newName); } @Override diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java index aab4b05d2f4b..5467be71207f 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java @@ -16,6 +16,7 @@ package com.intellij.refactoring.rename.inplace; import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.impl.FinishMarkAction; @@ -201,7 +202,7 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { } final String commandName = RefactoringBundle - .message("renaming.0.1.to.2", UsageViewUtil.getType(variable), UsageViewUtil.getDescriptiveName(variable), newName); + .message("renaming.0.1.to.2", UsageViewUtil.getType(variable), DescriptiveNameUtil.getDescriptiveName(variable), newName); CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { @Override public void run() { diff --git a/platform/lang-impl/src/com/intellij/refactoring/util/DefaultRefactoringElementDescriptionProvider.java b/platform/lang-impl/src/com/intellij/refactoring/util/DefaultRefactoringElementDescriptionProvider.java index ec732b2467fc..36979a4cc3c9 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/util/DefaultRefactoringElementDescriptionProvider.java +++ b/platform/lang-impl/src/com/intellij/refactoring/util/DefaultRefactoringElementDescriptionProvider.java @@ -16,11 +16,11 @@ package com.intellij.refactoring.util; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.psi.ElementDescriptionProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.ElementDescriptionLocation; import com.intellij.usageView.UsageViewUtil; -import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.NotNull; /** @@ -32,7 +32,7 @@ public class DefaultRefactoringElementDescriptionProvider implements ElementDesc @Override public String getElementDescription(@NotNull final PsiElement element, @NotNull final ElementDescriptionLocation location) { final String typeString = UsageViewUtil.getType(element); - final String name = UsageViewUtil.getDescriptiveName(element); + final String name = DescriptiveNameUtil.getDescriptiveName(element); return typeString + " " + CommonRefactoringUtil.htmlEmphasize(name); } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/util/RefactoringUIUtil.java b/platform/lang-impl/src/com/intellij/refactoring/util/RefactoringUIUtil.java index 7b00bd7066fd..47f51265ab9e 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/util/RefactoringUIUtil.java +++ b/platform/lang-impl/src/com/intellij/refactoring/util/RefactoringUIUtil.java @@ -16,6 +16,7 @@ package com.intellij.refactoring.util; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NonNls; import com.intellij.psi.PsiElement; @@ -62,7 +63,7 @@ public class RefactoringUIUtil { if (i > 0) buffer.append(", "); buffer.append(UsageViewUtil.getType(elements[i])); buffer.append(" "); - buffer.append(UsageViewUtil.getDescriptiveName(elements[i])); + buffer.append(DescriptiveNameUtil.getDescriptiveName(elements[i])); } return buffer.toString(); diff --git a/platform/lang-impl/src/com/intellij/usageView/UsageViewNodeTextLocation.java b/platform/lang-impl/src/com/intellij/usageView/UsageViewNodeTextLocation.java index 022feaaedec9..94692f9c2e27 100644 --- a/platform/lang-impl/src/com/intellij/usageView/UsageViewNodeTextLocation.java +++ b/platform/lang-impl/src/com/intellij/usageView/UsageViewNodeTextLocation.java @@ -17,6 +17,7 @@ package com.intellij.usageView; import com.intellij.lang.Language; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.lang.findUsages.FindUsagesProvider; import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.psi.ElementDescriptionLocation; @@ -49,7 +50,7 @@ public class UsageViewNodeTextLocation extends ElementDescriptionLocation { if (element instanceof PsiMetaOwner) { final PsiMetaData metaData = ((PsiMetaOwner)element).getMetaData(); if (metaData instanceof PsiPresentableMetaData) { - return ((PsiPresentableMetaData)metaData).getTypeName() + " " + UsageViewUtil.getMetaDataName(metaData); + return ((PsiPresentableMetaData)metaData).getTypeName() + " " + DescriptiveNameUtil.getMetaDataName(metaData); } } diff --git a/platform/lang-impl/src/com/intellij/usageView/UsageViewShortNameLocation.java b/platform/lang-impl/src/com/intellij/usageView/UsageViewShortNameLocation.java index f28b34e554dd..ad1e3edd2d18 100644 --- a/platform/lang-impl/src/com/intellij/usageView/UsageViewShortNameLocation.java +++ b/platform/lang-impl/src/com/intellij/usageView/UsageViewShortNameLocation.java @@ -16,6 +16,7 @@ package com.intellij.usageView; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.psi.ElementDescriptionLocation; import com.intellij.psi.ElementDescriptionProvider; import com.intellij.psi.PsiElement; @@ -45,7 +46,7 @@ public class UsageViewShortNameLocation extends ElementDescriptionLocation { if (element instanceof PsiMetaOwner) { PsiMetaData metaData = ((PsiMetaOwner)element).getMetaData(); - if (metaData!=null) return UsageViewUtil.getMetaDataName(metaData); + if (metaData!=null) return DescriptiveNameUtil.getMetaDataName(metaData); } if (element instanceof PsiNamedElement) { diff --git a/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java b/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java index cebccff1c1cc..c68b30103a63 100644 --- a/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java +++ b/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java @@ -16,21 +16,17 @@ package com.intellij.usageView; -import com.intellij.lang.Language; -import com.intellij.lang.findUsages.FindUsagesProvider; -import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.ElementDescriptionUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; -import com.intellij.psi.meta.PsiMetaData; -import com.intellij.psi.meta.PsiMetaOwner; import com.intellij.refactoring.util.MoveRenameUsageInfo; import com.intellij.refactoring.util.NonCodeUsageInfo; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -47,11 +43,6 @@ public class UsageViewUtil { return ElementDescriptionUtil.getElementDescription(element, UsageViewNodeTextLocation.INSTANCE); } - public static String getMetaDataName(final PsiMetaData metaData) { - final String name = metaData.getName(); - return StringUtil.isEmpty(name) ? "''" : name; - } - public static String getShortName(final PsiElement psiElement) { LOG.assertTrue(psiElement.isValid()); return ElementDescriptionUtil.getElementDescription(psiElement, UsageViewShortNameLocation.INSTANCE); @@ -66,21 +57,6 @@ public class UsageViewUtil { return ElementDescriptionUtil.getElementDescription(psiElement, UsageViewTypeLocation.INSTANCE); } - public static String getDescriptiveName(@NotNull PsiElement psiElement) { - LOG.assertTrue(psiElement.isValid()); - - if (psiElement instanceof PsiMetaOwner) { - final PsiMetaOwner psiMetaOwner = (PsiMetaOwner)psiElement; - final PsiMetaData metaData = psiMetaOwner.getMetaData(); - if (metaData != null) return getMetaDataName(metaData); - } - - final Language lang = psiElement.getLanguage(); - final FindUsagesProvider provider = LanguageFindUsages.INSTANCE.forLanguage(lang); - assert provider != null : lang; - return provider.getDescriptiveName(psiElement); - } - public static boolean hasNonCodeUsages(UsageInfo[] usages) { for (UsageInfo usage : usages) { if (usage.isNonCodeUsage) return true; @@ -97,31 +73,31 @@ public class UsageViewUtil { public static UsageInfo[] removeDuplicatedUsages(@NotNull UsageInfo[] usages) { Set set = new LinkedHashSet(Arrays.asList(usages)); - + // Replace duplicates of move rename usage infos in injections from non code usages of master files String newTextInNonCodeUsage = null; - + for(UsageInfo usage:usages) { if (!(usage instanceof NonCodeUsageInfo)) continue; newTextInNonCodeUsage = ((NonCodeUsageInfo)usage).newText; break; } - + if (newTextInNonCodeUsage != null) { for(UsageInfo usage:usages) { if (!(usage instanceof MoveRenameUsageInfo)) continue; PsiFile file = usage.getFile(); - + if (file != null) { PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file); if (context != null) { - + PsiElement usageElement = usage.getElement(); if (usageElement == null) continue; - + PsiReference psiReference = usage.getReference(); if (psiReference == null) continue; - + int injectionOffsetInMasterFile = InjectedLanguageManager.getInstance(usageElement.getProject()).injectedToHost(usageElement, usageElement.getTextOffset()); TextRange rangeInElement = usage.getRangeInElement(); assert rangeInElement != null : usage; @@ -133,7 +109,7 @@ public class UsageViewUtil { containingFile, range.getStartOffset(), range.getEndOffset(), - ((MoveRenameUsageInfo)usage).getReferencedElement(), + ((MoveRenameUsageInfo)usage).getReferencedElement(), newTextInNonCodeUsage ) ); @@ -149,4 +125,15 @@ public class UsageViewUtil { final int size = collection.size(); return size == 0 ? UsageInfo.EMPTY_ARRAY : collection.toArray(new UsageInfo[size]); } + + @NotNull + public static PsiElement[] toElements(@NotNull UsageInfo[] usageInfos) { + return ContainerUtil.map2Array(usageInfos, PsiElement.class, new Function() { + @Override + public PsiElement fun(UsageInfo info) { + return info.getElement(); + } + }); + } + } diff --git a/platform/platform-impl/src/com/intellij/util/InstanceofCheckerGeneratorImpl.java b/platform/platform-impl/src/com/intellij/util/InstanceofCheckerGeneratorImpl.java index ca512ad80442..479424b6420e 100644 --- a/platform/platform-impl/src/com/intellij/util/InstanceofCheckerGeneratorImpl.java +++ b/platform/platform-impl/src/com/intellij/util/InstanceofCheckerGeneratorImpl.java @@ -17,6 +17,7 @@ package com.intellij.util; import com.intellij.openapi.util.Condition; import com.intellij.util.containers.ConcurrentFactoryMap; +import org.jetbrains.annotations.NotNull; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Type; @@ -43,6 +44,7 @@ public class InstanceofCheckerGeneratorImpl extends InstanceofCheckerGenerator { } }; + @NotNull public Condition getInstanceofChecker(final Class someClass) { return myCache.get(someClass); } diff --git a/platform/platform-api/src/com/intellij/util/InstanceofCheckerGenerator.java b/platform/util/src/com/intellij/util/InstanceofCheckerGenerator.java similarity index 100% rename from platform/platform-api/src/com/intellij/util/InstanceofCheckerGenerator.java rename to platform/util/src/com/intellij/util/InstanceofCheckerGenerator.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReturnNullInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReturnNullInspection.java index 4f3c7e4377f7..81e65843cf94 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReturnNullInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReturnNullInspection.java @@ -18,6 +18,9 @@ package com.siyeh.ig.bugs; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInspection.AnnotateMethodFix; +import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; +import com.intellij.ide.util.SuperMethodWarningUtil; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; @@ -27,7 +30,6 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.DelegatingFix; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.CollectionUtils; -import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import org.intellij.lang.annotations.Pattern; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -76,7 +78,12 @@ public class ReturnNullInspection extends BaseInspection { NullableNotNullManager.getInstance(elt.getProject()); return new DelegatingFix(new AnnotateMethodFix( manager.getDefaultNullable(), - ArrayUtil.toStringArray(manager.getNotNulls()))); + ArrayUtil.toStringArray(manager.getNotNulls())){ + @Override + public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) { + return SuperMethodWarningUtil.askWhetherShouldAnnotateBaseMethod(method, superMethod); + } + }); } @Override diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java index b9ddd044dcb4..8a6ebeff68ce 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java @@ -16,6 +16,7 @@ package com.siyeh.ig.junit; import com.intellij.codeInspection.AnnotateMethodFix; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -48,7 +49,12 @@ public class JUnit3StyleTestMethodInJUnit4ClassInspection extends BaseInspection @Nullable @Override protected InspectionGadgetsFix buildFix(Object... infos) { - return new DelegatingFix(new AnnotateMethodFix("org.junit.Test")); + return new DelegatingFix(new AnnotateMethodFix("org.junit.Test"){ + @Override + public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) { + return 1; + } + }); } @Override diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java index edde2ccfd863..fcb00ffeeeda 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java @@ -16,6 +16,7 @@ package org.intellij.plugins.intelliLang.util; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInspection.dataFlow.DfaPsiUtil; import com.intellij.codeInspection.dataFlow.DfaUtil; import com.intellij.openapi.project.Project; import com.intellij.psi.*; @@ -77,11 +78,11 @@ public class SubstitutedExpressionEvaluationHelper { resolvedType = psiVariable.getType(); final Collection values; if (dfaOption == Configuration.DfaOption.ASSIGNMENTS) { - values = DfaUtil.getVariableAssignmentsInFile(psiVariable, true, o); + values = DfaPsiUtil.getVariableAssignmentsInFile(psiVariable, true, o); } else if (dfaOption == Configuration.DfaOption.DFA) { final Collection realValues = DfaUtil.getCachedVariableValues(psiVariable, o); - values = realValues == null? DfaUtil.getVariableAssignmentsInFile(psiVariable, true, o) : realValues; + values = realValues == null? DfaPsiUtil.getVariableAssignmentsInFile(psiVariable, true, o) : realValues; } else { values = Collections.emptyList(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index a910b1d3b9fc..fd52c937b270 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java @@ -421,7 +421,10 @@ public class GrClassImplUtil { List result = new ArrayList(); for (CandidateInfo info : CollectClassMembersUtil.getAllInnerClasses(grType, false).values()) { final PsiClass inner = (PsiClass)info.getElement(); - if (lastParent == null || !inner.getContainingClass().isInterface()) { + final PsiClass containingClass = inner.getContainingClass(); + assert containingClass != null; + + if (lastParent == null || !containingClass.isInterface() || PsiTreeUtil.isAncestor(containingClass, place, false)) { ContainerUtil.addIfNotNull(result, inner); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/CollectClassMembersUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/CollectClassMembersUtil.java index 5ff1ade5b9e0..eb1ca8032980 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/CollectClassMembersUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/CollectClassMembersUtil.java @@ -17,7 +17,6 @@ package org.jetbrains.plugins.groovy.lang.resolve; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Trinity; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.util.*; @@ -37,28 +36,56 @@ import java.util.Set; * @author ven */ public class CollectClassMembersUtil { - private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.lang.resolve.CollectClassMembersUtil"); - private static final Key, Map>, Map>>> CACHED_MEMBERS = Key.create("CACHED_CLASS_MEMBERS"); + private static class ClassMembers { + private final Map myFields; + private final Map> myMethods; + private final Map myInnerClasses; - private static final Key, Map>, Map>>> CACHED_MEMBERS_INCLUDING_SYNTHETIC = Key.create("CACHED_MEMBERS_INCLUDING_SYNTHETIC"); + private ClassMembers(@NotNull Map fields, + @NotNull Map> methods, + @NotNull Map innerClasses) { + myFields = fields; + myMethods = methods; + myInnerClasses = innerClasses; + } + + public static ClassMembers create(@NotNull Map first, + @NotNull Map> second, + @NotNull Map third) { + return new ClassMembers(first, second, third); + } + + private Map getFields() { + return myFields; + } + + private Map> getMethods() { + return myMethods; + } + + private Map getInnerClasses() { + return myInnerClasses; + } + } + + private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.lang.resolve.CollectClassMembersUtil"); + private static final Key> CACHED_MEMBERS = Key.create("CACHED_CLASS_MEMBERS"); + + private static final Key> CACHED_MEMBERS_INCLUDING_SYNTHETIC = Key.create("CACHED_MEMBERS_INCLUDING_SYNTHETIC"); private CollectClassMembersUtil() { } public static Map> getAllMethods(final PsiClass aClass, boolean includeSynthetic) { - return getCachedMembers(aClass, includeSynthetic).getSecond(); + return getCachedMembers(aClass, includeSynthetic).getMethods(); } @NotNull - private static Trinity, Map>, Map> getCachedMembers( - PsiClass aClass, - boolean includeSynthetic) { + private static ClassMembers getCachedMembers(@NotNull PsiClass aClass, boolean includeSynthetic) { LOG.assertTrue(aClass.isValid()); - Key, Map>, Map>>> key = - includeSynthetic ? CACHED_MEMBERS_INCLUDING_SYNTHETIC : CACHED_MEMBERS; - CachedValue, Map>, Map>> cachedValue = - aClass.getUserData(key); + Key> key = includeSynthetic ? CACHED_MEMBERS_INCLUDING_SYNTHETIC : CACHED_MEMBERS; + CachedValue cachedValue = aClass.getUserData(key); if (cachedValue == null) { cachedValue = buildCache(aClass, includeSynthetic); aClass.putUserData(key, cachedValue); @@ -66,37 +93,38 @@ public class CollectClassMembersUtil { return cachedValue.getValue(); } - public static Map getAllInnerClasses(final PsiClass aClass, boolean includeSynthetic) { - return getCachedMembers(aClass, includeSynthetic).getThird(); + public static Map getAllInnerClasses(@NotNull final PsiClass aClass, boolean includeSynthetic) { + return getCachedMembers(aClass, includeSynthetic).getInnerClasses(); } - public static Map getAllFields(final PsiClass aClass, boolean includeSynthetic) { - return getCachedMembers(aClass, includeSynthetic).getFirst(); + public static Map getAllFields(@NotNull final PsiClass aClass, boolean includeSynthetic) { + return getCachedMembers(aClass, includeSynthetic).getFields(); } - public static Map getAllFields(final PsiClass aClass) { + public static Map getAllFields(@NotNull final PsiClass aClass) { return getAllFields(aClass, true); } - private static CachedValue, Map>, Map>> buildCache(final PsiClass aClass, final boolean includeSynthetic) { - return CachedValuesManager.getManager(aClass.getProject()).createCachedValue(new CachedValueProvider, Map>, Map>>() { - public Result, Map>, Map>> compute() { + private static CachedValue buildCache(@NotNull final PsiClass aClass, final boolean includeSynthetic) { + return CachedValuesManager.getManager(aClass.getProject()).createCachedValue(new CachedValueProvider() { + public Result compute() { Map allFields = new HashMap(); Map> allMethods = new HashMap>(); Map allInnerClasses = new HashMap(); processClass(aClass, allFields, allMethods, allInnerClasses, new HashSet(), PsiSubstitutor.EMPTY, includeSynthetic); - return Result.create(Trinity.create(allFields, allMethods, allInnerClasses), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + return Result.create(ClassMembers.create(allFields, allMethods, allInnerClasses), + PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); } }, false); } - private static void processClass(PsiClass aClass, - Map allFields, - Map> allMethods, - Map allInnerClasses, - Set visitedClasses, - PsiSubstitutor substitutor, + private static void processClass(@NotNull PsiClass aClass, + @NotNull Map allFields, + @NotNull Map> allMethods, + @NotNull Map allInnerClasses, + @NotNull Set visitedClasses, + @NotNull PsiSubstitutor substitutor, boolean includeSynthetic) { LOG.assertTrue(aClass.isValid()); @@ -110,11 +138,12 @@ public class CollectClassMembersUtil { else if (hasExplicitVisibilityModifiers(field)) { final CandidateInfo candidateInfo = allFields.get(name); final PsiElement element = candidateInfo.getElement(); - if (element instanceof GrField && (((GrField)element).getModifierList() == null || - !(((GrField)element).getModifierList()).hasExplicitVisibilityModifiers()) && - aClass == ((GrField)element).getContainingClass()) { - //replace property-field with field with explicit visibilityModifier - allFields.put(name, new CandidateInfo(field, substitutor)); + if (element instanceof GrField) { + final GrModifierList modifierList = ((GrField)element).getModifierList(); + if ((modifierList == null || !modifierList.hasExplicitVisibilityModifiers()) && aClass == ((GrField)element).getContainingClass()) { + //replace property-field with field with explicit visibilityModifier + allFields.put(name, new CandidateInfo(field, substitutor)); + } } } } @@ -139,15 +168,15 @@ public class CollectClassMembersUtil { } } - public static PsiField[] getFields(PsiClass aClass, boolean includeSynthetic) { + public static PsiField[] getFields(@NotNull PsiClass aClass, boolean includeSynthetic) { return includeSynthetic || !(aClass instanceof GrTypeDefinition) ? aClass.getFields() : ((GrTypeDefinition)aClass).getCodeFields(); } - public static PsiMethod[] getMethods(PsiClass aClass, boolean includeSynthetic) { + public static PsiMethod[] getMethods(@NotNull PsiClass aClass, boolean includeSynthetic) { return includeSynthetic || !(aClass instanceof GrTypeDefinition) ? aClass.getMethods() : ((GrTypeDefinition)aClass).getCodeMethods(); } - private static boolean hasExplicitVisibilityModifiers(PsiField field) { + private static boolean hasExplicitVisibilityModifiers(@NotNull PsiField field) { if (field instanceof GrField) { final GrModifierList list = (GrModifierList)field.getModifierList(); return list == null || list.hasExplicitVisibilityModifiers(); @@ -157,7 +186,9 @@ public class CollectClassMembersUtil { } } - private static void addMethod(Map> allMethods, PsiMethod method, PsiSubstitutor substitutor) { + private static void addMethod(@NotNull Map> allMethods, + @NotNull PsiMethod method, + @NotNull PsiSubstitutor substitutor) { String name = method.getName(); List methods = allMethods.get(name); if (methods == null) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyInlineHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyInlineHandler.java index a1282a069328..0a0ebe992055 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyInlineHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyInlineHandler.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.refactoring.inline; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.lang.refactoring.InlineHandler; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; @@ -61,7 +62,7 @@ public class GroovyInlineHandler implements InlineHandler { } private static String getFullName(PsiElement psi) { - final String name = UsageViewUtil.getDescriptiveName(psi); + final String name = DescriptiveNameUtil.getDescriptiveName(psi); return (UsageViewUtil.getType(psi) + " " + name).trim(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/field/GroovyFieldValidator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/field/GroovyFieldValidator.java index d59f4ca17d94..5a262fcd2989 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/field/GroovyFieldValidator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/field/GroovyFieldValidator.java @@ -15,9 +15,9 @@ */ package org.jetbrains.plugins.groovy.refactoring.introduce.field; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; -import com.intellij.usageView.UsageViewUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -44,7 +44,7 @@ public class GroovyFieldValidator extends GrIntroduceValidatorEngine { if (GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)toCheck) && varName.equals(GroovyPropertyUtils.getPropertyNameByAccessorName(((PsiMethod)toCheck).getName()))) { conflicts.putValue(toCheck, message("access.to.created.field.0.will.be.overriden.by.method.1", htmlEmphasize(varName), - htmlEmphasize(UsageViewUtil.getDescriptiveName(toCheck)))); + htmlEmphasize(DescriptiveNameUtil.getDescriptiveName(toCheck)))); } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceClosureParameterProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceClosureParameterProcessor.java index c99fcb384da1..25f18dd0c9c4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceClosureParameterProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceClosureParameterProcessor.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.refactoring.introduce.parameter; import com.intellij.codeInsight.ChangeContextUtil; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.Condition; @@ -384,10 +385,10 @@ public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcess callExpression = GroovyRefactoringUtil.getCallExpressionByMethodReference(parent); } } - + if (callExpression == null) return; - - + + //LOG.assertTrue(callExpression != null); //check for x.getFoo()(args) @@ -404,7 +405,7 @@ public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcess } } } - + GrArgumentList argList = callExpression.getArgumentList(); LOG.assertTrue(argList != null); GrExpression[] oldArgs = argList.getExpressionArguments(); @@ -613,7 +614,7 @@ public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcess @Override protected String getCommandName() { - return RefactoringBundle.message("introduce.parameter.command", UsageViewUtil.getDescriptiveName(mySettings.getToReplaceIn())); + return RefactoringBundle.message("introduce.parameter.command", DescriptiveNameUtil.getDescriptiveName(mySettings.getToReplaceIn())); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterProcessor.java index 7d694427935f..4dd51a436429 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterProcessor.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.refactoring.introduce.parameter; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; @@ -259,7 +260,7 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl @Override protected String getCommandName() { - return RefactoringBundle.message("introduce.parameter.command", UsageViewUtil.getDescriptiveName(mySettings.getToReplaceIn())); + return RefactoringBundle.message("introduce.parameter.command", DescriptiveNameUtil.getDescriptiveName(mySettings.getToReplaceIn())); } @NotNull diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy index 52263b499758..2092272b3647 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy @@ -263,7 +263,8 @@ print Component print List ''') def target = myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset).resolve() - assertEquals('java.util.List', target.getQualifiedName()) + assert target instanceof PsiClass + assertEquals('java.util.List', target.qualifiedName) } void testSuper() { @@ -292,5 +293,18 @@ new Foo().Inner assertNull(ref.resolve()) } + void testInnerClassOfInterfaceInsideItself() { + resolveByText('''\ +public interface OuterInterface { + static enum InnerEnum { + ONE, TWO + public static InnerEnum getSome() { + ONE + } + } +} +''', PsiClass) + } + private void doTest(String fileName = getTestName(false) + ".groovy") { resolve(fileName, PsiClass) } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenModelDocumentationProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenModelDocumentationProvider.java index 3214e2034305..2d60b495d215 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenModelDocumentationProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenModelDocumentationProvider.java @@ -16,13 +16,13 @@ package org.jetbrains.idea.maven.dom; import com.intellij.lang.documentation.DocumentationProvider; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.FakePsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlTag; import com.intellij.usageView.UsageViewTypeLocation; -import com.intellij.usageView.UsageViewUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.dom.references.MavenPsiElementWrapper; @@ -101,11 +101,11 @@ public class MavenModelDocumentationProvider implements DocumentationProvider, E } private static String buildPropertyName(PsiElement e, boolean property) { - if (property) return UsageViewUtil.getDescriptiveName(e); + if (property) return DescriptiveNameUtil.getDescriptiveName(e); List path = new ArrayList(); do { - path.add(UsageViewUtil.getDescriptiveName(e)); + path.add(DescriptiveNameUtil.getDescriptiveName(e)); } while ((e = PsiTreeUtil.getParentOfType(e, XmlTag.class)) != null); Collections.reverse(path); diff --git a/xml/impl/src/com/intellij/lang/xml/XmlFindUsagesProvider.java b/xml/impl/src/com/intellij/lang/xml/XmlFindUsagesProvider.java index c9154bd2d67b..19089b62405f 100644 --- a/xml/impl/src/com/intellij/lang/xml/XmlFindUsagesProvider.java +++ b/xml/impl/src/com/intellij/lang/xml/XmlFindUsagesProvider.java @@ -18,6 +18,7 @@ package com.intellij.lang.xml; import com.intellij.find.impl.HelpID; import com.intellij.lang.LangBundle; import com.intellij.lang.cacheBuilder.WordsScanner; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.lang.findUsages.FindUsagesProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -25,7 +26,6 @@ import com.intellij.psi.PsiNamedElement; import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.xml.*; import com.intellij.usageView.UsageViewBundle; -import com.intellij.usageView.UsageViewUtil; import org.jetbrains.annotations.NotNull; /** @@ -98,7 +98,7 @@ public class XmlFindUsagesProvider implements FindUsagesProvider { if (element instanceof XmlTag) { final XmlTag xmlTag = (XmlTag)element; final PsiMetaData metaData = xmlTag.getMetaData(); - final String name = metaData != null ? UsageViewUtil.getMetaDataName(metaData) : xmlTag.getName(); + final String name = metaData != null ? DescriptiveNameUtil.getMetaDataName(metaData) : xmlTag.getName(); return UsageViewBundle.message("usage.target.xml.tag.of.file", metaData == null ? "<" + name + ">" : name, xmlTag.getContainingFile().getName()); } else if (element instanceof XmlAttributeValue) { diff --git a/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameDialog.java b/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameDialog.java index 342a2e54e765..f811a0aa8393 100644 --- a/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameDialog.java +++ b/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameDialog.java @@ -24,6 +24,7 @@ package com.intellij.xml.refactoring; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; @@ -39,7 +40,6 @@ import com.intellij.psi.xml.XmlTag; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.ui.NameSuggestionsField; import com.intellij.refactoring.ui.RefactoringDialog; -import com.intellij.ui.IdeBorderFactory; import com.intellij.usageView.UsageViewUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.xml.XmlBundle; @@ -91,7 +91,7 @@ public class XmlTagRenameDialog extends RefactoringDialog { } private static String getFullName(@NotNull final XmlTag tag) { - final String name = UsageViewUtil.getDescriptiveName(tag); + final String name = DescriptiveNameUtil.getDescriptiveName(tag); return (UsageViewUtil.getType(tag) + " " + name).trim(); }