<commit_before>﻿using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using ErrorProne.NET.Common;
using ErrorProne.NET.Extensions;
using ErrorProne.NET.Utils;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace ErrorProne.NET.ExceptionHandlingRules
{
    /// <summary>
    /// Detects `catch` blocks that swallow an exception.
    /// </summary>
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public sealed class SwallowAllExceptionAnalyzer : DiagnosticAnalyzer
    {
        // Catch is not empty, `catch` or `catch(Exception)` and some return statement exists. 
        public const string DiagnosticId = RuleIds.AllExceptionSwalled;
        internal const string Title = "Catching everything considered harmful.";
        internal const string MessageFormat = "Exit point '{0}' swallows an unobserved exception.";
        private const string Description = "Generic catch block swallows an exception that was not observed.";
        internal const string Category = "CodeSmell";

        internal static readonly DiagnosticDescriptor Rule = 
            new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, description: Description, isEnabledByDefault: true);

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

        public override void Initialize(AnalysisContext context)
        {
            context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.CatchClause);
        }

        // Called when Roslyn encounters a catch clause.
        private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
        {
            var catchBlock = (CatchClauseSyntax)context.Node;

            if (catchBlock.Declaration == null || catchBlock.Declaration.CatchIsTooGeneric(context.SemanticModel))
            {
                var usages = context.SemanticModel.GetExceptionIdentifierUsages(catchBlock);

                bool wasObserved =
                    usages.
                        Select(id => id.Identifier)
                        .Any(u => u.Parent is ArgumentSyntax || // Exception object was used directly
                                  u.Parent is AssignmentExpressionSyntax || // Was saved to field or local
                                  // or Inner exception, Message or other properties were used
                                  u.Parent is MemberAccessExpressionSyntax);

                if (wasObserved)
                {<commit_msg>Fix false warning when exception observed in interpolation string.<commit_after>﻿using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using ErrorProne.NET.Common;
using ErrorProne.NET.Extensions;
using ErrorProne.NET.Utils;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace ErrorProne.NET.ExceptionHandlingRules
{
    /// <summary>
    /// Detects `catch` blocks that swallow an exception.
    /// </summary>
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public sealed class SwallowAllExceptionAnalyzer : DiagnosticAnalyzer
    {
        // Catch is not empty, `catch` or `catch(Exception)` and some return statement exists. 
        public const string DiagnosticId = RuleIds.AllExceptionSwalled;
        internal const string Title = "Catching everything considered harmful.";
        internal const string MessageFormat = "Exit point '{0}' swallows an unobserved exception.";
        private const string Description = "Generic catch block swallows an exception that was not observed.";
        internal const string Category = "CodeSmell";

        internal static readonly DiagnosticDescriptor Rule = 
            new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, description: Description, isEnabledByDefault: true);

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

        public override void Initialize(AnalysisContext context)
        {
            context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.CatchClause);
        }

        // Called when Roslyn encounters a catch clause.
        private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
        {
            var catchBlock = (CatchClauseSyntax)context.Node;

            if (catchBlock.Declaration == null || catchBlock.Declaration.CatchIsTooGeneric(context.SemanticModel))
            {
                var usages = context.SemanticModel.GetExceptionIdentifierUsages(catchBlock);

                    bool wasObserved =
                    usages.
                        Select(id => id.Identifier)
                        .Any(u => u.Parent is ArgumentSyntax || // Exception object was used directly
                                  u.Parent is AssignmentExpressionSyntax || // Was saved to field or local
                                  // For instance in Console.WriteLine($"e = {e}");
                                  u.Parent is InterpolationSyntax ||
                                  // or Inner exception, Message or other properties were used
                                  u.Parent is MemberAccessExpressionSyntax);

                if (wasObserved)
                {
{'fraction_non_alphanumeric': 0.07111756168359942, 'fraction_numerical': 0.000362844702467344, 'mean_word_length': 2.6009144350097975, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1923351', 'n_tokens_mistral': 1283, 'n_tokens_neox': 1222, 'n_words': 376}