mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
DataFlowInspection: specific message for ioobe contracts, messages moved to resources
Fixes IDEA-180501 Confusing warning about list get method
This commit is contained in:
@@ -33,6 +33,13 @@ public abstract class ContractValue {
|
||||
|
||||
abstract DfaValue makeDfaValue(DfaValueFactory factory, DfaCallArguments arguments);
|
||||
|
||||
/**
|
||||
* @return true if this contract value represents a bounds-checking condition
|
||||
*/
|
||||
boolean isBoundCheckingCondition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ContractValue qualifier() {
|
||||
return Qualifier.INSTANCE;
|
||||
}
|
||||
@@ -160,6 +167,19 @@ public abstract class ContractValue {
|
||||
myRelationType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isBoundCheckingCondition() {
|
||||
switch (myRelationType) {
|
||||
case LE:
|
||||
case LT:
|
||||
case GE:
|
||||
case GT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
DfaValue makeDfaValue(DfaValueFactory factory, DfaCallArguments arguments) {
|
||||
return factory.createCondition(myLeft.makeDfaValue(factory, arguments), myRelationType, myRight.makeDfaValue(factory, arguments));
|
||||
|
||||
+14
-5
@@ -393,13 +393,21 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool
|
||||
private static void reportAlwaysFailingCalls(ProblemsHolder holder,
|
||||
DataFlowInstructionVisitor visitor,
|
||||
HashSet<PsiElement> reportedAnchors) {
|
||||
for (PsiCall call : visitor.getAlwaysFailingCalls()) {
|
||||
if (TestUtils.isExceptionExpected(call)) continue;
|
||||
visitor.getAlwaysFailingCalls().forEach((call, contracts) -> {
|
||||
if (TestUtils.isExceptionExpected(call)) return;
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if (method != null && reportedAnchors.add(call)) {
|
||||
holder.registerProblem(getElementToHighlight(call), "The call to '#ref' always fails, according to its method contracts");
|
||||
holder.registerProblem(getElementToHighlight(call), getContractMessage(contracts));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getContractMessage(List<MethodContract> contracts) {
|
||||
if (contracts.stream().allMatch(mc -> mc.getConditions().stream().allMatch(cv -> cv.isBoundCheckingCondition()))) {
|
||||
return InspectionsBundle.message("dataflow.message.contract.fail.index");
|
||||
}
|
||||
return InspectionsBundle.message("dataflow.message.contract.fail");
|
||||
}
|
||||
|
||||
@NotNull private static PsiElement getElementToHighlight(@NotNull PsiCall call) {
|
||||
@@ -965,8 +973,9 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool
|
||||
return myOptionalQualifiers;
|
||||
}
|
||||
|
||||
Collection<PsiCall> getAlwaysFailingCalls() {
|
||||
return StreamEx.ofKeys(myFailingCalls, v -> v).map(MethodCallInstruction::getCallExpression).toList();
|
||||
Map<PsiCall, List<MethodContract>> getAlwaysFailingCalls() {
|
||||
return StreamEx.ofKeys(myFailingCalls, v -> v)
|
||||
.mapToEntry(MethodCallInstruction::getCallExpression, MethodCallInstruction::getContracts).toMap();
|
||||
}
|
||||
|
||||
boolean isAlwaysReturnsNotNull(Instruction[] instructions) {
|
||||
|
||||
@@ -26,6 +26,6 @@ public final class ArrayLength {
|
||||
System.out.println("Impossible");
|
||||
}
|
||||
Arrays.fill(x, -1);
|
||||
Arrays.<warning descr="The call to 'fill' always fails, according to its method contracts">fill</warning>(x, -1, -1, -1);
|
||||
Arrays.<warning descr="The call to 'fill' always fails as index is out of bounds">fill</warning>(x, -1, -1, -1);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
public class CustomContracts {
|
||||
public void testSubstring(String s) {
|
||||
if (s.<warning descr="The call to 'substring' always fails, according to its method contracts">substring</warning>(-1).length() == 0) {
|
||||
if (s.<warning descr="The call to 'substring' always fails as index is out of bounds">substring</warning>(-1).length() == 0) {
|
||||
System.out.println("Oops");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class ForEachOverEmptyCollection {
|
||||
}
|
||||
if(!hasItem) {
|
||||
System.out.println(
|
||||
list.<warning descr="The call to 'get' always fails, according to its method contracts">get</warning>(<warning descr="Condition 'max == null' is always 'true'">max == null</warning> ? 0 : 1));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,13 +196,13 @@ public class LongRangeKnownMethods {
|
||||
|
||||
void testEmptyListGet(List<String> list) {
|
||||
if (list.isEmpty()) {
|
||||
System.out.println(list.<warning descr="The call to 'get' always fails, according to its method contracts">get</warning>(0));
|
||||
System.out.println(list.<warning descr="The call to 'get' always fails as index is out of bounds">get</warning>(0));
|
||||
}
|
||||
}
|
||||
|
||||
void testBoundError(List<String> list) {
|
||||
if (list.size() < 10) {
|
||||
System.out.println(list.<warning descr="The call to 'get' always fails, according to its method contracts">get</warning>(10));
|
||||
System.out.println(list.<warning descr="The call to 'get' always fails as index is out of bounds">get</warning>(10));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@ dataflow.message.npe.field.access=Dereference of <code>#ref</code> #loc may prod
|
||||
dataflow.message.cce=Casting <code>{0}</code> to <code>#ref</code> #loc may produce <code>java.lang.ClassCastException</code>
|
||||
dataflow.message.arraystore=Storing element of type <code>{0}</code> to array of <code>{1}</code> elements may produce <code>java.lang.ArrayStoreException</code>
|
||||
dataflow.message.redundant.instanceof=Condition <code>#ref</code> #loc is redundant and can be replaced with <code>!= null</code>
|
||||
dataflow.message.contract.fail=The call to '#ref' always fails, according to its method contracts
|
||||
dataflow.message.contract.fail.index=The call to '#ref' always fails as index is out of bounds
|
||||
dataflow.message.constant.condition=Condition <code>#ref</code> #loc is always <code>{0}</code>
|
||||
dataflow.message.constant.condition.when.reached=Condition <code>#ref</code> #loc is always <code>{0}</code> when reached
|
||||
dataflow.message.loop.on.empty.array=Array <code>#ref</code> is always empty
|
||||
|
||||
Reference in New Issue
Block a user