From da3d3a087e3dd72b7f709cb53d0dfe55405800b0 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 13 Mar 2017 13:52:11 +0300 Subject: [PATCH] let "analyze dataflow to this" go through StringUtil.notNullize(String) --- .../src/com/intellij/slicer/SliceUtil.java | 203 ++++++++++-------- .../slice/backward/InterMethod.java | 14 +- 2 files changed, 125 insertions(+), 92 deletions(-) diff --git a/java/java-impl/src/com/intellij/slicer/SliceUtil.java b/java/java-impl/src/com/intellij/slicer/SliceUtil.java index a1a1785608cd..1b9ad43f3e40 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUtil.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUtil.java @@ -376,6 +376,14 @@ class SliceUtil { final int paramSeqNo = ArrayUtilRt.find(actualParameters, parameter); assert paramSeqNo != -1; + // first, check if we are looking for a specific method call. + // it happens when we were processing that very same method() return values somewhere up the tree + PsiCall specificMethodCall = findSpecificMethodCallUpTheTree(parent, method); + if (specificMethodCall != null) { + return processMethodCall(parent, parentSubstitutor, indexNesting, syntheticField, processor, actualParameterType, actualParameters, + paramSeqNo, specificMethodCall); + } + Collection superMethods = new THashSet<>(Arrays.asList(method.findDeepestSuperMethods())); superMethods.add(method); @@ -387,91 +395,9 @@ class SliceUtil { if (!processed.add(reference)) return true; } PsiElement refElement = reference.getElement(); - PsiExpressionList argumentList; - JavaResolveResult result; - if (refElement instanceof PsiCall) { - // the case of enum constant decl - PsiCall call = (PsiCall)refElement; - argumentList = call.getArgumentList(); - result = call.resolveMethodGenerics(); - } - else { - PsiElement element = refElement.getParent(); - if (element instanceof PsiCompiledElement) return true; - if (element instanceof PsiAnonymousClass) { - PsiAnonymousClass anon = (PsiAnonymousClass)element; - argumentList = anon.getArgumentList(); - PsiElement callExp = element.getParent(); - if (!(callExp instanceof PsiCallExpression)) return true; - result = ((PsiCall)callExp).resolveMethodGenerics(); - } - else if (element instanceof PsiCall) { - PsiCall call = (PsiCall)element; - argumentList = call.getArgumentList(); - result = call.resolveMethodGenerics(); - } - else { - return processIfInForeignLanguage(parent, parentSubstitutor, indexNesting, syntheticField, processor, refElement); - } - } - PsiSubstitutor substitutor = result.getSubstitutor(); - - PsiExpression[] expressions = argumentList.getExpressions(); - if (paramSeqNo >= expressions.length) { - return true; - } - PsiElement passExpression; - PsiType actualExpressionType; - if (actualParameterType instanceof PsiEllipsisType) { - passExpression = argumentList; - actualExpressionType = expressions[paramSeqNo].getType(); - } - else { - passExpression = expressions[paramSeqNo]; - actualExpressionType = ((PsiExpression)passExpression).getType(); - } - - Project project = argumentList.getProject(); - PsiElement element = result.getElement(); - if (element instanceof PsiCompiledElement) { - element = element.getNavigationElement(); - } - - // for erased method calls for which we cannot determine target substitutor, - // rely on call argument types. I.e. new Pair(1,2) -> Pair - if (element instanceof PsiTypeParameterListOwner && PsiUtil.isRawSubstitutor((PsiTypeParameterListOwner)element, substitutor)) { - PsiTypeParameter[] typeParameters = substitutor.getSubstitutionMap().keySet().toArray(PsiTypeParameter.EMPTY_ARRAY); - - PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper(); - substitutor = resolveHelper.inferTypeArguments(typeParameters, actualParameters, expressions, parentSubstitutor, argumentList, - DefaultParameterTypeInferencePolicy.INSTANCE); - } - - substitutor = removeRawMappingsLeftFromResolve(substitutor); - - PsiSubstitutor combined = unify(substitutor, parentSubstitutor, project); - if (combined == null) return true; - //PsiType substituted = combined.substitute(passExpression.getType()); - PsiType substituted = combined.substitute(actualExpressionType); - if (substituted instanceof PsiPrimitiveType) { - final PsiClassType boxedType = ((PsiPrimitiveType)substituted).getBoxedType(argumentList); - substituted = boxedType != null ? boxedType : substituted; - } - if (substituted == null) return true; - PsiType typeToCheck; - if (actualParameterType instanceof PsiEllipsisType) { - // there may be the case of passing the vararg argument to the other vararg method: foo(int... ints) { bar(ints); } bar(int... ints) {} - if (TypeConversionUtil.areTypesConvertible(substituted, actualParameterType)) { - return handToProcessor(expressions[paramSeqNo], processor, parent, combined, indexNesting, syntheticField); - } - typeToCheck = ((PsiEllipsisType)actualParameterType).getComponentType(); - } - else { - typeToCheck = actualParameterType; - } - if (!TypeConversionUtil.areTypesConvertible(substituted, typeToCheck)) return true; - - return handToProcessor(passExpression, processor, parent, combined, indexNesting, syntheticField); + return processMethodCall(parent, parentSubstitutor, indexNesting, syntheticField, processor, actualParameterType, actualParameters, + paramSeqNo, + refElement); })) { return false; } @@ -480,6 +406,113 @@ class SliceUtil { return true; } + private static PsiCall findSpecificMethodCallUpTheTree(SliceUsage parent, PsiMethod method) { + while (parent != null) { + PsiElement element = parent.getElement(); + if (element instanceof PsiCall && ((PsiCall)element).resolveMethod() == method) { + return (PsiCall)element; + } + parent = parent.getParent(); + } + return null; + } + + private static boolean processMethodCall(@NotNull SliceUsage parent, + @NotNull PsiSubstitutor parentSubstitutor, + int indexNesting, + @NotNull String syntheticField, + @NotNull Processor processor, + PsiType actualParameterType, + PsiParameter[] actualParameters, + int paramSeqNo, + PsiElement refElement) { + PsiExpressionList argumentList; + JavaResolveResult result; + if (refElement instanceof PsiCall) { + // the case of enum constant decl + PsiCall call = (PsiCall)refElement; + argumentList = call.getArgumentList(); + result = call.resolveMethodGenerics(); + } + else { + PsiElement element = refElement.getParent(); + if (element instanceof PsiCompiledElement) return true; + if (element instanceof PsiAnonymousClass) { + PsiAnonymousClass anon = (PsiAnonymousClass)element; + argumentList = anon.getArgumentList(); + PsiElement callExp = element.getParent(); + if (!(callExp instanceof PsiCallExpression)) return true; + result = ((PsiCall)callExp).resolveMethodGenerics(); + } + else if (element instanceof PsiCall) { + PsiCall call = (PsiCall)element; + argumentList = call.getArgumentList(); + result = call.resolveMethodGenerics(); + } + else { + return processIfInForeignLanguage(parent, parentSubstitutor, indexNesting, syntheticField, processor, refElement); + } + } + PsiSubstitutor substitutor = result.getSubstitutor(); + + PsiExpression[] expressions = argumentList.getExpressions(); + if (paramSeqNo >= expressions.length) { + return true; + } + PsiElement passExpression; + PsiType actualExpressionType; + if (actualParameterType instanceof PsiEllipsisType) { + passExpression = argumentList; + actualExpressionType = expressions[paramSeqNo].getType(); + } + else { + passExpression = expressions[paramSeqNo]; + actualExpressionType = ((PsiExpression)passExpression).getType(); + } + + Project project = argumentList.getProject(); + PsiElement element = result.getElement(); + if (element instanceof PsiCompiledElement) { + element = element.getNavigationElement(); + } + + // for erased method calls for which we cannot determine target substitutor, + // rely on call argument types. I.e. new Pair(1,2) -> Pair + if (element instanceof PsiTypeParameterListOwner && PsiUtil.isRawSubstitutor((PsiTypeParameterListOwner)element, substitutor)) { + PsiTypeParameter[] typeParameters = substitutor.getSubstitutionMap().keySet().toArray(PsiTypeParameter.EMPTY_ARRAY); + + PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper(); + substitutor = resolveHelper.inferTypeArguments(typeParameters, actualParameters, expressions, parentSubstitutor, argumentList, + DefaultParameterTypeInferencePolicy.INSTANCE); + } + + substitutor = removeRawMappingsLeftFromResolve(substitutor); + + PsiSubstitutor combined = unify(substitutor, parentSubstitutor, project); + if (combined == null) return true; + //PsiType substituted = combined.substitute(passExpression.getType()); + PsiType substituted = combined.substitute(actualExpressionType); + if (substituted instanceof PsiPrimitiveType) { + final PsiClassType boxedType = ((PsiPrimitiveType)substituted).getBoxedType(argumentList); + substituted = boxedType != null ? boxedType : substituted; + } + if (substituted == null) return true; + PsiType typeToCheck; + if (actualParameterType instanceof PsiEllipsisType) { + // there may be the case of passing the vararg argument to the other vararg method: foo(int... ints) { bar(ints); } bar(int... ints) {} + if (TypeConversionUtil.areTypesConvertible(substituted, actualParameterType)) { + return handToProcessor(expressions[paramSeqNo], processor, parent, combined, indexNesting, syntheticField); + } + typeToCheck = ((PsiEllipsisType)actualParameterType).getComponentType(); + } + else { + typeToCheck = actualParameterType; + } + if (!TypeConversionUtil.areTypesConvertible(substituted, typeToCheck)) return true; + + return handToProcessor(passExpression, processor, parent, combined, indexNesting, syntheticField); + } + private static boolean processIfInForeignLanguage(@NotNull SliceUsage parent, @NotNull PsiSubstitutor parentSubstitutor, int indexNesting, diff --git a/java/java-tests/testData/codeInsight/slice/backward/InterMethod.java b/java/java-tests/testData/codeInsight/slice/backward/InterMethod.java index ff257472a0d0..6144d4d19954 100644 --- a/java/java-tests/testData/codeInsight/slice/backward/InterMethod.java +++ b/java/java-tests/testData/codeInsight/slice/backward/InterMethod.java @@ -1,20 +1,20 @@ class WW { - void f(String ddd) { + void f(String ddd) { if (hashCode() == 0) - ddd = "dd"; - foo(ddd); + ddd = "dd"; + foo(ddd); } { - f("xxx"); + f("xxx"); } { - x("zzz"); + x("zzz"); } - String x(String g) { - String d = foo(g); + String x(String g) { + String d = foo(g); return d; }