LFT-2910: Detect mutability from primary class constructors#977
Conversation
|
|
||
| public bool HasPrimaryClassConstructorMutability( INamedTypeSymbol @class ) { | ||
| foreach( var constructor in @class.InstanceConstructors ) { | ||
| foreach( var syntaxRef in constructor.DeclaringSyntaxReferences ) { |
There was a problem hiding this comment.
There is some open chatter in the compiler about exposing more of this stuff via the semantic model but the current situation is you need to go into the syntax.
There was a problem hiding this comment.
You might wonder like don't they show up as properties or something in the GetMembers() call earlier, and the answer is that no they don't.
| m_diagnosticSink( | ||
| Diagnostic.Create( | ||
| Diagnostics.PrimaryClassConstructorIntroducesMutability, | ||
| ctor.ParameterList.GetLocation() | ||
| ) | ||
| ); |
There was a problem hiding this comment.
So, this is only the case if the parameters get used outside of field initializers. Really we just want the Roslyn team's RS0062, or to add an equivalent.
https://andrewlock.net/blocking-primary-constructor-member-capture-using-an-analyzer/
using System;
sealed class A( string P ) {
void M() {
Console.WriteLine( P );
}
}
sealed class B( string P ) {
private readonly string m_p = P;
void M() {
Console.WriteLine( m_p );
}
}using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue | DebuggableAttribute.DebuggingModes.DisableOptimizations)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[NullableContext(1)]
[Nullable(0)]
internal sealed class A
{
public A(string P)
{
<P>P = P;
base..ctor();
}
private void M()
{
Console.WriteLine(<P>P);
}
}
[NullableContext(1)]
[Nullable(0)]
internal sealed class B
{
private readonly string m_p;
public B(string P)
{
m_p = P;
base..ctor();
}
private void M()
{
Console.WriteLine(m_p);
}
}There was a problem hiding this comment.
If you want to do this as a first pass though, 👍
There was a problem hiding this comment.
I'm not sure I agree with
Really we just want the Roslyn team's RS0062, or to add an equivalent.
In that I think this analyzer should stand on it's own (if that counts as "adding an equivalent" then OK).
As written this will prevent okay usages of primary class constructors for immutable types, so I do agree that this is a "first pass" in that sense (I wasn't planning to do any more of it, though -- this was motivated by the thread in Slack and existing (probably benign) usages that have snuck through).
There was a problem hiding this comment.
I guess this is probably 99% agreement, I'll chat with you on Slack about next steps
No description provided.