<commit_before>// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.IntroduceVariable
{
    internal partial class CSharpIntroduceVariableService
    {
        protected override Task<Document> IntroduceLocalAsync(
            SemanticDocument document,
            ExpressionSyntax expression,
            bool allOccurrences,
            bool isConstant,
            CancellationToken cancellationToken)
        {
            var options = document.Project.Solution.Workspace.Options;

            var newLocalNameToken = GenerateUniqueLocalName(document, expression, isConstant, cancellationToken);
            var newLocalName = SyntaxFactory.IdentifierName(newLocalNameToken);

            var modifiers = isConstant
                ? SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.ConstKeyword))
                : default(SyntaxTokenList);

            var declarationStatement = SyntaxFactory.LocalDeclarationStatement(
                modifiers,
                SyntaxFactory.VariableDeclaration(
                    this.GetTypeSyntax(document, expression, isConstant, options, cancellationToken),
                    SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(
                        newLocalNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()),
                        null,
                        SyntaxFactory.EqualsValueClause(expression.WithoutTrailingTrivia().WithoutLeadingTrivia())))));

            var anonymousMethodParameters = GetAnonymousMethodParameters(document, expression, cancellationToken);
            var lambdas = anonymousMethodParameters.SelectMany(p => p.ContainingSymbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax(cancellationToken)).AsEnumerable())
                                                   .Where(n => n is ParenthesizedLambdaExpressionSyntax || n is SimpleLambdaExpressionSyntax)
                                                   .ToSet();

            var parentLambda = GetParentLambda(expression, lambdas);

            if (parentLambda != null)
            {
                return Task.FromResult(IntroduceLocalDeclarationIntoLambda(
                    document, expression, newLocalName, declarationStatement, parentLambda, allOccurrences, cancellationToken));
            }
            else if (IsInExpressionBodiedMember(expression))
            {
                return Task.FromResult(RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
                    document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken));
            }
            else
            {
                return IntroduceLocalDeclarationIntoBlockAsync(
                    document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken);
            }
        }

        private Document IntroduceLocalDeclarationIntoLambda(
            SemanticDocument document,
            ExpressionSyntax expression,
            IdentifierNameSyntax newLocalName,
            LocalDeclarationStatementSyntax declarationStatement,
            SyntaxNode oldLambda,
            bool allOccurrences,
            CancellationToken cancellationToken)
        {
            var oldBody = oldLambda is ParenthesizedLambdaExpressionSyntax
                ? (ExpressionSyntax)((ParenthesizedLambdaExpressionSyntax)oldLambda).Body
                : (ExpressionSyntax)((SimpleLambdaExpressionSyntax)oldLambda).Body;

            var rewrittenBody = Rewrite(
                document, expression, newLocalName, document, oldBody, allOccurrences, cancellationToken);

            var delegateType = document.SemanticModel.GetTypeInfo(oldLambda, cancellationToken).ConvertedType as INamedTypeSymbol;

            var newBody = delegateType != null && delegateType.DelegateInvokeMethod != null && delegateType.DelegateInvokeMethod.ReturnsVoid
                ? SyntaxFactory.Block(declarationStatement)
                : SyntaxFactory.Block(declarationStatement, SyntaxFactory.ReturnStatement(rewrittenBody));

            newBody = newBody.WithAdditionalAnnotations(Formatter.Annotation);

            var newLambda = oldLambda is ParenthesizedLambdaExpressionSyntax
                ? ((ParenthesizedLambdaExpressionSyntax)oldLambda).WithBody(newBody)
                : (SyntaxNode)((SimpleLambdaExpressionSyntax)oldLambda).WithBody(newBody);

            var newRoot = document.Root.ReplaceNode(oldLambda, newLambda);
            return document.Document.WithSyntaxRoot(newRoot);
        }

        private SyntaxNode GetParentLambda(ExpressionSyntax expression, ISet<SyntaxNode> lambdas)
        {
            var current = expression;
            while (current != null)
            {
                if (lambdas.Contains(current.Parent))
                {
                    return current.Parent;
                }

                current = current.Parent as ExpressionSyntax;
            }

            return null;
        }

        private TypeSyntax GetTypeSyntax(SemanticDocument document, ExpressionSyntax expression, bool isConstant, OptionSet options, CancellationToken cancellationToken)
        {
            var typeSymbol = GetTypeSymbol(document, expression, cancellationToken);
            if (typeSymbol.ContainsAnonymousType())
            {
                return SyntaxFactory.IdentifierName("var");
            }

            if (!isConstant && options.GetOption(CSharpCodeStyleOptions.UseVarWhenDeclaringLocals) && CanUseVar(typeSymbol))
            {
                return SyntaxFactory.IdentifierName("var");
            }

            return typeSymbol.GenerateTypeSyntax();
        }

        private bool CanUseVar(ITypeSymbol typeSymbol)
        {
            return typeSymbol.TypeKind != TypeKind.Delegate
                && !typeSymbol.IsErrorType()<commit_msg>update CSharpIntroduceVariable to consume...<commit_after>// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle.TypeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.IntroduceVariable
{
    internal partial class CSharpIntroduceVariableService
    {
        protected override Task<Document> IntroduceLocalAsync(
            SemanticDocument document,
            ExpressionSyntax expression,
            bool allOccurrences,
            bool isConstant,
            CancellationToken cancellationToken)
        {
            var options = document.Project.Solution.Workspace.Options;

            var newLocalNameToken = GenerateUniqueLocalName(document, expression, isConstant, cancellationToken);
            var newLocalName = SyntaxFactory.IdentifierName(newLocalNameToken);

            var modifiers = isConstant
                ? SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.ConstKeyword))
                : default(SyntaxTokenList);

            var declarationStatement = SyntaxFactory.LocalDeclarationStatement(
                modifiers,
                SyntaxFactory.VariableDeclaration(
                    this.GetTypeSyntax(document, expression, isConstant, options, cancellationToken),
                    SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(
                        newLocalNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()),
                        null,
                        SyntaxFactory.EqualsValueClause(expression.WithoutTrailingTrivia().WithoutLeadingTrivia())))));

            var anonymousMethodParameters = GetAnonymousMethodParameters(document, expression, cancellationToken);
            var lambdas = anonymousMethodParameters.SelectMany(p => p.ContainingSymbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax(cancellationToken)).AsEnumerable())
                                                   .Where(n => n is ParenthesizedLambdaExpressionSyntax || n is SimpleLambdaExpressionSyntax)
                                                   .ToSet();

            var parentLambda = GetParentLambda(expression, lambdas);

            if (parentLambda != null)
            {
                return Task.FromResult(IntroduceLocalDeclarationIntoLambda(
                    document, expression, newLocalName, declarationStatement, parentLambda, allOccurrences, cancellationToken));
            }
            else if (IsInExpressionBodiedMember(expression))
            {
                return Task.FromResult(RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
                    document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken));
            }
            else
            {
                return IntroduceLocalDeclarationIntoBlockAsync(
                    document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken);
            }
        }

        private Document IntroduceLocalDeclarationIntoLambda(
            SemanticDocument document,
            ExpressionSyntax expression,
            IdentifierNameSyntax newLocalName,
            LocalDeclarationStatementSyntax declarationStatement,
            SyntaxNode oldLambda,
            bool allOccurrences,
            CancellationToken cancellationToken)
        {
            var oldBody = oldLambda is ParenthesizedLambdaExpressionSyntax
                ? (ExpressionSyntax)((ParenthesizedLambdaExpressionSyntax)oldLambda).Body
                : (ExpressionSyntax)((SimpleLambdaExpressionSyntax)oldLambda).Body;

            var rewrittenBody = Rewrite(
                document, expression, newLocalName, document, oldBody, allOccurrences, cancellationToken);

            var delegateType = document.SemanticModel.GetTypeInfo(oldLambda, cancellationToken).ConvertedType as INamedTypeSymbol;

            var newBody = delegateType != null && delegateType.DelegateInvokeMethod != null && delegateType.DelegateInvokeMethod.ReturnsVoid
                ? SyntaxFactory.Block(declarationStatement)
                : SyntaxFactory.Block(declarationStatement, SyntaxFactory.ReturnStatement(rewrittenBody));

            newBody = newBody.WithAdditionalAnnotations(Formatter.Annotation);

            var newLambda = oldLambda is ParenthesizedLambdaExpressionSyntax
                ? ((ParenthesizedLambdaExpressionSyntax)oldLambda).WithBody(newBody)
                : (SyntaxNode)((SimpleLambdaExpressionSyntax)oldLambda).WithBody(newBody);

            var newRoot = document.Root.ReplaceNode(oldLambda, newLambda);
            return document.Document.WithSyntaxRoot(newRoot);
        }

        private SyntaxNode GetParentLambda(ExpressionSyntax expression, ISet<SyntaxNode> lambdas)
        {
            var current = expression;
            while (current != null)
            {
                if (lambdas.Contains(current.Parent))
                {
                    return current.Parent;
                }

                current = current.Parent as ExpressionSyntax;
            }

            return null;
        }

        private TypeSyntax GetTypeSyntax(SemanticDocument document, ExpressionSyntax expression, bool isConstant, OptionSet options, CancellationToken cancellationToken)
        {
            var typeSymbol = GetTypeSymbol(document, expression, cancellationToken);
            if (typeSymbol.ContainsAnonymousType())
            {
                return SyntaxFactory.IdentifierName("var");
            }

            if (!isConstant && 
                CanUseVar(typeSymbol) && 
                TypeStyleHelper.IsImplicitTypePreferred(expression, document.SemanticModel, options, cancellationToken))
            {
                return SyntaxFactory.IdentifierName("var");
            }

            return typeSymbol.GenerateTypeSyntax();
        }

        private bool CanUseVar(ITypeSymbol typeSymbol)
        {
            return typeSymbol.TypeKind != TypeKind.Delegate
                && !typeSymbol.IsErrorType()
{'fraction_non_alphanumeric': 0.06652134696331931, 'fraction_numerical': 0.0003006614552014432, 'mean_word_length': 2.5689377682403434, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 13, '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': '6725539', 'n_tokens_mistral': 2980, 'n_tokens_neox': 2846, 'n_words': 579}