Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions csharp/ql/src/Useless code/DefaultToStringQuery.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down
4 changes: 4 additions & 0 deletions csharp/ql/src/change-notes/2025-02-24-object-tostring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* C#: Improve precision of the query `cs/call-to-object-tostring` for value tuples.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ void M()

IPublic g = null;
Console.WriteLine(g); // GOOD

Console.WriteLine(new ValueTuple<int, int>(1, 2)); // GOOD

Console.WriteLine((1, 2)); // GOOD

var t1 = new ValueTuple<int, DefaultToString>(1, new DefaultToString());
Console.WriteLine(t1); // BAD

var t2 = new ValueTuple<A, D>(new A(), new D());
Console.WriteLine(t2); // GOOD
}

class A
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[] |
Expand Down