55using Microsoft . CodeAnalysis . Diagnostics ;
66using Microsoft . CodeAnalysis . Operations ;
77using Microsoft . CodeAnalysis . FlowAnalysis ;
8+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
89using DisposableAnalyzer . Helpers ;
910using RoslynAnalyzer . Core . ControlFlow ;
1011
@@ -45,7 +46,7 @@ private void AnalyzeOperationBlockStart(OperationBlockStartAnalysisContext conte
4546 if ( context . OwningSymbol is not IMethodSymbol )
4647 return ;
4748
48- var disposableCreations = new List < ( ILocalSymbol local , Location location ) > ( ) ;
49+ var disposableCreations = new List < ( ILocalSymbol local , VariableDeclaratorSyntax ? declarator ) > ( ) ;
4950 var localsNeedingFinally = new HashSet < string > ( ) ;
5051
5152 // Track disposable creations
@@ -60,7 +61,9 @@ private void AnalyzeOperationBlockStart(OperationBlockStartAnalysisContext conte
6061 var localSymbol = GetLocalSymbol ( creation ) ;
6162 if ( localSymbol != null )
6263 {
63- disposableCreations . Add ( ( localSymbol , creation . Syntax . GetLocation ( ) ) ) ;
64+ var declaratorSyntax = creation . Syntax . Parent ? . Parent as VariableDeclaratorSyntax ;
65+
66+ disposableCreations . Add ( ( localSymbol , declaratorSyntax ) ) ;
6467 }
6568 } , OperationKind . ObjectCreation ) ;
6669
@@ -89,7 +92,7 @@ private void AnalyzeOperationBlockStart(OperationBlockStartAnalysisContext conte
8992 if ( methodOperation == null )
9093 return ;
9194
92- foreach ( var ( local , location ) in disposableCreations )
95+ foreach ( var ( local , declarator ) in disposableCreations )
9396 {
9497 // Use the comprehensive disposal flow analyzer from core
9598 var analysis = _disposalAnalyzer . AnalyzeDisposal (
@@ -100,9 +103,14 @@ private void AnalyzeOperationBlockStart(OperationBlockStartAnalysisContext conte
100103
101104 if ( ! analysis . IsDisposedOnAllPaths || localsNeedingFinally . Contains ( local . Name ) )
102105 {
106+ var reportLocation = declarator ? . Identifier . GetLocation ( )
107+ ?? FindLocalDeclarator ( methodOperation , local ) ? . Identifier . GetLocation ( )
108+ ?? local . Locations . FirstOrDefault ( )
109+ ?? methodOperation . Syntax . GetLocation ( ) ;
110+
103111 var diagnostic = Diagnostic . Create (
104112 Rule ,
105- location ,
113+ reportLocation ,
106114 local . Name ) ;
107115 blockEndContext . ReportDiagnostic ( diagnostic ) ;
108116 }
@@ -131,6 +139,13 @@ private void AnalyzeOperationBlockStart(OperationBlockStartAnalysisContext conte
131139 return null ;
132140 }
133141
142+ private VariableDeclaratorSyntax ? FindLocalDeclarator ( IOperation methodOperation , ILocalSymbol local )
143+ {
144+ return methodOperation . Syntax . DescendantNodes ( )
145+ . OfType < VariableDeclaratorSyntax > ( )
146+ . FirstOrDefault ( v => v . Identifier . Text == local . Name ) ;
147+ }
148+
134149 private static bool FinallyDisposesLocal ( IBlockOperation finallyBlock , ILocalSymbol local )
135150 {
136151 foreach ( var operation in finallyBlock . Descendants ( ) )
0 commit comments