[java-slice] Support Optional tracking (IDEA-189788)

GitOrigin-RevId: b2df50d27bc69c3d01059a0fc2dba6fb1926891a
This commit is contained in:
Tagir Valeev
2021-04-12 10:56:56 +00:00
committed by intellij-monorepo-bot
parent 25128f2ba9
commit aa5d05cb34
6 changed files with 83 additions and 13 deletions
@@ -118,6 +118,12 @@ class SliceUsageCellRenderer extends SliceUsageCellRendererBase {
else if (element instanceof PsiReference) {
name = ((PsiReference)element).getCanonicalText();
}
else if (element instanceof PsiExpression) {
PsiType type = ((PsiExpression)element).getType();
if (type != null) {
name = type.getPresentableText();
}
}
prev = usage;
usage = (JavaSliceUsage)usage.getParent();
}
@@ -151,19 +151,20 @@ final class SliceUtil {
}
}
if (expression instanceof PsiMethodCallExpression) { // ctr call can't return value or be container get, so don't use PsiCall here
PsiExpression returnedValue = JavaMethodContractUtil.findReturnedValue((PsiMethodCallExpression)expression);
PsiMethodCallExpression call = (PsiMethodCallExpression)expression;
PsiExpression returnedValue = JavaMethodContractUtil.findReturnedValue(call);
if (returnedValue != null) {
if (!builder.process(returnedValue, processor)) {
return false;
}
}
PsiMethod method = ((PsiMethodCallExpression)expression).resolveMethod();
PsiMethod method = call.resolveMethod();
Flow anno = method == null ? null : isMethodFlowAnnotated(method);
if (anno != null) {
String target = anno.target();
if (target.equals(Flow.DEFAULT_TARGET)) target = Flow.RETURN_METHOD_TARGET;
if (target.equals(Flow.RETURN_METHOD_TARGET)) {
PsiExpression qualifier = ((PsiMethodCallExpression)expression).getMethodExpression().getQualifierExpression();
PsiExpression qualifier = call.getMethodExpression().getQualifierExpression();
if (qualifier != null) {
builder = builder.updateNesting(anno);
String source = anno.source();
@@ -173,7 +174,25 @@ final class SliceUtil {
}
}
}
return processMethodReturnValue((PsiMethodCallExpression)expression, processor, builder);
if (method != null && builder.hasNesting()) {
PsiParameter[] parameters = method.getParameterList().getParameters();
boolean hasFlownParameter = false;
for (int i = 0; i < parameters.length; i++) {
Flow paramAnno = isParamFlowAnnotated(method, i);
if (paramAnno != null && !parameters[i].isVarArgs()) {
PsiExpression[] args = call.getArgumentList().getExpressions();
if (args.length > i) {
JavaSliceBuilder argBuilder = builder.updateNesting(paramAnno);
if (!argBuilder.process(args[i], processor)) {
return false;
}
hasFlownParameter = true;
}
}
}
if (hasFlownParameter) return true;
}
return processMethodReturnValue(call, processor, builder);
}
if (expression instanceof PsiConditionalExpression) {
PsiConditionalExpression conditional = (PsiConditionalExpression)expression;
@@ -1,5 +1,3 @@
import javax.swing.*;
class Foo {
void foo(String <caret>s) {
}
@@ -14,4 +12,7 @@ class Foo {
}
});
}
}
class SwingUtilities {
static void invokeLater(Runnable runnable) {}
}
@@ -0,0 +1,14 @@
import java.util.Optional;
class MainTest {
public static void main(String[] <flown1111>args) {
Optional<String> optional;
if (args.length > 0) {
optional = <flown11>Optional.ofNullable(<flown111>args[0]);
} else {
optional = <flown12>Optional.of(<flown121>"foo");
}
String val = <flown1>optional.orElse(<flown13>"xyz");
System.out.println(<caret>val);
}
}
@@ -19,10 +19,13 @@ import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.execution.filters.ExceptionAnalysisProvider;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.slicer.*;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.util.ArrayUtil;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
@@ -32,6 +35,11 @@ import java.util.List;
import java.util.Map;
public class SliceBackwardTest extends SliceTestCase {
@Override
protected Sdk getTestProjectJdk() {
return PsiTestUtil.addJdkAnnotations(IdeaTestUtil.getMockJdk11());
}
private void doTest() throws Exception {
doTest("");
}
@@ -110,7 +118,7 @@ public class SliceBackwardTest extends SliceTestCase {
public void testAppend() throws Exception { doTest();}
public void testRequireNonNull() throws Exception { doTest();}
public void testBackAndForward() throws Exception { doTest();}
public void testFilterIntRange() throws Exception { doTest(">=0");}
public void testFilterIntRangeArray() throws Exception { doTest(">=0");}
public void testFilterNull() throws Exception { doTest("null");}
@@ -122,20 +130,21 @@ public class SliceBackwardTest extends SliceTestCase {
public void testReturnParameter() throws Exception { doTest(); }
public void testFilterLongByInt() throws Exception { doTest("<=0"); }
public void testFilterDoubleByInt() throws Exception { doTest("0.0"); }
public void testStackFilterSimple() throws Exception {
public void testStackFilterSimple() throws Exception {
doTest("null", "MainTest:test", "MainTest:foo", "MainTest:main");
}
public void testStackFilterBridgeMethod() throws Exception {
doTest("null", "MainTest$Bar:get", "MainTest$Bar:get", "MainTest:bar", "MainTest:main");
}
}
public void testStackFilterBridgeMethod2() throws Exception {
doTest("null", "MainTest$Bar:get", "MainTest$Bar:get", "MainTest:bar", "MainTest:main");
}
public void testRecordComponent() throws Exception { doTest();}
public void testRecordComponent2() throws Exception { doTest();}
public void testRecordComponent3() throws Exception { doTest();}
public void testOptionalAsContainer() throws Exception { doTest();}
}
@@ -3311,17 +3311,38 @@
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.Optional java.util.Optional&lt;T&gt; of(T) 0'>
<annotation name='org.intellij.lang.annotations.Flow'>
<val name="targetIsContainer" val="true"/>
</annotation>
</item>
<item name='java.util.Optional java.util.Optional&lt;T&gt; ofNullable(T) 0'>
<annotation name='org.intellij.lang.annotations.Flow'>
<val name="targetIsContainer" val="true"/>
</annotation>
</item>
<item name='java.util.Optional T get()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.intellij.lang.annotations.Flow'>
<val name="sourceIsContainer" val="true"/>
</annotation>
</item>
<item name='java.util.Optional T orElse(T)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="value" val="&quot;!null -&gt; !null&quot;"/>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.intellij.lang.annotations.Flow'>
<val name="sourceIsContainer" val="true"/>
</annotation>
</item>
<item name='java.util.Optional T orElse(T) 0'>
<annotation name='org.intellij.lang.annotations.Flow'>
<val name="targetIsContainer" val="true"/>
</annotation>
</item>
<item name='java.util.Properties java.lang.String getProperty(java.lang.String) 0'>
<annotation name='org.jetbrains.annotations.NonNls'/>