[java-inspections] IDEA-284073 Enhance dfa: Support that Stream.toList() is unmodifiable

PR#1861

GitOrigin-RevId: ddddc2451708df8e11d00e059eafdb8674fa562b
This commit is contained in:
pyltsin-m
2021-12-06 10:05:53 +00:00
committed by intellij-monorepo-bot
parent 0b5d6324c8
commit 0ded7bc2f5
4 changed files with 52 additions and 0 deletions
@@ -12,6 +12,7 @@ import com.intellij.java.analysis.JavaAnalysisBundle;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.impl.source.PsiMethodImpl;
@@ -64,6 +65,8 @@ public enum Mutability {
public static final @NotNull String UNMODIFIABLE_VIEW_ANNOTATION = UNMODIFIABLE_VIEW.myAnnotation;
private static final @NotNull CallMatcher STREAM_COLLECT = CallMatcher.instanceCall(
CommonClassNames.JAVA_UTIL_STREAM_STREAM, "collect").parameterTypes("java.util.stream.Collector");
private static final @NotNull CallMatcher STREAM_TO_LIST = CallMatcher.instanceCall(
CommonClassNames.JAVA_UTIL_STREAM_STREAM, "toList").withLanguageLevelAtLeast(LanguageLevel.JDK_16);
private static final @NotNull CallMatcher UNMODIFIABLE_COLLECTORS = CallMatcher.staticCall(
CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, "toUnmodifiableList", "toUnmodifiableSet", "toUnmodifiableMap");
private final @PropertyKey(resourceBundle = JavaAnalysisBundle.BUNDLE) String myResourceKey;
@@ -187,6 +190,8 @@ public enum Mutability {
if (STREAM_COLLECT.test(call)) {
PsiExpression collector = call.getArgumentList().getExpressions()[0];
newMutability = UNMODIFIABLE_COLLECTORS.matches(collector) ? UNMODIFIABLE : UNKNOWN;
} else if (STREAM_TO_LIST.test(call)) {
newMutability = UNMODIFIABLE;
} else {
PsiMethod method = call.resolveMethod();
newMutability = method == null ? UNKNOWN : getMutability(method);
@@ -28,6 +28,7 @@ import com.intellij.codeInspection.dataFlow.types.DfType;
import com.intellij.codeInspection.dataFlow.types.DfTypes;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.dataFlow.value.RelationType;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
@@ -69,6 +70,8 @@ public class StreamChainInliner implements CallInliner {
instanceCall(JAVA_UTIL_STREAM_STREAM, "reduce").parameterTypes("T", "java.util.function.BinaryOperator");
private static final CallMatcher COLLECT_TERMINAL =
instanceCall(JAVA_UTIL_STREAM_STREAM, "collect").parameterTypes("java.util.stream.Collector");
private static final CallMatcher TO_LIST_TERMINAL = instanceCall(JAVA_UTIL_STREAM_STREAM, "toList")
.withLanguageLevelAtLeast(LanguageLevel.JDK_16);
private static final CallMatcher COLLECT3_TERMINAL =
instanceCall(JAVA_UTIL_STREAM_STREAM, "collect").parameterTypes("java.util.function.Supplier",
"java.util.function.BiConsumer", "java.util.function.BiConsumer");
@@ -142,6 +145,7 @@ public class StreamChainInliner implements CallInliner {
.register(TO_ARRAY_TERMINAL, call -> new ToArrayStep(call))
.register(COLLECT3_TERMINAL, call -> new Collect3TerminalStep(call))
.register(COLLECT_TERMINAL, call -> createTerminalFromCollector(call))
.register(TO_LIST_TERMINAL, call -> new ToCollectionStep(call, null, true))
.register(TWO_ARG_REDUCE, call -> new TwoArgReduceStep(call));
private static final Step NULL_TERMINAL_STEP = new Step(null, null, null) {
@@ -0,0 +1,41 @@
package java.util.stream;
import java.util.List;
import java.util.Iterator;
import java.util.Spliterator;
//mock
class Stream<T> implements BaseStream<T, Stream<T>>{
public native List<T> toList();
public native Iterator<T> iterator();
public native Spliterator<T> spliterator();
public native boolean isParallel();
public native Stream<T> sequential();
public native Stream<T> parallel();
public native Stream<T> unordered();
public native Stream<T> onClose(Runnable var1);
public native void close();
}
public class MutabilityJdk16 {
private final List<Integer> list = new Stream<Integer>().toList();
void testFieldList(){
list.<warning descr="Immutable object is modified">add</warning>(4);
}
void testToList() {
List<Integer> l = new Stream<Integer>()
.toList();
l.<warning descr="Immutable object is modified">add</warning>(4);
}
}
@@ -39,4 +39,6 @@ public class DataFlowInspection16Test extends DataFlowInspectionTestCase {
doTest();
}
public void testStaticFieldInAnonymous() { doTest(); }
public void testMutabilityJdk16() { doTest(); }
}