Beispiel #1
0
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var fromNodes = await context
                            .GetRelevantNodesAsync <TFromExpression>()
                            .ConfigureAwait(false);

            var from = fromNodes.FirstOrDefault(n => n.RawKind == FromKind);

            if (from == null)
            {
                return;
            }

            if (from.GetDiagnostics().Any(d => d.DefaultSeverity == DiagnosticSeverity.Error))
            {
                return;
            }

            var(document, _, cancellationToken) = context;

            var typeNode      = GetTypeNode(from);
            var semanticModel = await document
                                .GetRequiredSemanticModelAsync(cancellationToken)
                                .ConfigureAwait(false);

            var type = semanticModel.GetTypeInfo(typeNode, cancellationToken).Type;

            if (type is { TypeKind : not TypeKind.Error, IsReferenceType : true })
Beispiel #2
0
        protected override async Task <SyntaxNode?> GetSelectedClassDeclarationAsync(
            CodeRefactoringContext context
            )
        {
            var relaventNodes = await context
                                .GetRelevantNodesAsync <ClassDeclarationSyntax>()
                                .ConfigureAwait(false);

            return(relaventNodes.FirstOrDefault());
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, span, cancellationToken) = context;

            var root = await document
                       .GetRequiredSyntaxRootAsync(cancellationToken)
                       .ConfigureAwait(false);

            var node = root.FindNode(span);

            if (!IsInAsyncContext(node))
            {
                return;
            }

            var model = await document
                        .GetRequiredSemanticModelAsync(cancellationToken)
                        .ConfigureAwait(false);

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();

            var expressions = await context
                              .GetRelevantNodesAsync <TExpressionSyntax>()
                              .ConfigureAwait(false);

            for (var i = expressions.Length - 1; i >= 0; i--)
            {
                var expression = expressions[i];
                if (IsValidAwaitableExpression(expression, model, syntaxFacts))
                {
                    context.RegisterRefactoring(
                        new MyCodeAction(
                            GetTitle(),
                            c => AddAwaitAsync(document, expression, withConfigureAwait: false, c)
                            ),
                        expression.Span
                        );

                    context.RegisterRefactoring(
                        new MyCodeAction(
                            GetTitleWithConfigureAwait(),
                            c => AddAwaitAsync(document, expression, withConfigureAwait: true, c)
                            ),
                        expression.Span
                        );
                }
            }
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            var possibleExpressions = await context.GetRelevantNodesAsync <TExpressionSyntax>().ConfigureAwait(false);

            var syntaxFacts   = document.GetLanguageService <ISyntaxFactsService>();
            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            // let's take the largest (last) StringConcat we can given current textSpan
            var top = possibleExpressions
                      .Where(expr => IsStringConcat(syntaxFacts, expr, semanticModel, cancellationToken))
                      .LastOrDefault();

            if (top == null)
            {
                return;
            }

            // Currently we can concatenate only full subtrees. Therefore we can't support arbitrary selection. We could
            // theoretically support selecting the selections that correspond to full sub-trees (e.g. prefixes of
            // correct length but from UX point of view that it would feel arbitrary).
            // Thus, we only support selection that takes the whole topmost expression. It breaks some leniency around under-selection
            // but it's the best solution so far.
            if (CodeRefactoringHelpers.IsNodeUnderselected(top, textSpan) ||
                IsStringConcat(syntaxFacts, top.Parent, semanticModel, cancellationToken))
            {
                return;
            }

            // Now walk down the concatenation collecting all the pieces that we are
            // concatenating.
            var pieces = new List <SyntaxNode>();

            CollectPiecesDown(syntaxFacts, pieces, top, semanticModel, cancellationToken);

            var stringLiterals = pieces
                                 .Where(x => syntaxFacts.IsStringLiteralExpression(x) || syntaxFacts.IsCharacterLiteralExpression(x))
                                 .ToImmutableArray();

            // If the entire expression is just concatenated strings, then don't offer to
            // make an interpolated string.  The user likely manually split this for
            // readability.
            if (stringLiterals.Length == pieces.Count)
            {
                return;
            }

            var isVerbatimStringLiteral = false;

            if (stringLiterals.Length > 0)
            {
                // Make sure that all the string tokens we're concatenating are the same type
                // of string literal.  i.e. if we have an expression like: @" "" " + " \r\n "
                // then we don't merge this.  We don't want to be munging different types of
                // escape sequences in these strings, so we only support combining the string
                // tokens if they're all the same type.
                var firstStringToken = stringLiterals[0].GetFirstToken();
                isVerbatimStringLiteral = syntaxFacts.IsVerbatimStringLiteral(firstStringToken);
                if (stringLiterals.Any(
                        lit => isVerbatimStringLiteral != syntaxFacts.IsVerbatimStringLiteral(lit.GetFirstToken())))
                {
                    return;
                }
            }

            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var interpolatedString = CreateInterpolatedString(document, isVerbatimStringLiteral, pieces);

            context.RegisterRefactoring(
                new MyCodeAction(
                    _ => UpdateDocumentAsync(document, root, top, interpolatedString)),
                top.Span);
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            var possibleExpressions = await context.GetRelevantNodesAsync <TExpressionSyntax>().ConfigureAwait(false);

            var syntaxFacts   = document.GetRequiredLanguageService <ISyntaxFactsService>();
            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            // let's take the largest (last) StringConcat we can given current textSpan
            var top = possibleExpressions
                      .Where(expr => IsStringConcat(syntaxFacts, expr, semanticModel, cancellationToken))
                      .LastOrDefault();

            if (top == null)
            {
                return;
            }

            if (!syntaxFacts.SupportsConstantInterpolatedStrings(document.Project.ParseOptions !))
            {
                // if there is a const keyword, the refactoring shouldn't show because interpolated string is not const string
                var declarator = top.FirstAncestorOrSelf <SyntaxNode>(syntaxFacts.IsVariableDeclarator);
                if (declarator != null)
                {
                    var generator = SyntaxGenerator.GetGenerator(document);
                    if (generator.GetModifiers(declarator).IsConst)
                    {
                        return;
                    }
                }
            }

            // Currently we can concatenate only full subtrees. Therefore we can't support arbitrary selection. We could
            // theoretically support selecting the selections that correspond to full sub-trees (e.g. prefixes of
            // correct length but from UX point of view that it would feel arbitrary).
            // Thus, we only support selection that takes the whole topmost expression. It breaks some leniency around under-selection
            // but it's the best solution so far.
            if (CodeRefactoringHelpers.IsNodeUnderselected(top, textSpan) ||
                IsStringConcat(syntaxFacts, top.Parent, semanticModel, cancellationToken))
            {
                return;
            }

            // Now walk down the concatenation collecting all the pieces that we are
            // concatenating.
            using var _ = ArrayBuilder <SyntaxNode> .GetInstance(out var pieces);

            CollectPiecesDown(syntaxFacts, pieces, top, semanticModel, cancellationToken);

            var stringLiterals = pieces
                                 .Where(x => syntaxFacts.IsStringLiteralExpression(x) || syntaxFacts.IsCharacterLiteralExpression(x))
                                 .ToImmutableArray();

            // If the entire expression is just concatenated strings, then don't offer to
            // make an interpolated string.  The user likely manually split this for
            // readability.
            if (stringLiterals.Length == pieces.Count)
            {
                return;
            }

            var isVerbatimStringLiteral = false;

            if (stringLiterals.Length > 0)
            {
                // Make sure that all the string tokens we're concatenating are the same type
                // of string literal.  i.e. if we have an expression like: @" "" " + " \r\n "
                // then we don't merge this.  We don't want to be munging different types of
                // escape sequences in these strings, so we only support combining the string
                // tokens if they're all the same type.
                var firstStringToken = stringLiterals[0].GetFirstToken();
                isVerbatimStringLiteral = syntaxFacts.IsVerbatimStringLiteral(firstStringToken);
                if (stringLiterals.Any(