From cf2b33d39f609ee994c561f566237ff8738f6d5b Mon Sep 17 00:00:00 2001 From: Marco Kaufmann <83189575+kaufco@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:42:26 +0100 Subject: [PATCH] SONARJAVA-4508 Rule S2110: Add lower threshold to the Date values check (#4540) --- .../java/checks/InvalidDateValuesCheck.java | 6 ++- .../java/checks/InvalidDateValuesCheck.java | 53 ++++++++++++------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/java-checks-test-sources/default/src/main/java/checks/InvalidDateValuesCheck.java b/java-checks-test-sources/default/src/main/java/checks/InvalidDateValuesCheck.java index 4be26adf916..d2f6a0a3515 100644 --- a/java-checks-test-sources/default/src/main/java/checks/InvalidDateValuesCheck.java +++ b/java-checks-test-sources/default/src/main/java/checks/InvalidDateValuesCheck.java @@ -12,6 +12,8 @@ int foo() { Date d = new Date(); d.setDate(25); d.setDate(32);// Noncompliant [[sc=15;ec=17]] {{"32" is not a valid value for "setDate" method.}} + d.setDate(0);// Noncompliant [[sc=15;ec=16]] {{"0" is not a valid value for "setDate" method.}} + d.setDate(-1);// Noncompliant [[sc=15;ec=17]] {{"-1" is not a valid value for "setDate" method.}} d.setYear(2014); d.setMonth(11); d.setMonth(12); // Noncompliant {{"12" is not a valid value for "setMonth" method.}} @@ -70,6 +72,8 @@ int foo() { b = 31 == d.getDate(); b = foo() == d.getDate(); b = 32 == d.getDate(); // Noncompliant {{"32" is not a valid value for "getDate".}} + b = -1 == d.getDate(); // Noncompliant {{"-1" is not a valid value for "getDate".}} + b = 0 == d.getDate(); // Noncompliant {{"0" is not a valid value for "getDate".}} b = d1.getSeconds() == -1;// Noncompliant {{"-1" is not a valid value for "getSeconds".}} b = cal.get(Calendar.DST_OFFSET) == 0; return 0; @@ -90,5 +94,3 @@ class RollingCalendar extends GregorianCalendar { } } } - - diff --git a/java-checks/src/main/java/org/sonar/java/checks/InvalidDateValuesCheck.java b/java-checks/src/main/java/org/sonar/java/checks/InvalidDateValuesCheck.java index 9b960628e92..7a319e2a1d9 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/InvalidDateValuesCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/InvalidDateValuesCheck.java @@ -117,8 +117,7 @@ private static String getReferencedCalendarName(ExpressionTree argument) { reference = ((IdentifierTree) argument).symbol(); } if (reference != null && - reference.owner().type().is(JAVA_UTIL_CALENDAR) && - Threshold.getThreshold(reference.name()) != null) { + reference.owner().type().is(JAVA_UTIL_CALENDAR) && DateField.containsField(reference.name())) { return reference.name(); } return null; @@ -180,7 +179,8 @@ private void checkArgument(ExpressionTree arg, String name, String message) { } if (literal != null) { int argValue = Integer.parseInt(literal.value()) * sign; - if (argValue > Threshold.getThreshold(name) || argValue < 0) { + Range range = DateField.getFieldRange(name); + if (argValue > range.maxValue || argValue < range.minValue) { reportIssue(arg, MessageFormat.format(message, argValue, name)); } } @@ -190,41 +190,54 @@ private static String getMethodName(MethodInvocationTree mit) { return ExpressionUtils.methodName(mit).name(); } - private enum Threshold { - MONTH(11, "setMonth", "getMonth", "MONTH", "month"), - DATE(31, "setDate", "getDate", "DAY_OF_MONTH", "dayOfMonth"), - HOURS(23, "setHours", "getHours", "HOUR_OF_DAY", "hourOfDay"), - MINUTE(60, "setMinutes", "getMinutes", "MINUTE", "minute"), - SECOND(61, "setSeconds", "getSeconds", "SECOND", "second"); + private enum DateField { + MONTH(new Range(0, 11), "setMonth", "getMonth", "MONTH", "month"), + DATE(new Range(1, 31), "setDate", "getDate", "DAY_OF_MONTH", "dayOfMonth"), + HOURS(new Range(0, 23), "setHours", "getHours", "HOUR_OF_DAY", "hourOfDay"), + MINUTE(new Range(0, 60), "setMinutes", "getMinutes", "MINUTE", "minute"), + SECOND(new Range(0, 61), "setSeconds", "getSeconds", "SECOND", "second"); - private static Map thresholdByName = new HashMap<>(); + private static final Map rangeByName = new HashMap<>(); static { - for (Threshold value : Threshold.values()) { - thresholdByName.put(value.javaDateSetter, value.edgeValue); - thresholdByName.put(value.javaDateGetter, value.edgeValue); - thresholdByName.put(value.calendarConstant, value.edgeValue); - thresholdByName.put(value.gregorianParam, value.edgeValue); + for (DateField field : DateField.values()) { + rangeByName.put(field.javaDateSetter, field.range); + rangeByName.put(field.javaDateGetter, field.range); + rangeByName.put(field.calendarConstant, field.range); + rangeByName.put(field.gregorianParam, field.range); } } - private final int edgeValue; + private final Range range; private final String javaDateSetter; private final String javaDateGetter; private final String calendarConstant; private final String gregorianParam; - Threshold(int edgeValue, String javaDateSetter, String javaDateGetter, String calendarConstant, String gregorianParam) { - this.edgeValue = edgeValue; + DateField(Range range, String javaDateSetter, String javaDateGetter, String calendarConstant, String gregorianParam) { + this.range = range; this.javaDateSetter = javaDateSetter; this.javaDateGetter = javaDateGetter; this.calendarConstant = calendarConstant; this.gregorianParam = gregorianParam; } - public static Integer getThreshold(String name) { - return thresholdByName.get(name); + public static Range getFieldRange(String name) { + return rangeByName.get(name); + } + + public static boolean containsField(String name) { + return rangeByName.containsKey(name); } } + private static class Range { + public final int minValue; + public final int maxValue; + + private Range(int minValue, int maxValue) { + this.minValue = minValue; + this.maxValue = maxValue; + } + } }