private static void AnalyzeBlock(SyntaxNodeAnalysisContext context, BlockSyntax body) { if (body == null) { return; } SyntaxWalker walker = SyntaxWalker.GetInstance(); walker.VisitBlock(body); if (walker.Expressions?.Count > 0) { foreach (ExpressionSyntax expression in walker.Expressions) { ReportDiagnostic(context, expression); } } SyntaxWalker.Free(walker); }
private static void Analyze( SyntaxNodeAnalysisContext context, SyntaxNode declaration, ParameterListSyntax parameterList, CSharpSyntaxNode bodyOrExpressionBody) { if (parameterList == null) { return; } if (bodyOrExpressionBody == null) { return; } if (!parameterList.Parameters.Any()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(declaration, cancellationToken); SyntaxWalker walker = null; foreach (IParameterSymbol parameter in methodSymbol.Parameters) { cancellationToken.ThrowIfCancellationRequested(); ITypeSymbol type = parameter.Type; if (type.Kind == SymbolKind.ErrorType) { continue; } if (CSharpFacts.IsSimpleType(type.SpecialType)) { continue; } if (!type.IsReadOnlyStruct()) { if (parameter.RefKind == RefKind.In && type.TypeKind == TypeKind.Struct) { var parameterSyntax = (ParameterSyntax)parameter.GetSyntax(cancellationToken); Debug.Assert(parameterSyntax.Modifiers.Contains(SyntaxKind.InKeyword), ""); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.DoNotPassNonReadOnlyStructByReadOnlyReference, parameterSyntax.Identifier); } continue; } if (parameter.RefKind != RefKind.None) { continue; } if (walker == null) { if (methodSymbol.ImplementsInterfaceMember(allInterfaces: true)) { break; } walker = SyntaxWalker.GetInstance(); } else if (walker.Parameters.ContainsKey(parameter.Name)) { walker.Parameters.Clear(); break; } walker.Parameters.Add(parameter.Name, parameter); } if (walker == null) { return; } if (walker.Parameters.Count > 0) { walker.SemanticModel = semanticModel; walker.CancellationToken = cancellationToken; if (bodyOrExpressionBody is BlockSyntax body) { walker.VisitBlock(body); } else { walker.VisitArrowExpressionClause((ArrowExpressionClauseSyntax)bodyOrExpressionBody); } if (walker.Parameters.Count > 0 && !IsReferencedAsMethodGroup()) { foreach (KeyValuePair <string, IParameterSymbol> kvp in walker.Parameters) { if (kvp.Value.GetSyntaxOrDefault(cancellationToken) is ParameterSyntax parameter) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.MakeParameterRefReadOnly, parameter.Identifier); } } } } SyntaxWalker.Free(walker); bool IsReferencedAsMethodGroup() { switch (declaration.Kind()) { case SyntaxKind.MethodDeclaration: return(MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.Parent, methodSymbol, semanticModel, cancellationToken)); case SyntaxKind.LocalFunctionStatement: return(MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.FirstAncestor <MemberDeclarationSyntax>(), methodSymbol, semanticModel, cancellationToken)); default: return(false); } } }
private static void Analyze( SyntaxNodeAnalysisContext context, SyntaxNode declaration, ParameterListSyntax parameterList, CSharpSyntaxNode bodyOrExpressionBody) { if (parameterList == null) { return; } if (bodyOrExpressionBody == null) { return; } if (!parameterList.Parameters.Any()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(declaration, cancellationToken); SyntaxWalker walker = null; foreach (IParameterSymbol parameter in methodSymbol.Parameters) { cancellationToken.ThrowIfCancellationRequested(); if (parameter.RefKind == RefKind.None) { ITypeSymbol type = parameter.Type; //TODO: ITypeSymbol.IsReadOnly, https://github.com/dotnet/roslyn/issues/23792 if (type.IsReadOnlyStruct()) { if (walker == null) { if (methodSymbol.ImplementsInterfaceMember(allInterfaces: true)) { return; } walker = SyntaxWalker.GetInstance(); } walker.Parameters.Add(parameter.Name, parameter); } } } if (walker == null) { return; } walker.SemanticModel = semanticModel; walker.CancellationToken = cancellationToken; if (bodyOrExpressionBody is BlockSyntax body) { walker.VisitBlock(body); } else { walker.VisitArrowExpressionClause((ArrowExpressionClauseSyntax)bodyOrExpressionBody); } foreach (KeyValuePair <string, IParameterSymbol> kvp in walker.Parameters) { if (kvp.Value.GetSyntaxOrDefault(cancellationToken) is ParameterSyntax parameter) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.MakeParameterRefReadOnly, parameter.Identifier); } } SyntaxWalker.Free(walker); }