GetFieldInstruction

This commit is contained in:
Tagir Valeev
2018-12-18 12:28:48 +07:00
parent 74c7e9a426
commit ce2a2e4305
18 changed files with 216 additions and 175 deletions
@@ -18,10 +18,7 @@ package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInsight.Nullability;
import com.intellij.codeInspection.dataFlow.inliner.CallInliner;
import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.dataFlow.value.DfaUnknownValue;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtil;
@@ -120,6 +117,21 @@ public class CFGBuilder {
return this;
}
/**
* Generate instructions to load a qualified field described by given source which qualifier is on the stack
* <p>
* Stack before: ... qualifier
* <p>
* Stack after: ... loaded_field
*
* @param source a {@link DfaVariableSource} which describes a field to load
* @param type a loaded field type
* @return this builder
*/
public CFGBuilder getField(@NotNull DfaVariableSource source, @Nullable PsiType type) {
return add(new GetFieldInstruction(source, type));
}
/**
* Generate instructions to push given variable value on stack for subsequent write.
* <p>
@@ -523,25 +523,23 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
if (iteratedValue != null) {
iteratedValue.accept(this);
addInstruction(new PopInstruction());
DfaValue qualifier = myFactory.createValue(iteratedValue);
if (qualifier instanceof DfaVariableValue) {
PsiType type = iteratedValue.getType();
SpecialField length = null;
if (type instanceof PsiArrayType) {
length = SpecialField.ARRAY_LENGTH;
}
else if (InheritanceUtil.isInheritor(type, JAVA_UTIL_COLLECTION)) {
length = SpecialField.COLLECTION_SIZE;
}
if (length != null) {
addInstruction(new PushInstruction(length.createValue(myFactory, qualifier), null));
addInstruction(new PushInstruction(myFactory.getInt(0), null));
addInstruction(new BinopInstruction(JavaTokenType.EQEQ, iteratedValue, PsiType.BOOLEAN));
addInstruction(new ConditionalGotoInstruction(loopEndOffset, false, null));
hasSizeCheck = true;
}
PsiType type = iteratedValue.getType();
SpecialField length = null;
if (type instanceof PsiArrayType) {
length = SpecialField.ARRAY_LENGTH;
}
else if (InheritanceUtil.isInheritor(type, JAVA_UTIL_COLLECTION)) {
length = SpecialField.COLLECTION_SIZE;
}
if (length != null) {
addInstruction(new GetFieldInstruction(length, PsiType.INT));
addInstruction(new PushInstruction(myFactory.getInt(0), null));
addInstruction(new BinopInstruction(JavaTokenType.EQEQ, iteratedValue, PsiType.BOOLEAN));
addInstruction(new ConditionalGotoInstruction(loopEndOffset, false, null));
hasSizeCheck = true;
} else {
addInstruction(new PopInstruction());
}
}
@@ -1495,7 +1493,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
if (TypeConversionUtil.isPrimitiveAndNotNull(expectedType) && TypeConversionUtil.isPrimitiveWrapper(actualType)) {
PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(actualType); // expectedType is not always precise unboxed type
addInstruction(new UnboxingInstruction(unboxedType));
addInstruction(new GetFieldInstruction(SpecialField.UNBOX, unboxedType));
}
else if (TypeConversionUtil.isPrimitiveAndNotNull(actualType) && TypeConversionUtil.isAssignableFromPrimitiveWrapper(expectedType)) {
addConditionalRuntimeThrow();
@@ -598,7 +598,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (value instanceof DfaVariableValue) {
PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(value.getType());
if (unboxedType != null) {
value = myFactory.getBoxedFactory().createUnboxed(value, unboxedType);
value = SpecialField.UNBOX.createValue(myFactory, value, unboxedType);
}
EqClass ec = getEqClass(value);
return ec == null ? null : ec.findConstant();
@@ -948,9 +948,8 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return true;
}
DfaBoxedValue.Factory boxedFactory = myFactory.getBoxedFactory();
DfaValue unboxedLeft = boxedFactory.createUnboxed(dfaLeft, null);
DfaValue unboxedRight = boxedFactory.createUnboxed(dfaRight, null);
DfaValue unboxedLeft = SpecialField.UNBOX.createValue(myFactory, dfaLeft);
DfaValue unboxedRight = SpecialField.UNBOX.createValue(myFactory, dfaRight);
DfaConstValue leftConst = getConstantValue(unboxedLeft);
DfaConstValue rightConst = getConstantValue(unboxedRight);
if (leftConst != null && rightConst != null) {
@@ -354,7 +354,7 @@ public class DfaUtil {
if (TypeConversionUtil.isPrimitiveAndNotNull(type)) {
if (value instanceof DfaBoxedValue ||
(value instanceof DfaVariableValue && TypeConversionUtil.isPrimitiveWrapper(value.getType()))) {
return value.getFactory().getBoxedFactory().createUnboxed(value, ObjectUtils.tryCast(type, PsiPrimitiveType.class));
return SpecialField.UNBOX.createValue(value.getFactory(), value, type);
}
}
return value;
@@ -159,9 +159,10 @@ public abstract class InstructionVisitor {
return nextInstruction(instruction, runner, state);
}
public DfaInstructionState[] visitUnbox(UnboxingInstruction instruction, DataFlowRunner runner, DfaMemoryState state) {
public DfaInstructionState[] visitGetField(GetFieldInstruction instruction, DataFlowRunner runner, DfaMemoryState state) {
DfaValue value = state.pop();
state.push(runner.getFactory().getBoxedFactory().createUnboxed(value, instruction.getTargetType()));
DfaValue field = instruction.getSource().createValue(runner.getFactory(), value, instruction.getTargetType());
pushExpressionResult(field, instruction, state);
return nextInstruction(instruction, runner, state);
}
@@ -94,6 +94,15 @@ public enum SpecialField implements DfaVariableSource {
return DfaUnknownValue.getInstance();
}
@NotNull
@Override
public DfaValue createValue(@NotNull DfaValueFactory factory, @Nullable DfaValue qualifier, PsiType targetType) {
if (qualifier instanceof DfaBoxedValue) {
return ((DfaBoxedValue)qualifier).getWrappedValue();
}
return super.createValue(factory, qualifier, targetType);
}
@Override
boolean isMyQualifierType(PsiType type) {
return TypeConversionUtil.isPrimitiveWrapper(type);
@@ -157,19 +166,14 @@ public enum SpecialField implements DfaVariableSource {
* @param qualifier a known qualifier value
* @return a DfaValue which represents this special field
*/
public DfaValue createValue(DfaValueFactory factory, DfaValue qualifier) {
@NotNull
public final DfaValue createValue(@NotNull DfaValueFactory factory, @Nullable DfaValue qualifier) {
return createValue(factory, qualifier, null);
}
/**
* Returns a DfaValue which represents this special field
*
* @param factory a factory to create new values if necessary
* @param qualifier a known qualifier value
* @param targetType a type of created value
* @return a DfaValue which represents this special field
*/
public DfaValue createValue(DfaValueFactory factory, DfaValue qualifier, PsiType targetType) {
@NotNull
@Override
public DfaValue createValue(@NotNull DfaValueFactory factory, @Nullable DfaValue qualifier, PsiType targetType) {
if (qualifier instanceof DfaVariableValue) {
DfaVariableValue variableValue = (DfaVariableValue)qualifier;
PsiModifierListOwner psiVariable = variableValue.getPsiVariable();
@@ -185,7 +189,7 @@ public enum SpecialField implements DfaVariableSource {
}
}
}
return factory.getVarFactory().createVariableValue(this, targetType == null ? getType(variableValue) : targetType, variableValue);
return DfaVariableSource.super.createValue(factory, qualifier, targetType == null ? getType(variableValue) : targetType);
}
if(qualifier instanceof DfaFactMapValue) {
SpecialFieldValue sfValue = ((DfaFactMapValue)qualifier).get(DfaFactType.SPECIAL_FIELD_VALUE);
@@ -5,7 +5,6 @@ import com.intellij.codeInspection.dataFlow.value.DfaConstValue;
import com.intellij.codeInspection.dataFlow.value.DfaFactMapValue;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
@@ -14,7 +13,7 @@ import java.util.Objects;
*/
public final class SpecialFieldValue {
private final @NotNull SpecialField myField;
private final @Nullable DfaValue myValue;
private final @NotNull DfaValue myValue;
public SpecialFieldValue(@NotNull SpecialField field, @NotNull DfaValue value) {
if (value instanceof DfaFactMapValue) {
@@ -34,7 +33,7 @@ public final class SpecialFieldValue {
return myField;
}
@Nullable
@NotNull
public DfaValue getValue() {
return myValue;
}
@@ -512,13 +512,9 @@ public class StandardInstructionVisitor extends InstructionVisitor {
if (instruction.getContext() instanceof PsiMethodReferenceExpression && qualifierValue instanceof DfaVariableValue) {
PsiMethod method = instruction.getTargetMethod();
SpecialField field = SpecialField.findSpecialField(method);
if (field != null) {
return field.createValue(factory, qualifierValue);
}
DfaVariableSource source = DfaExpressionFactory.getAccessedVariableOrGetter(method);
if (source != null) {
return factory.getVarFactory().createVariableValue(source, instruction.getResultType(), (DfaVariableValue)qualifierValue);
return source.createValue(factory, qualifierValue, instruction.getResultType());
}
}
@@ -725,42 +725,31 @@ public class StreamChainInliner implements CallInliner {
.chain(firstStep::iteration);
return;
}
PsiExpression qualifierExpression = null;
SpecialField sizeField = null;
if (array) {
PsiExpression qualifierExpression = sourceCall.getArgumentList().getExpressions()[0];
DfaValue qualifierValue = builder.getFactory().createValue(qualifierExpression);
if (qualifierValue != null) {
builder.pushExpression(qualifierExpression)
.chain(firstStep::before)
.pop()
.push(SpecialField.ARRAY_LENGTH.createValue(builder.getFactory(), qualifierValue))
.push(builder.getFactory().getInt(0))
.ifCondition(JavaTokenType.GT)
.chain(b -> makeMainLoop(b, firstStep, inType))
.end();
return;
}
qualifierExpression = sourceCall.getArgumentList().getExpressions()[0];
sizeField = SpecialField.ARRAY_LENGTH;
}
if (COLLECTION_STREAM.test(sourceCall)) {
PsiExpression qualifierExpression = sourceCall.getMethodExpression().getQualifierExpression();
DfaValue qualifierValue = builder.getFactory().createValue(qualifierExpression);
if (qualifierValue != null) {
builder.pushExpression(qualifierExpression)
.chain(firstStep::before)
.pop()
.push(SpecialField.COLLECTION_SIZE.createValue(builder.getFactory(), qualifierValue))
.push(builder.getFactory().getInt(0))
.ifCondition(JavaTokenType.GT)
.chain(b -> makeMainLoop(b, firstStep, inType))
.end();
return;
}
else if (COLLECTION_STREAM.test(sourceCall)) {
qualifierExpression = sourceCall.getMethodExpression().getQualifierExpression();
sizeField = SpecialField.COLLECTION_SIZE;
}
if (qualifierExpression != null) {
builder.pushExpression(qualifierExpression)
.chain(firstStep::before)
.getField(sizeField, PsiType.INT)
.push(builder.getFactory().getInt(0))
.ifCondition(JavaTokenType.GT);
} else {
builder
.pushExpression(originalQualifier)
.pop()
.chain(firstStep::before)
.pushUnknown()
.ifConditionIs(true);
}
builder
.pushExpression(originalQualifier)
.pop()
.chain(firstStep::before)
.pushUnknown()
.ifConditionIs(true)
.chain(b -> makeMainLoop(b, firstStep, inType))
.end();
}
@@ -0,0 +1,57 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.dataFlow.instructions;
import com.intellij.codeInspection.dataFlow.DataFlowRunner;
import com.intellij.codeInspection.dataFlow.DfaInstructionState;
import com.intellij.codeInspection.dataFlow.DfaMemoryState;
import com.intellij.codeInspection.dataFlow.InstructionVisitor;
import com.intellij.codeInspection.dataFlow.value.DfaVariableSource;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Instruction to push a field qualified by the value on the stack
*/
public class GetFieldInstruction extends Instruction implements ExpressionPushingInstruction {
@Nullable private final PsiType myTargetType;
@NotNull private final DfaVariableSource mySource;
@Nullable private final PsiExpression myAnchor;
public GetFieldInstruction(@NotNull DfaVariableSource source, @Nullable PsiType targetType) {
this(null, source, targetType);
}
public GetFieldInstruction(@Nullable PsiExpression anchor, @NotNull DfaVariableSource source, @Nullable PsiType targetType) {
myTargetType = targetType;
mySource = source;
myAnchor = anchor;
}
@Override
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor) {
return visitor.visitGetField(this, runner, stateBefore);
}
@NotNull
public DfaVariableSource getSource() {
return mySource;
}
@Nullable
public PsiType getTargetType() {
return myTargetType;
}
@Override
public String toString() {
return "GET_FIELD " + mySource;
}
@Nullable
@Override
public PsiExpression getExpression() {
return myAnchor;
}
}
@@ -1,32 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.dataFlow.instructions;
import com.intellij.codeInspection.dataFlow.DataFlowRunner;
import com.intellij.codeInspection.dataFlow.DfaInstructionState;
import com.intellij.codeInspection.dataFlow.DfaMemoryState;
import com.intellij.codeInspection.dataFlow.InstructionVisitor;
import com.intellij.psi.PsiPrimitiveType;
import org.jetbrains.annotations.Nullable;
public class UnboxingInstruction extends Instruction {
@Nullable private final PsiPrimitiveType myTargetType;
public UnboxingInstruction(@Nullable PsiPrimitiveType targetType) {
myTargetType = targetType;
}
@Override
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor) {
return visitor.visitUnbox(this, runner, stateBefore);
}
@Nullable
public PsiPrimitiveType getTargetType() {
return myTargetType;
}
@Override
public String toString() {
return "UNBOX";
}
}
@@ -16,7 +16,6 @@
package com.intellij.codeInspection.dataFlow.value;
import com.intellij.codeInspection.dataFlow.*;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.psi.PsiType;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NonNls;
@@ -84,14 +83,5 @@ public class DfaBoxedValue extends DfaValue {
}
return null;
}
@NotNull
public DfaValue createUnboxed(DfaValue value, PsiPrimitiveType targetType) {
if (value instanceof DfaBoxedValue) {
return ((DfaBoxedValue)value).getWrappedValue();
}
return SpecialField.UNBOX.createValue(myFactory, value, targetType);
}
}
}
@@ -139,43 +139,21 @@ public class DfaExpressionFactory {
}
private DfaValue createReferenceValue(@NotNull PsiReferenceExpression refExpr) {
DfaValue specialValue = createFromSpecialField(refExpr);
if (specialValue != null) {
return specialValue;
PsiElement target = refExpr.resolve();
if (target instanceof PsiVariable) {
PsiVariable variable = (PsiVariable)target;
if (variable.hasModifierProperty(PsiModifier.FINAL) && !PsiUtil.isAccessedForWriting(refExpr)) {
DfaValue constValue = myFactory.getConstFactory().create(variable);
if (constValue != null && !maybeUninitializedConstant(constValue, refExpr, variable)) return constValue;
}
}
DfaVariableSource var = getAccessedVariableOrGetter(refExpr.resolve());
DfaVariableSource var = getAccessedVariableOrGetter(target);
if (var == null) {
return null;
}
PsiModifierListOwner psiElement = var.getPsiElement();
boolean isVolatile = psiElement != null && psiElement.hasModifierProperty(PsiModifier.VOLATILE);
if (isVolatile) {
PsiType type = refExpr.getType();
return myFactory.createTypeValue(type, DfaPsiUtil.getElementNullability(type, psiElement));
}
if (psiElement instanceof PsiVariable && ((PsiVariable)psiElement).getType().equalsToText(CommonClassNames.JAVA_LANG_VOID)) {
return myFactory.getConstFactory().getNull();
}
if (psiElement instanceof PsiVariable && psiElement.hasModifierProperty(PsiModifier.FINAL) && !PsiUtil.isAccessedForWriting(refExpr)) {
DfaValue constValue = myFactory.getConstFactory().create((PsiVariable)psiElement);
if (constValue != null && !maybeUninitializedConstant(constValue, refExpr, psiElement)) return constValue;
}
if (psiElement instanceof PsiLocalVariable || psiElement instanceof PsiParameter ||
(psiElement instanceof PsiField &&
psiElement.hasModifierProperty(PsiModifier.STATIC) &&
!psiElement.hasModifierProperty(PsiModifier.FINAL)) ||
isStaticFinalConstantWithoutInitializationHacks(psiElement) ||
(psiElement instanceof PsiMethod && psiElement.hasModifierProperty(PsiModifier.STATIC))) {
return myFactory.getVarFactory().createVariableValue(var, refExpr.getType());
}
DfaVariableValue qualifier = getQualifierOrThisVariable(refExpr);
PsiType type = refExpr.getType();
if (qualifier != null) {
return myFactory.getVarFactory().createVariableValue(var, type, qualifier);
}
return myFactory.createTypeValue(type, DfaPsiUtil.getElementNullability(type, psiElement));
return var.createValue(myFactory, qualifier, refExpr.getType());
}
/**
@@ -236,25 +214,13 @@ public class DfaExpressionFactory {
return PsiTreeUtil.getTopmostParentOfType(refExpr, PsiClass.class) == PsiTreeUtil.getTopmostParentOfType(var, PsiClass.class);
}
private static boolean isStaticFinalConstantWithoutInitializationHacks(PsiModifierListOwner var) {
return (var instanceof PsiField && var.hasModifierProperty(PsiModifier.FINAL) && var.hasModifierProperty(PsiModifier.STATIC)) &&
!DfaUtil.hasInitializationHacks((PsiField)var);
}
@Nullable
private DfaValue createFromSpecialField(PsiReferenceExpression refExpr) {
PsiElement target = refExpr.resolve();
if (!(target instanceof PsiModifierListOwner)) return null;
SpecialField sf = SpecialField.findSpecialField(target);
if (sf == null) return null;
DfaVariableValue qualifier = getQualifierOrThisVariable(refExpr);
if (qualifier == null) return null;
return sf.createValue(myFactory, qualifier);
}
@Contract("null -> null")
@Nullable
public static DfaVariableSource getAccessedVariableOrGetter(final PsiElement target) {
SpecialField sf = SpecialField.findSpecialField(target);
if (sf != null) {
return sf;
}
if (target instanceof PsiVariable) {
return new PlainSource((PsiVariable)target);
}
@@ -351,7 +317,7 @@ public class DfaExpressionFactory {
}
ArrayElementSource indexVariable = getArrayIndexVariable(index);
if (indexVariable == null) return null;
return myFactory.getVarFactory().createVariableValue(indexVariable, componentType, arrayDfaVar);
return indexVariable.createValue(myFactory, arrayDfaVar, componentType);
}
@Nullable
@@ -387,6 +353,23 @@ public class DfaExpressionFactory {
myVariable.hasModifierProperty(PsiModifier.FINAL);
}
@NotNull
@Override
public DfaValue createValue(@NotNull DfaValueFactory factory, @Nullable DfaValue qualifier, @Nullable PsiType type) {
if (myVariable.getType().equalsToText(CommonClassNames.JAVA_LANG_VOID)) {
return factory.getConstFactory().getNull();
}
if (myVariable.hasModifierProperty(PsiModifier.VOLATILE)) {
return factory.createTypeValue(type, DfaPsiUtil.getElementNullability(type, myVariable));
}
if (myVariable instanceof PsiLocalVariable || myVariable instanceof PsiParameter ||
(myVariable instanceof PsiField && myVariable.hasModifierProperty(PsiModifier.STATIC) &&
(!myVariable.hasModifierProperty(PsiModifier.FINAL) || !DfaUtil.hasInitializationHacks((PsiField)myVariable)))) {
return factory.getVarFactory().createVariableValue(this, type);
}
return DfaVariableSource.super.createValue(factory, qualifier, type);
}
@Override
public boolean equals(Object obj) {
return obj == this || obj instanceof PlainSource && ((PlainSource)obj).myVariable == myVariable;
@@ -422,6 +405,15 @@ public class DfaExpressionFactory {
return true;
}
@NotNull
@Override
public DfaValue createValue(@NotNull DfaValueFactory factory, @Nullable DfaValue qualifier, @Nullable PsiType type) {
if (myGetter.hasModifierProperty(PsiModifier.STATIC)) {
return factory.getVarFactory().createVariableValue(this, type);
}
return DfaVariableSource.super.createValue(factory, qualifier, type);
}
@Override
public boolean equals(Object obj) {
return obj == this || (obj instanceof GetterSource && ((GetterSource)obj).myGetter == myGetter);
@@ -1,11 +1,14 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.dataFlow.value;
import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a source of {@link DfaVariableValue}. Two variables are the same if they have the same source, qualifier and negation flag.
* Represents a source of {@link DfaVariableValue}. Two variables are the same if they have the same source and qualifier.
* A source could be a PsiVariable, getter method, array element with given index, this expression, etc.
* <p>
* Subclasses must have proper {@link Object#equals(Object)} and implementation or instantiation must be controlled to prevent
@@ -38,4 +41,19 @@ public interface DfaVariableSource {
*/
@Override
String toString();
/**
* Returns a value which describes the field qualified by given qualifier and described by this source
* @param factory factory to use
* @param qualifier qualifier to use
* @param type field type
* @return a field value
*/
@NotNull
default DfaValue createValue(@NotNull DfaValueFactory factory, @Nullable DfaValue qualifier, @Nullable PsiType type) {
if (qualifier instanceof DfaVariableValue) {
return factory.getVarFactory().createVariableValue(this, type, (DfaVariableValue)qualifier);
}
return factory.createTypeValue(type, DfaPsiUtil.getElementNullability(type, getPsiElement()));
}
}
@@ -74,9 +74,9 @@ public final class DfaVariableValue extends DfaValue {
}
@NotNull
public DfaVariableValue createVariableValue(@NotNull DfaVariableSource source,
@Nullable PsiType varType,
@Nullable DfaVariableValue qualifier) {
DfaVariableValue createVariableValue(@NotNull DfaVariableSource source,
@Nullable PsiType varType,
@Nullable DfaVariableValue qualifier) {
Pair<String, DfaVariableValue> key = Pair.create(source.toString(), qualifier);
for (DfaVariableValue aVar : myExistingVars.get(key)) {
if (aVar.hardEquals(source, varType, qualifier)) return aVar;
@@ -28,6 +28,10 @@ class ArrayInitializerLength {
for (int i : <warning descr="Array 'arr' is always empty">arr</warning>) {
System.out.println("never");
}
int length = 0;
for (int i : <warning descr="Array 'new int[length]' is always empty">new int[length]</warning>) {
System.out.println(i);
}
}
void testConditional() {
@@ -1,4 +1,5 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class ForEachOverEmptyCollection {
@@ -56,4 +57,10 @@ public class ForEachOverEmptyCollection {
list.<warning descr="The call to 'get' always fails as index is out of bounds">get</warning>(<warning descr="Condition 'max == null' is always 'true'">max == null</warning> ? 0 : 1));
}
}
void testDirect() {
for (Object o : <warning descr="Collection 'Collections.emptyList()' is always empty">Collections.emptyList()</warning>) {
System.out.println(o);
}
}
}
@@ -257,4 +257,11 @@ public class StreamInlining {
System.out.println("found");
}
}
void testImmediateCollection() {
String result = Collections.singleton(" foo ").stream().map(String::trim).findFirst().orElse(null);
if (<warning descr="Condition 'result == null' is always 'false'">result == null</warning>) {
System.out.println("impossible");
}
}
}