Skip to content

Commit d23a1dd

Browse files
Add a model of String.format
This uses CProverString.format which is builtin in the string solver.
1 parent 59cfa41 commit d23a1dd

File tree

1 file changed

+58
-5
lines changed

1 file changed

+58
-5
lines changed

src/main/java/java/lang/String.java

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3884,6 +3884,46 @@ public char[] toCharArray() {
38843884
return result;
38853885
}
38863886

3887+
/**
3888+
* Helper function for the {@code format} function.
3889+
* Serialize potential String.format argument to a String.
3890+
* The returned String is never null.
3891+
*/
3892+
static String cproverFormatArgument(Object obj) {
3893+
if (obj == null) return "null";
3894+
if (obj instanceof String) return (String) obj;
3895+
3896+
// All primitive types are cast to a long
3897+
long longValue = 0;
3898+
if (obj instanceof Integer) {
3899+
longValue = (Integer) obj;
3900+
} else if (obj instanceof Long) {
3901+
longValue = (Long) obj;
3902+
} else if (obj instanceof Float) {
3903+
longValue = (long) ((Float) obj).doubleValue();
3904+
} else if (obj instanceof Double) {
3905+
longValue = (long) ((Double) obj).doubleValue();
3906+
} else if (obj instanceof Character) {
3907+
char charValue = (Character) obj;
3908+
longValue = (long) charValue;
3909+
} else if (obj instanceof Byte) {
3910+
byte byteValue = ((Byte) obj);
3911+
longValue = (long) byteValue;
3912+
} else if (obj instanceof Boolean) {
3913+
longValue = ((Boolean) obj) ? 1 : 0;
3914+
} else {
3915+
return CProver.nondetWithoutNull("");
3916+
}
3917+
3918+
// The long value is encoded using a string of 4 characters
3919+
StringBuilder builder = new StringBuilder();
3920+
builder.append((char) (longValue >> 48 & 0xFFFF));
3921+
builder.append((char) (longValue >> 32 & 0xFFFF));
3922+
builder.append((char) (longValue >> 16 & 0xFFFF));
3923+
builder.append((char) (longValue & 0xFFFF));
3924+
return builder.toString();
3925+
}
3926+
38873927
/**
38883928
* Returns a formatted string using the specified format string and
38893929
* arguments.
@@ -3946,9 +3986,23 @@ public char[] toCharArray() {
39463986
* @diffblue.untested
39473987
*/
39483988
public static String format(String format, Object... args) {
3949-
// DIFFBLUE MODEL LIBRARY This is treated internally in CBMC
3950-
return CProver.nondetWithoutNullForNotModelled();
39513989
// return new Formatter().format(format, args).toString();
3990+
// DIFFBLUE MODEL LIBRARY
3991+
if (args.length > 10) {
3992+
return CProver.nondetWithoutNull("");
3993+
}
3994+
String arg0 = args.length > 0 ? cproverFormatArgument(args[0]) : "";
3995+
String arg1 = args.length > 1 ? cproverFormatArgument(args[1]) : "";
3996+
String arg2 = args.length > 2 ? cproverFormatArgument(args[2]) : "";
3997+
String arg3 = args.length > 3 ? cproverFormatArgument(args[3]) : "";
3998+
String arg4 = args.length > 4 ? cproverFormatArgument(args[4]) : "";
3999+
String arg5 = args.length > 5 ? cproverFormatArgument(args[5]) : "";
4000+
String arg6 = args.length > 6 ? cproverFormatArgument(args[6]) : "";
4001+
String arg7 = args.length > 7 ? cproverFormatArgument(args[7]) : "";
4002+
String arg8 = args.length > 8 ? cproverFormatArgument(args[8]) : "";
4003+
String arg9 = args.length > 9 ? cproverFormatArgument(args[9]) : "";
4004+
return CProverString.format(format, arg0, arg1, arg2, arg3, arg4, arg5,
4005+
arg6, arg7, arg8, arg9);
39524006
}
39534007

39544008
/**
@@ -3988,12 +4042,11 @@ public static String format(String format, Object... args) {
39884042
* @see java.util.Formatter
39894043
* @since 1.5
39904044
*
3991-
* @diffblue.noSupport
4045+
* @diffblue.limitedSupport The locale argument is ignored
39924046
*/
39934047
public static String format(Locale l, String format, Object... args) {
39944048
// return new Formatter(l).format(format, args).toString();
3995-
CProver.notModelled();
3996-
return CProver.nondetWithoutNullForNotModelled();
4049+
return format(format, args);
39974050
}
39984051

39994052
/**

0 commit comments

Comments
 (0)