Port Dispose analyzers (DisposeObjectsBeforeLosingScope and DisposableFieldsShouldBeDisposed)#35248
Conversation
(DisposableFieldsShouldBeDisposed) We will now flag disposable creations in methods that do not escape the method body (return value, out/ref params, assign to field/property, add to collection, etc.). Additionally, we also flag disposable fields of disposable types that are not disposed in the type's Dispose method. Ported analyzers share the core dataflow analysis computation with the analyzers in the roslyn-analyzers repo (Microsoft.CodeAnalysis.FlowAnalysis.Utilities). This PR does not add any code fixes. We already have a code refactoring that offers wrapping a disposable creation within a using statement. I am hoping to extend that to handle more cases and also possibly convert it to a code fix in follow-up PR(s).
| <!-- Include a few dependencies of Roslyn. These right now are consumed out of the ExternalAPIs NuGet package to do assembly consistency checking in the main VS | ||
| repo. We should remove these and insert the packages directly, but for now we'll include these to limit the work needed to consume this package. --> | ||
| <_File Include="$(ArtifactsBinDir)Roslyn.VisualStudio.Setup\$(Configuration)\net472\Humanizer.dll" TargetDir="" /> | ||
| <_File Include="$(ArtifactsBinDir)Roslyn.VisualStudio.Setup\$(Configuration)\net472\Microsoft.CodeAnalysis.FlowAnalysis.Utilities.dll" TargetDir="" /> |
There was a problem hiding this comment.
@dotnet/roslyn-infrastructure for help on insertion changes for the new dependency. Will the change in this file and the next file suffice to ensure this assembly is copied next to Features/Workspaces assembly in VS install? I verified the setup project changes in subsequent files work fine and the assembly is loaded correctly in the RoslynDev hive.
There was a problem hiding this comment.
I think this file is for the roslyn external API package, so it probably not necessary to include this assembly here.
In reply to: 278337122 [](ancestors = 278337122)
There was a problem hiding this comment.
Sure, I will revert this change.
There was a problem hiding this comment.
@genlu - The comment about this say that the dependencies added here are needed to perform assembly dependency consistency checks in VSO repo. Are we sure not adding an entry here will not fail those dependency checks? Once you confirm, I can revert the change to this file.
There was a problem hiding this comment.
hmm, I'm not sure how the check works. But it sounds like we should add them back. @jasonmalinowski?
There was a problem hiding this comment.
Ideally if there's a new NuGet package you should be directly inserting that NuGet package. This is a bit of a hack which is a "well, we aren't, so we'll just stick the binary somewhere else".
The "consistency check" in this case is a tool that's looking at types to catch a minimum set of IVT breaks. So if you don't have a dependency of Roslyn inserted somewhere for it to look at...it won't be able to validate it. It's a suppressable warning by the tool, but better to include it if you can.
sharwell
left a comment
There was a problem hiding this comment.
Marking request changes so I get a chance to do a complete review
|
Ping for reviews. I would like to get this in sooner in 16.2 cycle so there is enough bake time to catch any issues/false positives. |
Thanks. @sharwell @heejaechang @genlu would you be able to review the analyzers and the added tests? Note that I plan to execute AnalyzerRunner with these analyzers on Roslyn.sln for dogfooding + measuring perf before merge. I will post the numbers when I have this data. |
| <ExpectedDependency Include="Humanizer.Core"/> | ||
| <ExpectedDependency Include="ICSharpCode.Decompiler"/> | ||
| <ExpectedDependency Include="Microsoft.DiaSymReader"/> | ||
| <ExpectedDependency Include="Microsoft.CodeAnalysis.FlowAnalysis.Utilities"/> |
There was a problem hiding this comment.
Also, we need to figure out if and how do we want to ngen this new assembly. @tmat Can we use the same model currently used for "System.Reflection.Metadata" if we decide to insert it as part of roslyn?
|
@mavasani so, I believe a lot of this code is porting from roslyn-analyzer repro? can you mark which is completely new code and which is ported code? |
src/EditorFeatures/CSharpTest/DisposeAnalysis/DisposableFieldsShouldBeDisposedTests.cs
Show resolved
Hide resolved
src/EditorFeatures/CSharpTest/DisposeAnalysis/DisposableFieldsShouldBeDisposedTests.cs
Show resolved
Hide resolved
|
...Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs
Show resolved
Hide resolved
...Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs
Outdated
Show resolved
Hide resolved
| symbolEndContext.ReportDiagnostic(diagnostic); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
do you remember whether this symbol analyzer now get deleted after this point? or all symbol analyzers alive until whole compilationwithAnalyzer get deleted?
There was a problem hiding this comment.
Nested actions registered within SymbolStart callback can never be called after SymbolEnd action has been called. So yes, the driver will not maintain any state pertaining to Symbol associated with SymbolStart/End once its SymbolEnd action has been called.
...Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs
Show resolved
Hide resolved
...Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs
Show resolved
Hide resolved
...Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs
Show resolved
Hide resolved
...Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs
Outdated
Show resolved
Hide resolved
...Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs
Show resolved
Hide resolved
| void AnalyzeDisposeMethod() | ||
| { | ||
| // Perform dataflow analysis to compute dispose value of disposable fields at the end of dispose method. | ||
| if (_disposeAnalysisHelper.TryGetOrComputeResult(operationBlockStartContext.OperationBlocks, containingMethod, |
There was a problem hiding this comment.
so we also sharing whole dispose analysis itself on top of flow analysis engine?
There was a problem hiding this comment.
Yes, that is the core piece being shared.
src/Features/Core/Portable/DisposeAnalysis/DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/Features/Core/Portable/DisposeAnalysis/DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer.cs
Outdated
Show resolved
Hide resolved
| /// </summary> | ||
| private static bool HasDisposeMethodSignature(this IMethodSymbol method) | ||
| { | ||
| return method.Name == "Dispose" && method.MethodKind == MethodKind.Ordinary && |
There was a problem hiding this comment.
const for "Dispose" or nameof(IDisposable.Dispose) ?
… assembly load lazy and revert reference add to the FlowAnalysis assembly in Workspaces (only referenced in Features now).
These analyzers are being ported from CA2000 and CA2213 FxCop analyzers, which are amongst the most popular FxCop analyzers and were considered valuable enough to add in the box in VS. Ported analyzers share the core dispose dataflow analysis computation with the analyzers in the roslyn-analyzers repo (Microsoft.CodeAnalysis.FlowAnalysis.Utilities NuGet package).
We will now flag disposable creations in methods that do not escape the method body (return value, out/ref params, assign to field/property, add to collection, etc.). Additionally, we also flag disposable fields of disposable types that are not disposed in the type's Dispose method.
This PR does not add any code fixes. We already have a code refactoring that offers wrapping a disposable creation within a using statement. I am hoping to extend that to handle more cases and also
possibly convert it to a code fix in follow-up PR(s).