protected override void AnalyzeNode(SyntaxNodeAnalysisContext context, EnabledRules rules) { var node = context.Node; var semanticModel = context.SemanticModel; Action <Diagnostic> reportDiagnostic = context.ReportDiagnostic; var cancellationToken = context.CancellationToken; string filePath = node.SyntaxTree.FilePath; var invocationExpression = node as InvocationExpressionSyntax; if (semanticModel.GetSymbolInfo(invocationExpression, cancellationToken).Symbol is IMethodSymbol methodInfo) { if (rules.IsEnabled(AllocationRules.ValueTypeNonOverridenCallRule.Id)) { if (methodInfo.IsOverride) { var rule = rules.Get(AllocationRules.ValueTypeNonOverridenCallRule.Id); CheckNonOverridenMethodOnStruct(rule, methodInfo, reportDiagnostic, invocationExpression, filePath); } } if (rules.IsEnabled(AllocationRules.ParamsParameterRule.Id)) { if (methodInfo.Parameters.Length > 0 && invocationExpression.ArgumentList != null) { var lastParam = methodInfo.Parameters[methodInfo.Parameters.Length - 1]; if (lastParam.IsParams) { var rule = rules.Get(AllocationRules.ParamsParameterRule.Id); CheckParam(rule, invocationExpression, methodInfo, semanticModel, reportDiagnostic, filePath, cancellationToken); } } } } }
private static void ArrowExpressionCheck(EnabledRules rules, SyntaxNode node, SemanticModel semanticModel, bool isAssignmentToReadonly, Action <Diagnostic> reportDiagnostic, string filePath, CancellationToken cancellationToken) { var syntax = node as ArrowExpressionClauseSyntax; var typeInfo = semanticModel.GetTypeInfo(syntax.Expression, cancellationToken); var conversionInfo = semanticModel.GetConversion(syntax.Expression, cancellationToken); CheckTypeConversion(rules.Get(AllocationRules.ValueTypeToReferenceTypeConversionRule.Id), conversionInfo, reportDiagnostic, syntax.Expression.GetLocation(), filePath); CheckDelegateCreation(rules, syntax, typeInfo, semanticModel, false, reportDiagnostic, syntax.Expression.GetLocation(), filePath, cancellationToken); }
private static void EqualsValueClauseCheck(EnabledRules rules, SyntaxNode node, SemanticModel semanticModel, bool isAssignmentToReadonly, Action <Diagnostic> reportDiagnostic, string filePath, CancellationToken cancellationToken) { var initializer = node as EqualsValueClauseSyntax; if (initializer.Value != null) { var typeInfo = semanticModel.GetTypeInfo(initializer.Value, cancellationToken); var conversionInfo = semanticModel.GetConversion(initializer.Value, cancellationToken); CheckTypeConversion(rules.Get(AllocationRules.ValueTypeToReferenceTypeConversionRule.Id), conversionInfo, reportDiagnostic, initializer.Value.GetLocation(), filePath); CheckDelegateCreation(rules, initializer.Value, typeInfo, semanticModel, isAssignmentToReadonly, reportDiagnostic, initializer.Value.GetLocation(), filePath, cancellationToken); } }
protected override void AnalyzeNode(SyntaxNodeAnalysisContext context, EnabledRules rules) { var node = context.Node; var semanticModel = context.SemanticModel; Action <Diagnostic> reportDiagnostic = context.ReportDiagnostic; var cancellationToken = context.CancellationToken; string filePath = node.SyntaxTree.FilePath; var binaryExpressions = node.DescendantNodesAndSelf().OfType <BinaryExpressionSyntax>().Reverse(); // need inner most expressions int stringConcatenationCount = 0; foreach (var binaryExpression in binaryExpressions) { if (binaryExpression.Left == null || binaryExpression.Right == null) { continue; } bool isConstant = semanticModel.GetConstantValue(binaryExpression, cancellationToken).HasValue; if (isConstant) { continue; } // TODO: TryGetEnabled() var left = semanticModel.GetTypeInfo(binaryExpression.Left, cancellationToken); var right = semanticModel.GetTypeInfo(binaryExpression.Right, cancellationToken); if (rules.TryGet(AllocationRules.ValueTypeToReferenceTypeInAStringConcatenationRule.Id, out var rule)) { var leftConversion = semanticModel.GetConversion(binaryExpression.Left, cancellationToken); var rightConversion = semanticModel.GetConversion(binaryExpression.Right, cancellationToken); CheckTypeConversion(rule, left, leftConversion, reportDiagnostic, binaryExpression.Left.GetLocation(), filePath); CheckTypeConversion(rule, right, rightConversion, reportDiagnostic, binaryExpression.Right.GetLocation(), filePath); } // regular string allocation if (rules.IsEnabled(AllocationRules.StringConcatenationAllocationRule.Id)) { if (left.Type?.SpecialType == SpecialType.System_String || right.Type?.SpecialType == SpecialType.System_String) { stringConcatenationCount++; } } } if (stringConcatenationCount > 3) { var rule = rules.Get(AllocationRules.StringConcatenationAllocationRule.Id); reportDiagnostic(Diagnostic.Create(rule, node.GetLocation(), EmptyMessageArgs)); } }
private static void ArgumentSyntaxCheck(EnabledRules rules, SyntaxNode node, SemanticModel semanticModel, bool isAssignmentToReadonly, Action <Diagnostic> reportDiagnostic, string filePath, CancellationToken cancellationToken) { var argument = node as ArgumentSyntax; if (argument.Expression != null) { if (rules.IsEnabled(AllocationRules.ValueTypeToReferenceTypeConversionRule.Id)) { var argumentTypeInfo = semanticModel.GetTypeInfo(argument.Expression, cancellationToken); var argumentConversionInfo = semanticModel.GetConversion(argument.Expression, cancellationToken); CheckTypeConversion(rules.Get(AllocationRules.ValueTypeToReferenceTypeConversionRule.Id), argumentConversionInfo, reportDiagnostic, argument.Expression.GetLocation(), filePath); CheckDelegateCreation(rules, argument.Expression, argumentTypeInfo, semanticModel, isAssignmentToReadonly, reportDiagnostic, argument.Expression.GetLocation(), filePath, cancellationToken); } } }
private static void CheckDelegateCreation(EnabledRules rules, SyntaxNode node, TypeInfo typeInfo, SemanticModel semanticModel, bool isAssignmentToReadonly, Action <Diagnostic> reportDiagnostic, Location location, string filePath, CancellationToken cancellationToken) { if (typeInfo.ConvertedType?.TypeKind != TypeKind.Delegate) { return; } if (rules.TryGet(AllocationRules.DelegateOnStructInstanceRule.Id, out var delegateOnStructRule)) { var symbolInfo = semanticModel.GetSymbolInfo(node, cancellationToken).Symbol; if (symbolInfo?.ContainingType?.IsValueType == true && symbolInfo.GetType().Name == "SourceMemberMethodSymbol") { reportDiagnostic(Diagnostic.Create(delegateOnStructRule, location, EmptyMessageArgs)); } } // new Action<Foo>(MethodGroup); should skip this one var insideObjectCreation = node?.Parent?.Parent?.Parent?.Kind() == SyntaxKind.ObjectCreationExpression; if (node is ParenthesizedLambdaExpressionSyntax || node is SimpleLambdaExpressionSyntax || node is AnonymousMethodExpressionSyntax || node is ObjectCreationExpressionSyntax || insideObjectCreation) { // skip this, because it's intended. return; } if (rules.IsEnabled(AllocationRules.MethodGroupAllocationRule.Id) && node.IsKind(SyntaxKind.IdentifierName)) { if (semanticModel.GetSymbolInfo(node, cancellationToken).Symbol is IMethodSymbol) { reportDiagnostic(Diagnostic.Create(rules.Get(AllocationRules.MethodGroupAllocationRule.Id), location, EmptyMessageArgs)); } } else if (node.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccess = node as MemberAccessExpressionSyntax; if (semanticModel.GetSymbolInfo(memberAccess.Name, cancellationToken).Symbol is IMethodSymbol) { if (isAssignmentToReadonly && rules.TryGet(AllocationRules.ReadonlyMethodGroupAllocationRule.Id, out var readonlyMethodGroupAllocationRule)) { reportDiagnostic(Diagnostic.Create(readonlyMethodGroupAllocationRule, location, EmptyMessageArgs)); } else if (rules.TryGet(AllocationRules.MethodGroupAllocationRule.Id, out var methodGroupAllocationRule)) { reportDiagnostic(Diagnostic.Create(methodGroupAllocationRule, location, EmptyMessageArgs)); } } } else if (node is ArrowExpressionClauseSyntax) { if (rules.TryGet(AllocationRules.MethodGroupAllocationRule.Id, out var methodGroupAllocationRule)) { var arrowClause = node as ArrowExpressionClauseSyntax; if (semanticModel.GetSymbolInfo(arrowClause.Expression, cancellationToken).Symbol is IMethodSymbol) { reportDiagnostic(Diagnostic.Create(methodGroupAllocationRule, location, EmptyMessageArgs)); } } } }