11namespace IDisposableAnalyzers
22{
33 using System . Collections . Immutable ;
4- using System . Linq ;
54 using System . Threading ;
65
76 using Gu . Roslyn . AnalyzerExtensions ;
7+
88 using Microsoft . CodeAnalysis ;
99 using Microsoft . CodeAnalysis . CSharp ;
1010 using Microsoft . CodeAnalysis . CSharp . Syntax ;
@@ -77,7 +77,7 @@ private static void HandleReturnValue(SyntaxNodeAnalysisContext context, Express
7777 if ( Disposable . IsCreation ( returnValue , context . SemanticModel , context . CancellationToken ) &&
7878 context . SemanticModel . TryGetSymbol ( returnValue , context . CancellationToken , out var returnedSymbol ) )
7979 {
80- if ( IsInUsing ( returnedSymbol , context . CancellationToken ) ||
80+ if ( IsUsing ( returnedSymbol , context . CancellationToken ) ||
8181 Disposable . IsDisposedBefore ( returnedSymbol , returnValue , context . SemanticModel , context . CancellationToken ) )
8282 {
8383 context . ReportDiagnostic ( Diagnostic . Create ( Descriptors . IDISP011DontReturnDisposed , returnValue . GetLocation ( ) ) ) ;
@@ -110,7 +110,7 @@ private static void HandleReturnValue(SyntaxNodeAnalysisContext context, Express
110110 Disposable . IsCreation ( expression , context . SemanticModel , context . CancellationToken ) &&
111111 context . SemanticModel . TryGetSymbol ( expression , context . CancellationToken , out var argumentSymbol ) )
112112 {
113- if ( IsInUsing ( argumentSymbol , context . CancellationToken ) ||
113+ if ( IsUsing ( argumentSymbol , context . CancellationToken ) ||
114114 Disposable . IsDisposedBefore ( argumentSymbol , expression , context . SemanticModel , context . CancellationToken ) )
115115 {
116116 if ( IsLazyEnumerable ( invocation , containingType , context . SemanticModel , context . CancellationToken ) )
@@ -123,7 +123,7 @@ private static void HandleReturnValue(SyntaxNodeAnalysisContext context, Express
123123 }
124124
125125 if ( ReturnType ( context ) ? . IsAwaitable ( ) == true &&
126- IsInUsingScope ( returnValue ) &&
126+ IsInUsing ( returnValue ) &&
127127 ! returnValue . TryFirstAncestorOrSelf < AwaitExpressionSyntax > ( out _ ) &&
128128 context . SemanticModel . TryGetType ( returnValue , context . CancellationToken , out var returnValueType2 ) &&
129129 returnValueType2 . IsAwaitable ( ) &&
@@ -133,42 +133,45 @@ private static void HandleReturnValue(SyntaxNodeAnalysisContext context, Express
133133 }
134134 }
135135
136- private static bool IsInUsingScope ( SyntaxNode node )
137- {
138- return IsInUsingStatement ( node ) || HasPrecedingUsingDeclaration ( node ) ;
139- }
140-
141- private static bool IsInUsingStatement ( SyntaxNode node )
142- {
143- return node . TryFirstAncestor < UsingStatementSyntax > ( out var usingStatement ) &&
144- usingStatement . Statement . Contains ( node ) ;
145- }
146-
147- private static bool HasPrecedingUsingDeclaration ( SyntaxNode node )
136+ private static bool IsInUsing ( SyntaxNode node )
148137 {
149- if ( node . TryFirstAncestor < UsingStatementSyntax > ( out var usingStatement ) &&
150- usingStatement . Statement . Contains ( node ) )
138+ if ( node . TryFirstAncestor < UsingStatementSyntax > ( out var usingStatement ) )
151139 {
152- return true ;
140+ return usingStatement . Statement . Contains ( node ) ;
153141 }
154142
155- if ( node . Parent ? . ChildNodes ( ) . TakeWhile ( x => x != node ) . OfType < LocalDeclarationStatementSyntax > ( ) . Any ( x => x . UsingKeyword . Text == "using" ) ?? false )
143+ if ( node . TryFirstAncestor < BlockSyntax > ( out var block ) )
156144 {
157- return true ;
158- }
145+ foreach ( var statement in block . Statements )
146+ {
147+ if ( statement . SpanStart >= node . SpanStart )
148+ {
149+ return false ;
150+ }
159151
160- if ( node . Parent is { } parent )
161- {
162- return HasPrecedingUsingDeclaration ( parent ) ;
152+ if ( statement is LocalDeclarationStatementSyntax { UsingKeyword . ValueText : "using" } )
153+ {
154+ return true ;
155+ }
156+ }
163157 }
164158
165159 return false ;
166160 }
167161
168- private static bool IsInUsing ( ISymbol symbol , CancellationToken cancellationToken )
162+ private static bool IsUsing ( ISymbol symbol , CancellationToken cancellationToken )
169163 {
170- return symbol . TrySingleDeclaration < SyntaxNode > ( cancellationToken , out var declaration ) &&
171- declaration . Parent ? . Parent is UsingStatementSyntax ;
164+ if ( symbol . TrySingleDeclaration < SyntaxNode > ( cancellationToken , out var declaration ) )
165+ {
166+ return declaration switch
167+ {
168+ { Parent . Parent : UsingStatementSyntax } => true ,
169+ { Parent . Parent : LocalDeclarationStatementSyntax { UsingKeyword . ValueText : "using" } } => true ,
170+ _ => false ,
171+ } ;
172+ }
173+
174+ return false ;
172175 }
173176
174177 private static bool ShouldAwait ( SyntaxNodeAnalysisContext context , ExpressionSyntax returnValue )
0 commit comments