Example #1
0
        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);
                }
            }
        }
Example #2
0
        private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
        {
            var methodDeclaration = (MethodDeclarationSyntax)context.Node;

            if (methodDeclaration.ContainsDiagnostics)
            {
                return;
            }

            if (!methodDeclaration.IsParentKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.RecordDeclaration, SyntaxKind.RecordStructDeclaration))
            {
                return;
            }

            if (methodDeclaration.Modifiers.ContainsAny(
                    SyntaxKind.AbstractKeyword,
                    SyntaxKind.VirtualKeyword,
                    SyntaxKind.OverrideKeyword,
                    SyntaxKind.PartialKeyword))
            {
                return;
            }

            ParameterInfo parameterInfo = SyntaxInfo.ParameterInfo(methodDeclaration);

            if (!parameterInfo.Success)
            {
                return;
            }

            if (ContainsOnlyThrowNewExpression(parameterInfo.Body))
            {
                return;
            }

            IMethodSymbol methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken);

            if (methodSymbol == null)
            {
                return;
            }

            if (SymbolUtility.IsEventHandlerMethod(methodSymbol))
            {
                return;
            }

            if (!methodSymbol.ExplicitInterfaceImplementations.IsDefaultOrEmpty)
            {
                return;
            }

            if (methodSymbol.ImplementsInterfaceMember(allInterfaces: true))
            {
                return;
            }

            UnusedParameterWalker walker = null;

            try
            {
                walker = UnusedParameterWalker.GetInstance();

                walker.SetValues(context.SemanticModel, context.CancellationToken);

                FindUnusedNodes(parameterInfo, walker);

                if (walker.Nodes.Count > 0 &&
                    !MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(methodDeclaration, methodSymbol, context.SemanticModel, context.CancellationToken))
                {
                    foreach (KeyValuePair <string, NodeSymbolInfo> kvp in walker.Nodes)
                    {
                        ReportDiagnostic(context, kvp.Value.Node);
                    }
                }
            }
            finally
            {
                if (walker != null)
                {
                    UnusedParameterWalker.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();

                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();
                        }

                        if (walker.Parameters.ContainsKey(parameter.Name))
                        {
                            SyntaxWalker.Free(walker);
                            return;
                        }

                        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);
            }

            switch (declaration.Kind())
            {
            case SyntaxKind.MethodDeclaration:
            {
                if (MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.Parent, methodSymbol, semanticModel, cancellationToken))
                {
                    return;
                }

                break;
            }

            case SyntaxKind.LocalFunctionStatement:
            {
                if (MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.FirstAncestor <MemberDeclarationSyntax>(), methodSymbol, semanticModel, cancellationToken))
                {
                    return;
                }

                break;
            }
            }

            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);
        }