diff --git a/csharp/ql/src/Useless code/DefaultToStringQuery.qll b/csharp/ql/src/Useless code/DefaultToStringQuery.qll index 9185756b0a95..f11b5a9cd324 100644 --- a/csharp/ql/src/Useless code/DefaultToStringQuery.qll +++ b/csharp/ql/src/Useless code/DefaultToStringQuery.qll @@ -46,6 +46,7 @@ private predicate alwaysInvokesToString(ParameterRead pr) { * method from `System.Object` or `System.ValueType`. */ predicate alwaysDefaultToString(ValueOrRefType t) { + not t instanceof TupleType and exists(ToStringMethod m | t.hasMethod(m) | m.getDeclaringType() instanceof SystemObjectClass or m.getDeclaringType() instanceof SystemValueTypeClass @@ -55,6 +56,11 @@ predicate alwaysDefaultToString(ValueOrRefType t) { overriding.getABaseType+() = t ) and ((t.isAbstract() or t instanceof Interface) implies not t.isEffectivelyPublic()) + or + exists(ValueOrRefType elem | + elem = t.(TupleType).getElementType(_) and + alwaysDefaultToString(elem) + ) } class DefaultToStringType extends ValueOrRefType { diff --git a/csharp/ql/src/change-notes/2025-02-24-object-tostring.md b/csharp/ql/src/change-notes/2025-02-24-object-tostring.md new file mode 100644 index 000000000000..9dff09fb07a3 --- /dev/null +++ b/csharp/ql/src/change-notes/2025-02-24-object-tostring.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* C#: Improve precision of the query `cs/call-to-object-tostring` for value tuples. diff --git a/csharp/ql/test/query-tests/Useless Code/DefaultToString/DefaultToString.cs b/csharp/ql/test/query-tests/Useless Code/DefaultToString/DefaultToString.cs index 6fe7850d781b..2d6ea91f71e0 100644 --- a/csharp/ql/test/query-tests/Useless Code/DefaultToString/DefaultToString.cs +++ b/csharp/ql/test/query-tests/Useless Code/DefaultToString/DefaultToString.cs @@ -35,6 +35,16 @@ void M() IPublic g = null; Console.WriteLine(g); // GOOD + + Console.WriteLine(new ValueTuple(1, 2)); // GOOD + + Console.WriteLine((1, 2)); // GOOD + + var t1 = new ValueTuple(1, new DefaultToString()); + Console.WriteLine(t1); // BAD + + var t2 = new ValueTuple(new A(), new D()); + Console.WriteLine(t2); // GOOD } class A diff --git a/csharp/ql/test/query-tests/Useless Code/DefaultToString/DefaultToString.expected b/csharp/ql/test/query-tests/Useless Code/DefaultToString/DefaultToString.expected index b3f3dcdd72de..c856d4ff4d00 100644 --- a/csharp/ql/test/query-tests/Useless Code/DefaultToString/DefaultToString.expected +++ b/csharp/ql/test/query-tests/Useless Code/DefaultToString/DefaultToString.expected @@ -2,7 +2,8 @@ | DefaultToString.cs:10:28:10:28 | access to local variable d | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | DefaultToString.cs:4:14:4:28 | DefaultToString | DefaultToString | | DefaultToString.cs:16:27:16:30 | access to local variable ints | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | Int32[] | Int32[] | | DefaultToString.cs:19:24:19:27 | access to local variable ints | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | Int32[] | Int32[] | -| DefaultToString.cs:34:27:34:27 | access to local variable f | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | DefaultToString.cs:62:23:62:30 | IPrivate | IPrivate | +| DefaultToString.cs:34:27:34:27 | access to local variable f | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | DefaultToString.cs:72:23:72:30 | IPrivate | IPrivate | +| DefaultToString.cs:44:27:44:28 | (...) ... | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | (Int32,DefaultToString) | (Int32,DefaultToString) | | DefaultToStringBad.cs:8:35:8:35 | access to local variable p | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | DefaultToStringBad.cs:14:11:14:16 | Person | Person | | DefaultToStringBad.cs:11:38:11:41 | access to local variable ints | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | Int32[] | Int32[] | | WriteLineArray.cs:7:23:7:26 | access to parameter args | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | String[] | String[] |