Open terrajobst opened 4 years ago
Tagging subscribers to this area: @dotnet/area-system-runtime See info in area-owners.md if you want to be subscribed.
Author: | terrajobst |
---|---|
Assignees: | jeffhandley |
Labels: | `api-needs-work`, `area-System.Runtime`, `code-analyzer` |
Milestone: | 8.0.0 |
Could this also allow for specifying a list of fully-qualified return types that must never be ignored?
For example, I have Result
and Result<TValue>
types that are returned from many different methods. It would be a lot easier to configure these types as "DoNotIgnore", as opposed to applying the DoNotIgnore
attribute to every method.
@glen-84 , when you write "fully-qualified", do you mean you might want to warn about ignoring List<VeryImportant>
but not warn about ignoring List<WhoCares>
?
@KalleOlaviNiemitalo I was referring mainly to the namespace. I haven't considered generic type arguments.
Hi,
Sorry for a shameless self-promotion.
While the official analyzer is in works, you might consider checking out this one https://github.com/mykolav/must-use-ret-val-fs
It emits a diagnostic if it comes across code that ignores the value returned from a method marked with [MustUseReturnValue]
.
Would you consider extending that to allow types too?
+1
I wrote a promise library where each promise object is required to either be awaited, or forgotten. Using discard instead of Forget is wrong. It looks like this proposal treats discards as "not ignored", but I would want it to treat it as "ignored". Could that be configurable?
Were there any discussions around alternatives to an attribute in this case? For example, what about using required
before the return type to signal it must be consumed by the caller?
public required Task<int> ReadAsync(...);
It feels more "first-class" to me to have it as a language keyword vs an attribute.
Additionally, it could also be used to signal similar semantics for other cases, such as if you want to enforce a given out
parameter to not be discarded as well:
public void MyMethod(required out int value);
In .NET APIs, calling methods for side effects is the norm. Thus, it's generally OK to call a method and discard the result. For example,
List<T>
sRemove()
method returns a Boolean, indicating whether anything was removed. Ignoring this is just fine.However, there are cases where ignoring the return value is a 100% a bug. For example,
ImmutableList<T>
'sAdd()
has no side effects and instead returns a new list with the item being added. If you're discarding the return value, then you're not actually doing anything but heating up your CPU and give work to the GC. And your code probably isn't working the way you thought it was.We should add the ability for specific APIs to be marked as "do not ignore return value", and have an analyzer that flags callsites to these methods that don't capture the return value.
Proposal
Suggested severity: Info Suggested category: Reliability
Methods to annotate
[Pure]
, but were removed with #35118.The general rule is that we only annotate APIs where there is a very high likelihood that your code is a mistake. If there are generally valid reasons for ignoring a result (like creating new objects can have side-effects, ignoring TryParse and use the default, etc.), we won't annotate the API with
[DoNotIgnore]
.Usage
If a method is annotated with
[return: DoNotIgnore]
, discarding the return value should be a flagged:Annotating
{Value}Task<T>
Methods marked with
[return: DoNotIgnore]
that returnTask<T>
orValueTask<T>
will be handled to apply both to the Task that is returned, as well as itsawait
ed result.DoNotIgnore on parameters
DoNotIgnoreAttribute is only valid on
ref
andout
parameters - values that are returned from a method. We should flag annotating normal,in
, andref readonly
parameters with[DoNotIgnore]
.Interaction with CA1806
The
DoNotIgnoreAttribute
will use a newRule ID
distinct fromCA1806
. The reason for this is:CA1806
is in the "Performance" category. It is concerned with doing unnecessary operations: ignoring new objects, unnecessary LINQ operations, etc.DoNotIgnoreAttribute
is about correctness and is in theReliability
category.Of the rules for
CA1806
:new
objectsThe only APIs that will also be marked
[return: DoNotIgnore]
are the string creation APIs. The only valid scenario to ignore one of the string APIs results that I've found is totry-catch
around astring.Format
call, and catchFormatException
to do validation and throw some other exception. When the string creation APIs are annotated with[return: DoNotIgnore]
, the new Rule ID will be raised, andCA1806
won't fire. But for older TFMs where the new attribute doesn't exist,CA1806
will still be raised.