| File: CSharpSpecializedEnumerableCreationAnalyzer.cs | Web Access |
| Project: src\roslyn\src\RoslynAnalyzers\Roslyn.Diagnostics.Analyzers\CSharp\Roslyn.Diagnostics.CSharp.Analyzers.csproj (Roslyn.Diagnostics.CSharp.Analyzers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable warnings using System; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Roslyn.Diagnostics.Analyzers; namespace Roslyn.Diagnostics.CSharp.Analyzers { [DiagnosticAnalyzer(LanguageNames.CSharp)] public class CSharpSpecializedEnumerableCreationAnalyzer : SpecializedEnumerableCreationAnalyzer { protected override void GetCodeBlockStartedAnalyzer(CompilationStartAnalysisContext context, INamedTypeSymbol genericEnumerableSymbol, IMethodSymbol genericEmptyEnumerableSymbol) { context.RegisterCodeBlockStartAction<SyntaxKind>(new CodeBlockStartedAnalyzer(genericEnumerableSymbol, genericEmptyEnumerableSymbol).Initialize); } private sealed class CodeBlockStartedAnalyzer : AbstractCodeBlockStartedAnalyzer<SyntaxKind> { public CodeBlockStartedAnalyzer(INamedTypeSymbol genericEnumerableSymbol, IMethodSymbol genericEmptyEnumerableSymbol) : base(genericEnumerableSymbol, genericEmptyEnumerableSymbol) { } protected override void GetSyntaxAnalyzer(CodeBlockStartAnalysisContext<SyntaxKind> context, INamedTypeSymbol genericEnumerableSymbol, IMethodSymbol genericEmptyEnumerableSymbol) { context.RegisterSyntaxNodeAction(new SyntaxAnalyzer(genericEnumerableSymbol, genericEmptyEnumerableSymbol).AnalyzeNode, SyntaxKind.ReturnStatement); } } private sealed class SyntaxAnalyzer : AbstractSyntaxAnalyzer { public SyntaxAnalyzer(INamedTypeSymbol genericEnumerableSymbol, IMethodSymbol genericEmptyEnumerableSymbol) : base(genericEnumerableSymbol, genericEmptyEnumerableSymbol) { } public void AnalyzeNode(SyntaxNodeAnalysisContext context) { System.Collections.Generic.IEnumerable<SyntaxNode> expressionsToAnalyze = context.Node.DescendantNodes().Where(n => ShouldAnalyzeExpression(n, context.SemanticModel, context.CancellationToken)); foreach (SyntaxNode expression in expressionsToAnalyze) { switch (expression.Kind()) { case SyntaxKind.ArrayCreationExpression: AnalyzeArrayCreationExpression((ArrayCreationExpressionSyntax)expression, context.ReportDiagnostic); break; case SyntaxKind.ImplicitArrayCreationExpression: AnalyzeInitializerExpression(((ImplicitArrayCreationExpressionSyntax)expression).Initializer, context.ReportDiagnostic); break; case SyntaxKind.SimpleMemberAccessExpression: AnalyzeMemberAccessName(((MemberAccessExpressionSyntax)expression).Name, context.SemanticModel, context.ReportDiagnostic, context.CancellationToken); break; } } } private bool ShouldAnalyzeExpression(SyntaxNode expression, SemanticModel semanticModel, CancellationToken cancellationToken) { return expression.Kind() switch { SyntaxKind.ArrayCreationExpression or SyntaxKind.ImplicitArrayCreationExpression => ShouldAnalyzeArrayCreationExpression(expression, semanticModel, cancellationToken), SyntaxKind.SimpleMemberAccessExpression => true, _ => false, }; } private static void AnalyzeArrayCreationExpression(ArrayCreationExpressionSyntax arrayCreationExpression, Action<Diagnostic> addDiagnostic) { ArrayTypeSyntax arrayType = arrayCreationExpression.Type; if (arrayType.RankSpecifiers.Count == 1) { // Check for explicit specification of empty or singleton array if (arrayType.RankSpecifiers[0].ChildNodes() .FirstOrDefault(n => n.IsKind(SyntaxKind.NumericLiteralExpression)) is LiteralExpressionSyntax literalRankSpecifier) { AnalyzeArrayLength((int)literalRankSpecifier.Token.Value, arrayCreationExpression, addDiagnostic); return; } } AnalyzeInitializerExpression(arrayCreationExpression.Initializer, addDiagnostic); } private static void AnalyzeInitializerExpression(InitializerExpressionSyntax initializer, Action<Diagnostic> addDiagnostic) { // Check length of initializer list for empty or singleton array if (initializer != null) { AnalyzeArrayLength(initializer.Expressions.Count, initializer.Parent, addDiagnostic); } } } } }