From 09f2566e2a9642991f89881aec8d8cdc73cbf099 Mon Sep 17 00:00:00 2001 From: Todd Lang Date: Tue, 21 Jul 2026 08:23:23 -0400 Subject: [PATCH 1/2] Resolve CA1861/IDE0028 --- .../Immutability/ImmutabilityAnalyzer.cs | 4 +- .../Immutability/ReadOnlyParameterAnalyzer.cs | 4 +- .../Immutability/StatelessFuncAnalyzer.cs | 362 +++++++++--------- 3 files changed, 185 insertions(+), 185 deletions(-) diff --git a/src/D2L.CodeStyle.Analyzers/Immutability/ImmutabilityAnalyzer.cs b/src/D2L.CodeStyle.Analyzers/Immutability/ImmutabilityAnalyzer.cs index f0cbf3fc..12615932 100644 --- a/src/D2L.CodeStyle.Analyzers/Immutability/ImmutabilityAnalyzer.cs +++ b/src/D2L.CodeStyle.Analyzers/Immutability/ImmutabilityAnalyzer.cs @@ -280,11 +280,11 @@ AnnotationsContext annotationsContext ctx.ReportDiagnostic( Diagnostics.ConflictingImmutability, parameter.Locations[0], - messageArgs: new[] { + messageArgs: [ "Immutable", "ConditionallyImmutable.OnlyIf", "typeparameter" - } + ] ); } } diff --git a/src/D2L.CodeStyle.Analyzers/Immutability/ReadOnlyParameterAnalyzer.cs b/src/D2L.CodeStyle.Analyzers/Immutability/ReadOnlyParameterAnalyzer.cs index 3d5825e8..120467a6 100644 --- a/src/D2L.CodeStyle.Analyzers/Immutability/ReadOnlyParameterAnalyzer.cs +++ b/src/D2L.CodeStyle.Analyzers/Immutability/ReadOnlyParameterAnalyzer.cs @@ -112,7 +112,7 @@ Location getLocation() { ctx.ReportDiagnostic( Diagnostics.ReadOnlyParameterIsnt, getLocation(), - messageArgs: new[] { "is an in/ref/out parameter" } + messageArgs: [ "is an in/ref/out parameter" ] ); } @@ -128,7 +128,7 @@ Location getLocation() { ctx.ReportDiagnostic( Diagnostics.ReadOnlyParameterIsnt, getLocation(), - messageArgs: new[] { "is assigned to and/or passed by reference" } + messageArgs: [ "is assigned to and/or passed by reference" ] ); } } diff --git a/src/D2L.CodeStyle.Analyzers/Immutability/StatelessFuncAnalyzer.cs b/src/D2L.CodeStyle.Analyzers/Immutability/StatelessFuncAnalyzer.cs index ea350632..c35e8e70 100644 --- a/src/D2L.CodeStyle.Analyzers/Immutability/StatelessFuncAnalyzer.cs +++ b/src/D2L.CodeStyle.Analyzers/Immutability/StatelessFuncAnalyzer.cs @@ -1,61 +1,61 @@ -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; - -namespace D2L.CodeStyle.Analyzers.Immutability { - [DiagnosticAnalyzer( LanguageNames.CSharp )] - public sealed class StatelessFuncAnalyzer : DiagnosticAnalyzer { - - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create( - Diagnostics.StatelessFuncIsnt - ); - - public override void Initialize( AnalysisContext context ) { - context.EnableConcurrentExecution(); - context.ConfigureGeneratedCodeAnalysis( GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics ); - context.RegisterCompilationStartAction( RegisterAnalysis ); - } - - private static void RegisterAnalysis( CompilationStartAnalysisContext context ) { - - Compilation compilation = context.Compilation; - ISymbol? statelessFuncAttr = compilation.GetTypeByMetadataName( "D2L.CodeStyle.Annotations.Contract.StatelessFuncAttribute" ); - - if( statelessFuncAttr == null ) { - return; - } - - ImmutableHashSet statelessFuncs = GetStatelessFuncTypes( compilation ); - - context.RegisterOperationAction( - ctx => { - AnalyzeArgument( - ctx, - (IArgumentOperation)ctx.Operation, - statelessFuncAttr, - statelessFuncs - ); - }, - OperationKind.Argument - ); - } - - private static void AnalyzeArgument( - OperationAnalysisContext context, - IArgumentOperation argumentOperation, - ISymbol statelessFuncAttribute, - ImmutableHashSet statelessFuncs - ) { +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +namespace D2L.CodeStyle.Analyzers.Immutability { + [DiagnosticAnalyzer( LanguageNames.CSharp )] + public sealed class StatelessFuncAnalyzer : DiagnosticAnalyzer { + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create( + Diagnostics.StatelessFuncIsnt + ); + + public override void Initialize( AnalysisContext context ) { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis( GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics ); + context.RegisterCompilationStartAction( RegisterAnalysis ); + } + + private static void RegisterAnalysis( CompilationStartAnalysisContext context ) { + + Compilation compilation = context.Compilation; + ISymbol? statelessFuncAttr = compilation.GetTypeByMetadataName( "D2L.CodeStyle.Annotations.Contract.StatelessFuncAttribute" ); + + if( statelessFuncAttr == null ) { + return; + } + + ImmutableHashSet statelessFuncs = GetStatelessFuncTypes( compilation ); + + context.RegisterOperationAction( + ctx => { + AnalyzeArgument( + ctx, + (IArgumentOperation)ctx.Operation, + statelessFuncAttr, + statelessFuncs + ); + }, + OperationKind.Argument + ); + } + + private static void AnalyzeArgument( + OperationAnalysisContext context, + IArgumentOperation argumentOperation, + ISymbol statelessFuncAttribute, + ImmutableHashSet statelessFuncs + ) { if( argumentOperation.ArgumentKind == ArgumentKind.DefaultValue ) { return; - } - - IParameterSymbol? param = argumentOperation.Parameter; + } + + IParameterSymbol? param = argumentOperation.Parameter; if( param == null ) { return; - } - + } + if( !IsParameterMarkedStateless( statelessFuncAttribute, param ) ) { return; } @@ -88,31 +88,31 @@ ImmutableHashSet statelessFuncs break; } - /** - * Even though we haven't specifically accounted for its - * source if it's a StatelessFunc we're reasonably - * certain its been analyzed. + /** + * Even though we haven't specifically accounted for its + * source if it's a StatelessFunc we're reasonably + * certain its been analyzed. */ - ISymbol? type = operationToInspect.Type; - if( type != null && IsStatelessFunc( type, statelessFuncs ) ) { - return; + ISymbol? type = operationToInspect.Type; + if( type != null && IsStatelessFunc( type, statelessFuncs ) ) { + return; } - switch( operationToInspect ) { - // this is the case when a method reference is used - // eg Func func = int.Parse - case IMemberReferenceOperation memberReference: + switch( operationToInspect ) { + // this is the case when a method reference is used + // eg Func func = int.Parse + case IMemberReferenceOperation memberReference: if( memberReference.Member.IsStatic ) { return; } // non-static member access means that state could // be used / held. - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"{ argumentOperation.Syntax } is not static" } - ); + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"{ argumentOperation.Syntax } is not static" } + ); break; /** @@ -123,11 +123,11 @@ ImmutableHashSet statelessFuncs return; } - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { "Lambda is not static" } - ); + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: [ "Lambda is not static" ] + ); break; // this is the case where an expression is invoked, @@ -139,132 +139,132 @@ ImmutableHashSet statelessFuncs // we are rejecting this because it is tricky to // analyze properly, but also a bit ugly and should // never really be necessary - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"Invocations are not allowed: { argumentOperation.Syntax }" } - ); - + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"Invocations are not allowed: { argumentOperation.Syntax }" } + ); + break; - /** + /** * This is the case where a paraeter is passed in - * void MyMethod( Func f ) { + * void MyMethod( Func f ) { * Foo( f ) * } - * void MyMethod( [StatelessFunc] Func f ) { + * void MyMethod( [StatelessFunc] Func f ) { * Foo( f ) * } * If the parameter was StatelesFunc, it was allowed via the - * type check. + * type check. */ - case IParameterReferenceOperation paramReference: - /** - * If it's a local parameter marked with [StatelessFunc] we're reasonably - * certain it was analyzed on the caller side. - */ - if( IsParameterMarkedStateless( - statelessFuncAttribute, - paramReference.Parameter - ) ) { - return; - } - - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"Parameter { argumentOperation.Syntax } is not marked [StatelessFunc]." } - ); + case IParameterReferenceOperation paramReference: + /** + * If it's a local parameter marked with [StatelessFunc] we're reasonably + * certain it was analyzed on the caller side. + */ + if( IsParameterMarkedStateless( + statelessFuncAttribute, + paramReference.Parameter + ) ) { + return; + } + + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"Parameter { argumentOperation.Syntax } is not marked [StatelessFunc]." } + ); break; - /** + /** * This is the case where a local variable is passed in - * var f = () => 0; + * var f = () => 0; * Foo( f ) * If the variable was StatelessFunc, it was allowed via the - * type check. + * type check. */ - case ILocalReferenceOperation: - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"Unable to determine if { argumentOperation.Syntax } is stateless." } - ); - - break; - + case ILocalReferenceOperation: + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"Unable to determine if { argumentOperation.Syntax } is stateless." } + ); + + break; + default: // we need StatelessFunc to be ultra safe, so we'll // reject usages we do not understand yet - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"Unable to determine safety of { argumentOperation.Syntax }. This is an unexpectes usage of StatelessFunc" } - ); - - break; - } - } - - private static bool IsStatelessFunc( - ISymbol symbol, - ImmutableHashSet statelessFuncs - ) { - // Generics work a bit different, in that the symbol we have to work - // with is not (eg StatelessFunc ), but the list of symbols we're - // checking against are the definitions, which are (eg - // StatelessFunc ) generic. So check the "parent" definition. - return statelessFuncs.Contains( symbol.OriginalDefinition ); - } - - private static bool IsParameterMarkedStateless( - ISymbol statelessFuncAttribute, - IParameterSymbol param + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"Unable to determine safety of { argumentOperation.Syntax }. This is an unexpectes usage of StatelessFunc" } + ); + + break; + } + } + + private static bool IsStatelessFunc( + ISymbol symbol, + ImmutableHashSet statelessFuncs + ) { + // Generics work a bit different, in that the symbol we have to work + // with is not (eg StatelessFunc ), but the list of symbols we're + // checking against are the definitions, which are (eg + // StatelessFunc ) generic. So check the "parent" definition. + return statelessFuncs.Contains( symbol.OriginalDefinition ); + } + + private static bool IsParameterMarkedStateless( + ISymbol statelessFuncAttribute, + IParameterSymbol param ) { - ImmutableArray paramAttributes = param.GetAttributes(); + ImmutableArray paramAttributes = param.GetAttributes(); foreach( AttributeData a in paramAttributes ) { if( SymbolEqualityComparer.Default.Equals( a.AttributeClass, statelessFuncAttribute ) ) { return true; } - } - - return false; - } - - private static ImmutableHashSet GetStatelessFuncTypes( Compilation compilation) { - - var builder = ImmutableHashSet.CreateBuilder( SymbolEqualityComparer.Default ); - - var types = new string[] { - "D2L.StatelessFunc`1", - "D2L.StatelessFunc`2", - "D2L.StatelessFunc`3", - "D2L.StatelessFunc`4", - "D2L.StatelessFunc`5", - "D2L.StatelessFunc`6", - "D2L.StatelessFunc`7", - "D2L.StatelessFunc`8", - "D2L.StatelessFunc`9", - "D2L.StatelessFunc`10", - "D2L.StatelessFunc`11", - }; - - foreach( string typeName in types ) { - INamedTypeSymbol? typeSymbol = compilation.GetTypeByMetadataName( typeName ); - - if( typeSymbol == null ) { - // These types are usually defined in another assembly, - // ( usually ) and thus we have a bit of a circular - // dependency. Allowing this lookup to return null - // allow us to update the analyzer before the other - // assembly, which should be safer - continue; - } - - builder.Add( typeSymbol.OriginalDefinition ); - } - - return builder.ToImmutable(); - } - } -} + } + + return false; + } + + private static ImmutableHashSet GetStatelessFuncTypes( Compilation compilation) { + + var builder = ImmutableHashSet.CreateBuilder( SymbolEqualityComparer.Default ); + + var types = new string[] { + "D2L.StatelessFunc`1", + "D2L.StatelessFunc`2", + "D2L.StatelessFunc`3", + "D2L.StatelessFunc`4", + "D2L.StatelessFunc`5", + "D2L.StatelessFunc`6", + "D2L.StatelessFunc`7", + "D2L.StatelessFunc`8", + "D2L.StatelessFunc`9", + "D2L.StatelessFunc`10", + "D2L.StatelessFunc`11", + }; + + foreach( string typeName in types ) { + INamedTypeSymbol? typeSymbol = compilation.GetTypeByMetadataName( typeName ); + + if( typeSymbol == null ) { + // These types are usually defined in another assembly, + // ( usually ) and thus we have a bit of a circular + // dependency. Allowing this lookup to return null + // allow us to update the analyzer before the other + // assembly, which should be safer + continue; + } + + builder.Add( typeSymbol.OriginalDefinition ); + } + + return builder.ToImmutable(); + } + } +} From e7ebdf48daa257d7a5fe8ec05372286a63a2765f Mon Sep 17 00:00:00 2001 From: Todd Lang Date: Tue, 21 Jul 2026 08:24:47 -0400 Subject: [PATCH 2/2] Reverting whitespace changes in StatelessFuncAnalyzer --- .../Immutability/StatelessFuncAnalyzer.cs | 362 +++++++++--------- 1 file changed, 181 insertions(+), 181 deletions(-) diff --git a/src/D2L.CodeStyle.Analyzers/Immutability/StatelessFuncAnalyzer.cs b/src/D2L.CodeStyle.Analyzers/Immutability/StatelessFuncAnalyzer.cs index c35e8e70..ea350632 100644 --- a/src/D2L.CodeStyle.Analyzers/Immutability/StatelessFuncAnalyzer.cs +++ b/src/D2L.CodeStyle.Analyzers/Immutability/StatelessFuncAnalyzer.cs @@ -1,61 +1,61 @@ -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; - -namespace D2L.CodeStyle.Analyzers.Immutability { - [DiagnosticAnalyzer( LanguageNames.CSharp )] - public sealed class StatelessFuncAnalyzer : DiagnosticAnalyzer { - - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create( - Diagnostics.StatelessFuncIsnt - ); - - public override void Initialize( AnalysisContext context ) { - context.EnableConcurrentExecution(); - context.ConfigureGeneratedCodeAnalysis( GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics ); - context.RegisterCompilationStartAction( RegisterAnalysis ); - } - - private static void RegisterAnalysis( CompilationStartAnalysisContext context ) { - - Compilation compilation = context.Compilation; - ISymbol? statelessFuncAttr = compilation.GetTypeByMetadataName( "D2L.CodeStyle.Annotations.Contract.StatelessFuncAttribute" ); - - if( statelessFuncAttr == null ) { - return; - } - - ImmutableHashSet statelessFuncs = GetStatelessFuncTypes( compilation ); - - context.RegisterOperationAction( - ctx => { - AnalyzeArgument( - ctx, - (IArgumentOperation)ctx.Operation, - statelessFuncAttr, - statelessFuncs - ); - }, - OperationKind.Argument - ); - } - - private static void AnalyzeArgument( - OperationAnalysisContext context, - IArgumentOperation argumentOperation, - ISymbol statelessFuncAttribute, - ImmutableHashSet statelessFuncs - ) { +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +namespace D2L.CodeStyle.Analyzers.Immutability { + [DiagnosticAnalyzer( LanguageNames.CSharp )] + public sealed class StatelessFuncAnalyzer : DiagnosticAnalyzer { + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create( + Diagnostics.StatelessFuncIsnt + ); + + public override void Initialize( AnalysisContext context ) { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis( GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics ); + context.RegisterCompilationStartAction( RegisterAnalysis ); + } + + private static void RegisterAnalysis( CompilationStartAnalysisContext context ) { + + Compilation compilation = context.Compilation; + ISymbol? statelessFuncAttr = compilation.GetTypeByMetadataName( "D2L.CodeStyle.Annotations.Contract.StatelessFuncAttribute" ); + + if( statelessFuncAttr == null ) { + return; + } + + ImmutableHashSet statelessFuncs = GetStatelessFuncTypes( compilation ); + + context.RegisterOperationAction( + ctx => { + AnalyzeArgument( + ctx, + (IArgumentOperation)ctx.Operation, + statelessFuncAttr, + statelessFuncs + ); + }, + OperationKind.Argument + ); + } + + private static void AnalyzeArgument( + OperationAnalysisContext context, + IArgumentOperation argumentOperation, + ISymbol statelessFuncAttribute, + ImmutableHashSet statelessFuncs + ) { if( argumentOperation.ArgumentKind == ArgumentKind.DefaultValue ) { return; - } - - IParameterSymbol? param = argumentOperation.Parameter; + } + + IParameterSymbol? param = argumentOperation.Parameter; if( param == null ) { return; - } - + } + if( !IsParameterMarkedStateless( statelessFuncAttribute, param ) ) { return; } @@ -88,31 +88,31 @@ ImmutableHashSet statelessFuncs break; } - /** - * Even though we haven't specifically accounted for its - * source if it's a StatelessFunc we're reasonably - * certain its been analyzed. + /** + * Even though we haven't specifically accounted for its + * source if it's a StatelessFunc we're reasonably + * certain its been analyzed. */ - ISymbol? type = operationToInspect.Type; - if( type != null && IsStatelessFunc( type, statelessFuncs ) ) { - return; + ISymbol? type = operationToInspect.Type; + if( type != null && IsStatelessFunc( type, statelessFuncs ) ) { + return; } - switch( operationToInspect ) { - // this is the case when a method reference is used - // eg Func func = int.Parse - case IMemberReferenceOperation memberReference: + switch( operationToInspect ) { + // this is the case when a method reference is used + // eg Func func = int.Parse + case IMemberReferenceOperation memberReference: if( memberReference.Member.IsStatic ) { return; } // non-static member access means that state could // be used / held. - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"{ argumentOperation.Syntax } is not static" } - ); + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"{ argumentOperation.Syntax } is not static" } + ); break; /** @@ -123,11 +123,11 @@ ImmutableHashSet statelessFuncs return; } - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: [ "Lambda is not static" ] - ); + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { "Lambda is not static" } + ); break; // this is the case where an expression is invoked, @@ -139,132 +139,132 @@ ImmutableHashSet statelessFuncs // we are rejecting this because it is tricky to // analyze properly, but also a bit ugly and should // never really be necessary - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"Invocations are not allowed: { argumentOperation.Syntax }" } - ); - + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"Invocations are not allowed: { argumentOperation.Syntax }" } + ); + break; - /** + /** * This is the case where a paraeter is passed in - * void MyMethod( Func f ) { + * void MyMethod( Func f ) { * Foo( f ) * } - * void MyMethod( [StatelessFunc] Func f ) { + * void MyMethod( [StatelessFunc] Func f ) { * Foo( f ) * } * If the parameter was StatelesFunc, it was allowed via the - * type check. + * type check. */ - case IParameterReferenceOperation paramReference: - /** - * If it's a local parameter marked with [StatelessFunc] we're reasonably - * certain it was analyzed on the caller side. - */ - if( IsParameterMarkedStateless( - statelessFuncAttribute, - paramReference.Parameter - ) ) { - return; - } - - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"Parameter { argumentOperation.Syntax } is not marked [StatelessFunc]." } - ); + case IParameterReferenceOperation paramReference: + /** + * If it's a local parameter marked with [StatelessFunc] we're reasonably + * certain it was analyzed on the caller side. + */ + if( IsParameterMarkedStateless( + statelessFuncAttribute, + paramReference.Parameter + ) ) { + return; + } + + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"Parameter { argumentOperation.Syntax } is not marked [StatelessFunc]." } + ); break; - /** + /** * This is the case where a local variable is passed in - * var f = () => 0; + * var f = () => 0; * Foo( f ) * If the variable was StatelessFunc, it was allowed via the - * type check. + * type check. */ - case ILocalReferenceOperation: - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"Unable to determine if { argumentOperation.Syntax } is stateless." } - ); - - break; - + case ILocalReferenceOperation: + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"Unable to determine if { argumentOperation.Syntax } is stateless." } + ); + + break; + default: // we need StatelessFunc to be ultra safe, so we'll // reject usages we do not understand yet - context.ReportDiagnostic( - Diagnostics.StatelessFuncIsnt, - argumentOperation.Syntax.GetLocation(), - messageArgs: new[] { $"Unable to determine safety of { argumentOperation.Syntax }. This is an unexpectes usage of StatelessFunc" } - ); - - break; - } - } - - private static bool IsStatelessFunc( - ISymbol symbol, - ImmutableHashSet statelessFuncs - ) { - // Generics work a bit different, in that the symbol we have to work - // with is not (eg StatelessFunc ), but the list of symbols we're - // checking against are the definitions, which are (eg - // StatelessFunc ) generic. So check the "parent" definition. - return statelessFuncs.Contains( symbol.OriginalDefinition ); - } - - private static bool IsParameterMarkedStateless( - ISymbol statelessFuncAttribute, - IParameterSymbol param + context.ReportDiagnostic( + Diagnostics.StatelessFuncIsnt, + argumentOperation.Syntax.GetLocation(), + messageArgs: new[] { $"Unable to determine safety of { argumentOperation.Syntax }. This is an unexpectes usage of StatelessFunc" } + ); + + break; + } + } + + private static bool IsStatelessFunc( + ISymbol symbol, + ImmutableHashSet statelessFuncs + ) { + // Generics work a bit different, in that the symbol we have to work + // with is not (eg StatelessFunc ), but the list of symbols we're + // checking against are the definitions, which are (eg + // StatelessFunc ) generic. So check the "parent" definition. + return statelessFuncs.Contains( symbol.OriginalDefinition ); + } + + private static bool IsParameterMarkedStateless( + ISymbol statelessFuncAttribute, + IParameterSymbol param ) { - ImmutableArray paramAttributes = param.GetAttributes(); + ImmutableArray paramAttributes = param.GetAttributes(); foreach( AttributeData a in paramAttributes ) { if( SymbolEqualityComparer.Default.Equals( a.AttributeClass, statelessFuncAttribute ) ) { return true; } - } - - return false; - } - - private static ImmutableHashSet GetStatelessFuncTypes( Compilation compilation) { - - var builder = ImmutableHashSet.CreateBuilder( SymbolEqualityComparer.Default ); - - var types = new string[] { - "D2L.StatelessFunc`1", - "D2L.StatelessFunc`2", - "D2L.StatelessFunc`3", - "D2L.StatelessFunc`4", - "D2L.StatelessFunc`5", - "D2L.StatelessFunc`6", - "D2L.StatelessFunc`7", - "D2L.StatelessFunc`8", - "D2L.StatelessFunc`9", - "D2L.StatelessFunc`10", - "D2L.StatelessFunc`11", - }; - - foreach( string typeName in types ) { - INamedTypeSymbol? typeSymbol = compilation.GetTypeByMetadataName( typeName ); - - if( typeSymbol == null ) { - // These types are usually defined in another assembly, - // ( usually ) and thus we have a bit of a circular - // dependency. Allowing this lookup to return null - // allow us to update the analyzer before the other - // assembly, which should be safer - continue; - } - - builder.Add( typeSymbol.OriginalDefinition ); - } - - return builder.ToImmutable(); - } - } -} + } + + return false; + } + + private static ImmutableHashSet GetStatelessFuncTypes( Compilation compilation) { + + var builder = ImmutableHashSet.CreateBuilder( SymbolEqualityComparer.Default ); + + var types = new string[] { + "D2L.StatelessFunc`1", + "D2L.StatelessFunc`2", + "D2L.StatelessFunc`3", + "D2L.StatelessFunc`4", + "D2L.StatelessFunc`5", + "D2L.StatelessFunc`6", + "D2L.StatelessFunc`7", + "D2L.StatelessFunc`8", + "D2L.StatelessFunc`9", + "D2L.StatelessFunc`10", + "D2L.StatelessFunc`11", + }; + + foreach( string typeName in types ) { + INamedTypeSymbol? typeSymbol = compilation.GetTypeByMetadataName( typeName ); + + if( typeSymbol == null ) { + // These types are usually defined in another assembly, + // ( usually ) and thus we have a bit of a circular + // dependency. Allowing this lookup to return null + // allow us to update the analyzer before the other + // assembly, which should be safer + continue; + } + + builder.Add( typeSymbol.OriginalDefinition ); + } + + return builder.ToImmutable(); + } + } +}