diff options
author | Tor Norbye <tnorbye@google.com> | 2014-07-16 18:07:37 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2014-07-16 18:09:03 -0700 |
commit | 65f60eb9011bb2c549a6d83ae31257480368ddc5 (patch) | |
tree | de0dca03bec460e8797332e5f460400f5cf6485f /java/java-analysis-impl/src/com/intellij/codeInspection | |
parent | 9ea67227e8fdcf8ed37e65bb96e32767291d0f4f (diff) | |
download | idea-65f60eb9011bb2c549a6d83ae31257480368ddc5.tar.gz |
Snapshot idea/138.1029 from git://git.jetbrains.org/idea/community.git
Update from idea/138.538 to idea/138.1029
Change-Id: I828f829a968439a99ec67640990c18ff7c9b58ce
Diffstat (limited to 'java/java-analysis-impl/src/com/intellij/codeInspection')
11 files changed, 144 insertions, 55 deletions
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index 87ad7d9f6756..96066c34eefe 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -433,6 +433,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection if (resolved instanceof PsiField && ((PsiField)resolved).getContainingClass() == field.getContainingClass()) { final PsiExpression initializer = ((PsiField)resolved).getInitializer(); if (initializer == null || + resolved == field || initializer.getTextOffset() > myAnonymClass.getTextOffset() && !((PsiField)resolved).hasModifierProperty(PsiModifier.STATIC)) { myBodyContainsForbiddenRefs = true; return; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java index 6fb217eaa4e9..1e887030dcb4 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java @@ -112,7 +112,6 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp containingClass = psiMethod.getContainingClass(); isConstructor = psiMethod.isConstructor(); } - if (containingClass == null) return null; boolean isReceiverType = PsiMethodReferenceUtil.isReceiverType(functionalInterfaceType, containingClass, psiMethod); if (isReceiverType && psiMethod != null) { PsiMethod nonAmbiguousMethod = ensureNonAmbiguousMethod(parameters, psiMethod); @@ -120,6 +119,7 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp psiMethod = nonAmbiguousMethod; containingClass = nonAmbiguousMethod.getContainingClass(); } + if (containingClass == null) return null; final boolean staticOrValidConstructorRef; if (isConstructor) { staticOrValidConstructorRef = @@ -182,6 +182,8 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp } }); if (usedInQualifier.get()) return null; + } else if (containingClass != PsiTreeUtil.getParentOfType(body, PsiClass.class) && containingClass.getName() == null) { + return null; } return methodCall; } else if (methodCall instanceof PsiNewExpression) { @@ -275,8 +277,16 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp methodRefText = qualifier + "::" + ((PsiMethodCallExpression)element).getTypeArgumentList().getText() + methodReferenceName; } else { - methodRefText = - (psiMethod.hasModifierProperty(PsiModifier.STATIC) ? getClassReferenceName(containingClass) : "this") + "::" + methodReferenceName; + if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) { + methodRefText = getClassReferenceName(containingClass); + } else { + if (containingClass != PsiTreeUtil.getParentOfType(element, PsiClass.class) ) { + methodRefText = containingClass.getName() + ".this"; + } else { + methodRefText = "this"; + } + } + methodRefText += "::" + methodReferenceName; } } else if (element instanceof PsiNewExpression) { @@ -343,7 +353,13 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp private static String getClassReferenceName(PsiClass containingClass) { final String qualifiedName = containingClass.getQualifiedName(); - return qualifiedName != null ? qualifiedName : containingClass.getName(); + if (qualifiedName != null) { + return qualifiedName; + } + else { + final String containingClassName = containingClass.getName(); + return containingClassName != null ? containingClassName : ""; + } } private static class ReplaceWithMethodRefFix implements LocalQuickFix { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/SuppressManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/SuppressManagerImpl.java index 6136e01f85d8..5f8e43d24ef8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/SuppressManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/SuppressManagerImpl.java @@ -38,6 +38,11 @@ public class SuppressManagerImpl extends SuppressManager { } @Override + public SuppressQuickFix[] getSuppressActions(@NotNull PsiElement element, String toolShortName) { + return createBatchSuppressActions(HighlightDisplayKey.find(toolShortName)); + } + + @Override public boolean isSuppressedFor(@NotNull final PsiElement element, final String toolId) { return JavaSuppressionUtil.getElementToolSuppressedIn(element, toolId) != null; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java index b76177e58880..534d65b07531 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java @@ -16,10 +16,15 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.Function; +import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,8 +40,14 @@ import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstrain public class ContractInference { @NotNull - public static List<MethodContract> inferContracts(@NotNull PsiMethod method) { - return new ContractInferenceInterpreter(method).inferContracts(); + public static List<MethodContract> inferContracts(@NotNull final PsiMethod method) { + return CachedValuesManager.getCachedValue(method, new CachedValueProvider<List<MethodContract>>() { + @Nullable + @Override + public Result<List<MethodContract>> compute() { + return Result.create(new ContractInferenceInterpreter(method).inferContracts(), method); + } + }); } } @@ -49,15 +60,78 @@ class ContractInferenceInterpreter { List<MethodContract> inferContracts() { PsiCodeBlock body = myMethod.getBody(); - if (body == null) return Collections.emptyList(); - - PsiStatement[] statements = body.getStatements(); + PsiStatement[] statements = body == null ? PsiStatement.EMPTY_ARRAY : body.getStatements(); if (statements.length == 0) return Collections.emptyList(); + if (statements.length == 1) { + if (statements[0] instanceof PsiReturnStatement) { + List<MethodContract> result = handleDelegation(((PsiReturnStatement)statements[0]).getReturnValue(), false); + if (result != null) return result; + } + else if (statements[0] instanceof PsiExpressionStatement && ((PsiExpressionStatement)statements[0]).getExpression() instanceof PsiMethodCallExpression) { + List<MethodContract> result = handleDelegation(((PsiExpressionStatement)statements[0]).getExpression(), false); + if (result != null) return result; + } + } + ValueConstraint[] emptyState = MethodContract.createConstraintArray(myMethod.getParameterList().getParametersCount()); return visitStatements(Collections.singletonList(emptyState), statements); } + @Nullable + private List<MethodContract> handleDelegation(final PsiExpression expression, final boolean negated) { + if (expression instanceof PsiParenthesizedExpression) { + return handleDelegation(((PsiParenthesizedExpression)expression).getExpression(), negated); + } + + if (expression instanceof PsiPrefixExpression && ((PsiPrefixExpression)expression).getOperationTokenType() == JavaTokenType.EXCL) { + return handleDelegation(((PsiPrefixExpression)expression).getOperand(), !negated); + } + + if (expression instanceof PsiMethodCallExpression) { + return handleCallDelegation((PsiMethodCallExpression)expression, negated); + } + + return null; + } + + private List<MethodContract> handleCallDelegation(PsiMethodCallExpression expression, final boolean negated) { + final PsiMethod targetMethod = expression.resolveMethod(); + if (targetMethod == null) return Collections.emptyList(); + + final PsiExpression[] arguments = expression.getArgumentList().getExpressions(); + return RecursionManager.doPreventingRecursion(myMethod, true, new Computable<List<MethodContract>>() { + @Override + public List<MethodContract> compute() { + List<MethodContract> delegateContracts = ContractInference.inferContracts(targetMethod); //todo use explicit contracts, too + return ContainerUtil.mapNotNull(delegateContracts, new NullableFunction<MethodContract, MethodContract>() { + @Nullable + @Override + public MethodContract fun(MethodContract delegateContract) { + ValueConstraint[] answer = MethodContract.createConstraintArray(myMethod.getParameterList().getParametersCount()); + for (int i = 0; i < delegateContract.arguments.length; i++) { + if (i >= arguments.length) return null; + + ValueConstraint argConstraint = delegateContract.arguments[i]; + if (argConstraint != ANY_VALUE) { + int paramIndex = resolveParameter(arguments[i]); + if (paramIndex < 0) { + if (argConstraint != getLiteralConstraint(arguments[i])) { + return null; + } + } + else { + answer = withConstraint(answer, paramIndex, argConstraint); + } + } + } + return new MethodContract(answer, negated ? negateConstraint(delegateContract.returnValue) : delegateContract.returnValue); + } + }); + } + }); + } + @NotNull private List<MethodContract> visitExpression(final List<ValueConstraint[]> states, @Nullable PsiExpression expr) { if (states.isEmpty()) return Collections.emptyList(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 3b44c82f9398..1b6d1dfedfec 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -583,7 +583,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (dfaLeft instanceof DfaVariableValue) { DfaVariableValue dfaVar = (DfaVariableValue)dfaLeft; if (isUnknownState(dfaVar)) return true; - + + if (!dfaRelation.isInstanceOf()) { + if (((DfaTypeValue)dfaRight).isNotNull() && isNull(dfaVar)) { + return isNegated; + } + return true; + } + if (isNegated) { DfaVariableState newState = getVariableState(dfaVar).withNotInstanceofValue((DfaTypeValue)dfaRight); if (newState != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 29bcecd0a53f..522bd34a9cf7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -254,7 +254,9 @@ public class StandardInstructionVisitor extends InstructionVisitor { DfaValue condition = factory.getRelationFactory().createRelation(argValue, expectedValue, EQEQ, invertCondition); if (condition == null) { if (!(argValue instanceof DfaConstValue)) { - falseStates.addAll(states); + for (DfaMemoryState state : states) { + falseStates.add(state.createCopy()); + } continue; } condition = constFactory.createFromValue((argValue == expectedValue) != invertCondition, PsiType.BOOLEAN, null); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StringExpressionHelper.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StringExpressionHelper.java index b187d80a3957..9d2530cd2eff 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StringExpressionHelper.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StringExpressionHelper.java @@ -20,7 +20,7 @@ import com.intellij.psi.*; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.Processor; +import com.intellij.util.CommonProcessors; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -161,18 +161,20 @@ public class StringExpressionHelper { @NotNull public static Set<PsiMethodCallExpression> searchMethodCalls(@NotNull final PsiMethod psiMethod, @NotNull SearchScope searchScope) { final Set<PsiMethodCallExpression> callExpressions = new com.intellij.util.containers.HashSet<PsiMethodCallExpression>(); - MethodReferencesSearch.search(psiMethod, searchScope, true).forEach(new Processor<PsiReference>() { - @Override - public boolean process(PsiReference psiReference) { - final PsiMethodCallExpression methodCallExpression = - PsiTreeUtil.getParentOfType(psiReference.getElement(), PsiMethodCallExpression.class); - - if (methodCallExpression != null) { - callExpressions.add(methodCallExpression); - } - return true; + final CommonProcessors.CollectUniquesProcessor<PsiReference> consumer = new CommonProcessors.CollectUniquesProcessor<PsiReference>(); + + MethodReferencesSearch.search(psiMethod, searchScope, true).forEach(consumer); + + for (PsiReference psiReference : consumer.getResults()) { + final PsiMethodCallExpression methodCallExpression = + PsiTreeUtil.getParentOfType(psiReference.getElement(), PsiMethodCallExpression.class); + + if (methodCallExpression != null) { + callExpressions.add(methodCallExpression); } - }); + } + + return callExpressions; } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java index 8343fc9e6a2c..3e70b2d4b673 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java @@ -52,7 +52,6 @@ public class DfaRelationValue extends DfaValue { } public DfaRelationValue createRelation(DfaValue dfaLeft, DfaValue dfaRight, IElementType relation, boolean negated) { - if (dfaRight instanceof DfaTypeValue && INSTANCEOF_KEYWORD != relation) return null; if (PLUS == relation) return null; if (dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue @@ -169,6 +168,10 @@ public class DfaRelationValue extends DfaValue { return myRelation == EQEQ && myIsNegated || myRelation == GT && !myIsNegated || myRelation == GE && myIsNegated; } + public boolean isInstanceOf() { + return myRelation == INSTANCEOF_KEYWORD; + } + @NonNls public String toString() { return (isNegated() ? "not " : "") + myLeftOperand + " " + myRelation + " " + myRightOperand; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java index 29169ddaf5a2..006e5d946c22 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,7 +74,7 @@ public class Java15APIUsageInspectionBase extends BaseJavaBatchLocalInspectionTo loadForbiddenApi("ignore16List.txt", ourIgnored16ClassesAPI); } - private static Set<String> ourGenerifiedClasses = new HashSet<String>(); + private static final Set<String> ourGenerifiedClasses = new HashSet<String>(); static { ourGenerifiedClasses.add("javax.swing.JComboBox"); ourGenerifiedClasses.add("javax.swing.ListModel"); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java index ecf21db51d47..d725158a5201 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java @@ -18,11 +18,9 @@ package com.intellij.codeInspection.miscGenerics; import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.*; import com.intellij.util.containers.IntArrayList; -import com.sun.corba.se.impl.corba.TCUtility; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,10 +45,12 @@ public class SuspiciousMethodCallUtil { PsiMethod contains = MethodSignatureUtil.findMethodBySignature(collectionClass, containsSignature, false); addMethod(contains, 0, patternMethods, indices); - PsiClassType wildcardCollection = javaPsiFacade.getElementFactory().createType(collectionClass, PsiWildcardType.createUnbounded(manager)); - MethodSignature removeAllSignature = MethodSignatureUtil.createMethodSignature("removeAll", new PsiType[] {wildcardCollection}, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY); - PsiMethod removeAll = MethodSignatureUtil.findMethodBySignature(collectionClass, removeAllSignature, false); - addMethod(removeAll, 0, patternMethods, indices); + if (PsiUtil.isLanguageLevel5OrHigher(collectionClass)) { + PsiClassType wildcardCollection = javaPsiFacade.getElementFactory().createType(collectionClass, PsiWildcardType.createUnbounded(manager)); + MethodSignature removeAllSignature = MethodSignatureUtil.createMethodSignature("removeAll", new PsiType[] {wildcardCollection}, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY); + PsiMethod removeAll = MethodSignatureUtil.findMethodBySignature(collectionClass, removeAllSignature, false); + addMethod(removeAll, 0, patternMethods, indices); + } } final PsiClass listClass = javaPsiFacade.findClass(CommonClassNames.JAVA_UTIL_LIST, searchScope); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspectionBase.java index dc28a7b340c0..14da43194fe7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspectionBase.java @@ -15,14 +15,11 @@ */ package com.intellij.codeInspection.unusedSymbol; -import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; -import com.intellij.codeInspection.*; -import com.intellij.psi.PsiElement; +import com.intellij.codeInspection.BaseJavaLocalInspectionTool; import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -public class UnusedSymbolLocalInspectionBase extends AbstractBaseJavaLocalInspectionTool implements CustomSuppressableInspectionTool { +public class UnusedSymbolLocalInspectionBase extends BaseJavaLocalInspectionTool { @NonNls public static final String SHORT_NAME = HighlightInfoType.UNUSED_SYMBOL_SHORT_NAME; @NonNls public static final String DISPLAY_NAME = HighlightInfoType.UNUSED_SYMBOL_DISPLAY_NAME; @NonNls public static final String UNUSED_PARAMETERS_SHORT_NAME = "UnusedParameters"; @@ -33,22 +30,4 @@ public class UnusedSymbolLocalInspectionBase extends AbstractBaseJavaLocalInspec public boolean CLASS = true; public boolean PARAMETER = true; public boolean REPORT_PARAMETER_FOR_PUBLIC_METHODS = true; - - @Override - public boolean isSuppressedFor(@NotNull PsiElement element) { - return isSuppressedFor(element, this); - } - public static boolean isSuppressedFor(@NotNull PsiElement element, @NotNull LocalInspectionTool tool) { - return BaseJavaBatchLocalInspectionTool.isSuppressedFor(element, tool); - } - @Override - public SuppressIntentionAction[] getSuppressActions(final PsiElement element) { - String shortName = getShortName(); - HighlightDisplayKey key = HighlightDisplayKey.find(shortName); - if (key == null) { - throw new AssertionError("HighlightDisplayKey.find(" + shortName + ") is null. Inspection: "+getClass()); - } - SuppressQuickFix[] batchSuppressActions = BatchSuppressManager.SERVICE.getInstance().createBatchSuppressActions(key); - return SuppressIntentionActionFromFix.convertBatchToSuppressIntentionActions(batchSuppressActions); - } } |