Пример #1
0
 public static SyntaxToken WithRenameAnnotation(this SyntaxToken token)
 {
     return(token.WithAdditionalAnnotations(RenameAnnotation.Create()));
 }
        protected async override Task <IEnumerable <CodeActionOperation> > ComputeOperationsAsync(CancellationToken cancellationToken)
        {
            Project project = null;

            if (string.IsNullOrEmpty(options.ExtractDto.Project) == false)
            {
                project = document.Project.Solution.Projects.FirstOrDefault(x => x.Name == options.ExtractDto.Project);
            }
            else
            {
                project = document.Project;
            }

            var  identifierToken = this.typeDeclaration.Identifier;
            var  identifierText  = identifierToken.Text;
            bool isInterface     = this.typeDeclaration.IsKind(SyntaxKind.InterfaceDeclaration);

            if (isInterface && this.typeDeclaration.Identifier.Text.StartsWith("I"))
            {
                identifierText = identifierText.Substring(1);
            }

            var dtoName = identifierText + "Dto";

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken);

            var typeSymbol = semanticModel.GetDeclaredSymbol(this.typeDeclaration, cancellationToken);

            var publicMembers = SyntaxFactory.List <MemberDeclarationSyntax>();

            foreach (var member in this.typeDeclaration.Members)
            {
                switch (member.Kind())
                {
                case SyntaxKind.PropertyDeclaration:
                    var property = member as PropertyDeclarationSyntax;
                    if (isInterface == false && property.Modifiers.Any(SyntaxKind.PublicKeyword) == false)
                    {
                        continue;
                    }

                    var newProperty = property.WithAccessorList(
                        SyntaxFactory.AccessorList(
                            property.AccessorList.OpenBraceToken,
                            SyntaxFactory.List(
                                new[] { SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
                                        SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) }),
                            property.AccessorList.CloseBraceToken));

                    if (isInterface)
                    {
                        newProperty = newProperty.WithModifiers(
                            SyntaxFactory.TokenList(
                                property.Modifiers.Add(
                                    SyntaxFactory.Token(SyntaxKind.PublicKeyword))));
                    }

                    publicMembers = publicMembers.Add(newProperty);
                    break;

                case SyntaxKind.MethodDeclaration:
                    if (options.ExtractDto.ImplementMethods == false)
                    {
                        continue;
                    }
                    var method = member as MethodDeclarationSyntax;
                    if (isInterface || method.Modifiers.Any(SyntaxKind.AbstractKeyword))
                    {
                        publicMembers = publicMembers
                                        .Add(
                            method
                            .WithBody(
                                SyntaxFactory.Block()
                                .WithStatements(
                                    SyntaxFactory.SingletonList <StatementSyntax>(
                                        SyntaxFactory.ThrowStatement(
                                            SyntaxFactory.ObjectCreationExpression(
                                                SyntaxFactory.IdentifierName("NotImplementedException"))
                                            .WithArgumentList(SyntaxFactory.ArgumentList())))))
                            .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None))
                            .WithModifiers(
                                SyntaxFactory.TokenList(
                                    SyntaxFactory.Token(isInterface ? SyntaxKind.PublicKeyword : SyntaxKind.None))));
                    }
                    break;
                }
            }

            var compilation = this.typeDeclaration.SyntaxTree.GetCompilationUnitRoot(cancellationToken);

            var classDecl = SyntaxFactory.ClassDeclaration(SyntaxFactory.Identifier(dtoName).WithAdditionalAnnotations(RenameAnnotation.Create()))
                            .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
                            .WithTypeParameterList(this.typeDeclaration.TypeParameterList)
                            .WithMembers(publicMembers);

            var oldNameSpace     = this.typeDeclaration.FirstAncestorOrSelf <NamespaceDeclarationSyntax>();
            var newNamespaceName = this.GetNewNamespaceName(options, document);
            var newNameSpace     = SyntaxFactory.NamespaceDeclaration(newNamespaceName)
                                   .AddMembers(classDecl);

            var syntaxRoot = SyntaxFactory.CompilationUnit()
                             .WithUsings(
                SyntaxFactory.List(
                    compilation.Usings
                    .Add(SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("System")))
                    .Add(SyntaxFactory.UsingDirective(oldNameSpace.Name))
                    .Select(x => x.WithAdditionalAnnotations(Simplifier.Annotation))))
                             .WithMembers(SyntaxFactory.List <MemberDeclarationSyntax>().Add(newNameSpace));

            var originalSolution = document.Project.Solution;
            var newDoc           = project.AddDocument(dtoName, syntaxRoot, (options.ExtractDto.Folders ?? Enumerable.Empty <string>()).Any() ? options.ExtractDto.Folders : document.Folders);

            return(new CodeActionOperation[] { new ApplyChangesOperation(newDoc.Project.Solution), new OpenDocumentOperation(newDoc.Id, true) });
        }
Пример #3
0
        private static RenameResult RenameSymbol(Document document, SyntaxNode root, SyntaxNode startNode, VariableDeclaratorSyntax declarationNode, string newName)
        {
            var identifierToken = declarationNode.Identifier;

            var methodAnnotation = new SyntaxAnnotation(SELECTED_METHOD_ANNOTATION);
            var changeDic        = new Dictionary <SyntaxNode, SyntaxNode>();

            changeDic.Add(startNode, startNode.WithAdditionalAnnotations(methodAnnotation));
            changeDic.Add(declarationNode, declarationNode.WithIdentifier(identifierToken.WithAdditionalAnnotations(RenameAnnotation.Create())));

            var annotatedRoot = root.ReplaceNodes(changeDic.Keys, (x, y) => changeDic[x]);

            var newSolution = RenameSymbol(document, annotatedRoot, identifierToken, methodAnnotation, newName).Result;

            return(GetNewStartNode(newSolution, document, methodAnnotation, startNode));
        }
Пример #4
0
        internal static async Task <Solution> RenameSymbolAsync(Document document, SyntaxNode root, SyntaxToken declarationToken, string newName, CancellationToken cancellationToken)
        {
            var annotatedRoot     = root.ReplaceToken(declarationToken, declarationToken.WithAdditionalAnnotations(RenameAnnotation.Create()));
            var annotatedSolution = document.Project.Solution.WithDocumentSyntaxRoot(document.Id, annotatedRoot);
            var annotatedDocument = annotatedSolution.GetDocument(document.Id);

            annotatedRoot = await annotatedDocument !.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var annotatedToken = annotatedRoot.FindToken(declarationToken.SpanStart);

            var semanticModel = await annotatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var symbol = annotatedToken.Parent is IdentifierNameSyntax
                             ? semanticModel.GetSymbolSafe(annotatedToken.Parent, cancellationToken)
                             : semanticModel.GetDeclaredSymbolSafe(annotatedToken.Parent, cancellationToken);

            var newSolution = await Renamer.RenameSymbolAsync(annotatedSolution, symbol, newName, null, cancellationToken).ConfigureAwait(false);

            return(newSolution);
        }
        private async Task <Document> ConvertForToForEachAsync(
            Document document, TForStatementSyntax forStatement,
            SyntaxToken iterationVariable, TExpressionSyntax collectionExpression,
            INamedTypeSymbol containingType, ITypeSymbol collectionType,
            ITypeSymbol iterationType, CancellationToken cancellationToken)
        {
            var syntaxFacts   = document.GetLanguageService <ISyntaxFactsService>();
            var semanticFacts = document.GetLanguageService <ISemanticFactsService>();
            var generator     = SyntaxGenerator.GetGenerator(document);

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

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

            var editor = new SyntaxEditor(root, generator);

            // create a dummy "list[i]" expression.  We'll use this to find all places to replace
            // in the current for statement.
            var indexExpression = generator.ElementAccessExpression(
                collectionExpression, generator.IdentifierName(iterationVariable));

            // See if the first statement in the for loop is of the form:
            //      var x = list[i]   or
            //
            // If so, we'll use those as the iteration variables for the new foreach statement.
            var(typeNode, foreachIdentifier, declarationStatement) = TryDeconstructInitialDeclaration();

            if (typeNode == null)
            {
                // user didn't provide an explicit type.  Check if the index-type of the collection
                // is different from than .Current type of the enumerator.  If so, add an explicit
                // type so that the foreach will coerce the types accordingly.
                var indexerType = GetIndexerType(containingType, collectionType);
                if (!Equals(indexerType, iterationType))
                {
                    typeNode = (TTypeNode)generator.TypeExpression(
                        indexerType ?? semanticModel.Compilation.GetSpecialType(SpecialType.System_Object));
                }
            }

            // If we couldn't find an appropriate existing variable to use as the foreach
            // variable, then generate one automatically.
            if (foreachIdentifier.RawKind == 0)
            {
                foreachIdentifier = semanticFacts.GenerateUniqueName(
                    semanticModel, forStatement, containerOpt: null, baseName: "v", usedNames: Enumerable.Empty <string>(), cancellationToken);
                foreachIdentifier = foreachIdentifier.WithAdditionalAnnotations(RenameAnnotation.Create());
            }

            // Create the expression we'll use to replace all matches in the for-body.
            var foreachIdentifierReference = foreachIdentifier.WithoutAnnotations(RenameAnnotation.Kind).WithoutTrivia();

            // Walk the for statement, replacing any matches we find.
            FindAndReplaceMatches(forStatement);

            // Finally, remove the declaration statement if we found one.  Move all its leading
            // trivia to the next statement.
            if (declarationStatement != null)
            {
                editor.RemoveNode(declarationStatement,
                                  SyntaxGenerator.DefaultRemoveOptions | SyntaxRemoveOptions.KeepLeadingTrivia);
            }

            var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            editor.ReplaceNode(
                forStatement,
                (currentFor, _) => this.ConvertForNode(
                    (TForStatementSyntax)currentFor, typeNode, foreachIdentifier,
                    collectionExpression, iterationType, options));

            return(document.WithSyntaxRoot(editor.GetChangedRoot()));

            // local functions
            (TTypeNode, SyntaxToken, TStatementSyntax) TryDeconstructInitialDeclaration()
            {
                var bodyStatements = GetBodyStatements(forStatement);

                if (bodyStatements.Count >= 1)
                {
                    var firstStatement = bodyStatements[0];
                    if (syntaxFacts.IsLocalDeclarationStatement(firstStatement))
                    {
                        var firstVariable = (TVariableDeclarationSyntax)syntaxFacts.GetVariablesOfLocalDeclarationStatement(firstStatement);
                        if (IsValidVariableDeclaration(firstVariable))
                        {
                            var firstVariableInitializer = syntaxFacts.GetValueOfEqualsValueClause(
                                syntaxFacts.GetInitializerOfVariableDeclaration(firstVariable));
                            if (syntaxFacts.AreEquivalent(firstVariableInitializer, indexExpression))
                            {
                                var type       = (TTypeNode)syntaxFacts.GetTypeOfVariableDeclaration(firstVariable)?.WithoutLeadingTrivia();
                                var identifier = syntaxFacts.GetIdentifierOfVariableDeclaration(firstVariable);
                                var statement  = firstStatement;
                                return(type, identifier, statement);
                            }
                        }
                    }
                }

                return(default);
Пример #6
0
        public static async Task <Solution> RenameSymbolAsync(Document document, SyntaxNode root, SyntaxToken declarationToken, string newName, CancellationToken cancellationToken)
        {
            var annotatedRoot     = root.ReplaceToken(declarationToken, declarationToken.WithAdditionalAnnotations(RenameAnnotation.Create()));
            var annotatedSolution = document.Project.Solution.WithDocumentSyntaxRoot(document.Id, annotatedRoot);
            var annotatedDocument = annotatedSolution.GetDocument(document.Id);

            annotatedRoot = await annotatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var annotatedToken = annotatedRoot.FindToken(declarationToken.SpanStart);

            var semanticModel = await annotatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var symbol = semanticModel.GetDeclaredSymbol(annotatedToken.Parent, cancellationToken);

            var newSolution = await Renamer.RenameSymbolAsync(annotatedSolution, symbol, newName, null, cancellationToken).ConfigureAwait(false);

            foreach (var project in newSolution.Projects)
            {
                var compilation = await project.GetCompilationAsync(cancellationToken);

                var diagnostics = compilation.GetDiagnostics();
                foreach (var diagnostic in diagnostics)
                {
                    if (NamingConflictDiagnosticIds.Contains(diagnostic.Id))
                    {
                        // If we got here, it means there was a naming conflict
                        // I believe every warning contains the name of the conflicting member in its description
                        // Therefore we can look whether the description contains the new identifier and if it does, return the annotated solution

                        if (diagnostic.GetMessage().Contains(newName))
                        {
                            return(newSolution);
                        }
                    }
                }
            }

            // If we got here it means there weren't any new errors introduced by renaming
            // So we can just return the renamed solution without rename IDE helper
            var originalSemanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var originalSymbol = originalSemanticModel.GetDeclaredSymbol(declarationToken.Parent, cancellationToken);

            return(await Renamer.RenameSymbolAsync(document.Project.Solution, originalSymbol, newName, null, cancellationToken));
        }
        protected override async Task <Document> IntroduceLocalAsync(
            SemanticDocument document,
            ExpressionSyntax expression,
            bool allOccurrences,
            bool isConstant,
            CancellationToken cancellationToken)
        {
            var containerToGenerateInto = GetContainerToGenerateInto(document, expression, cancellationToken);

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

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

            var options = await document.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

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

            switch (containerToGenerateInto)
            {
            case BlockSyntax block:
                return(await IntroduceLocalDeclarationIntoBlockAsync(
                           document, block, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(false));

            case ArrowExpressionClauseSyntax arrowExpression:
                // this will be null for expression-bodied properties & indexer (not for individual getters & setters, those do have a symbol),
                // both of which are a shorthand for the getter and always return a value
                var  method = document.SemanticModel.GetDeclaredSymbol(arrowExpression.Parent) as IMethodSymbol;
                bool createReturnStatement = !method?.ReturnsVoid ?? true;

                return(RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
                           document, arrowExpression, expression, newLocalName,
                           declarationStatement, allOccurrences, createReturnStatement, cancellationToken));

            case LambdaExpressionSyntax lambda:
                return(IntroduceLocalDeclarationIntoLambda(
                           document, lambda, expression, newLocalName, declarationStatement,
                           allOccurrences, cancellationToken));
            }

            throw new InvalidOperationException();
        }
Пример #8
0
        private static ForStatementSyntax ConvertToFor(
            ForEachStatementSyntax forEachStatement,
            SemanticModel semanticModel,
            string lengthMemberName)
        {
            var collectionExpression = forEachStatement.Expression;

            var collectionType = semanticModel.GetTypeInfo(collectionExpression).Type;

            string counterName = NameHelper.GetLoopCounterName(forEachStatement.Statement.SpanStart, semanticModel);

            var counterIdentifier = SyntaxFactory
                                    .IdentifierName(counterName)
                                    .WithAdditionalAnnotations(RenameAnnotation.Create());

            var initializer = SyntaxFactory.EqualsValueClause(
                SyntaxFactory.LiteralExpression(
                    SyntaxKind.NumericLiteralExpression,
                    SyntaxFactory.Literal(0)
                    )
                );

            var declarator = SyntaxFactory.VariableDeclarator(
                SyntaxFactory.Identifier(counterName)
                .WithAdditionalAnnotations(RenameAnnotation.Create()),
                null,
                initializer);

            var counterDeclaration = SyntaxFactory.VariableDeclaration(
                SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)),
                SyntaxFactory.SingletonSeparatedList(declarator));

            var lengthAccess =
                SyntaxFactory.MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    collectionExpression,
                    SyntaxFactory.IdentifierName(lengthMemberName)
                    );

            var condition = SyntaxFactory.BinaryExpression(
                SyntaxKind.LessThanExpression,
                counterIdentifier,
                lengthAccess);

            var counterIncrementor = SyntaxFactory.PostfixUnaryExpression(
                SyntaxKind.PostIncrementExpression,
                counterIdentifier);

            var elementAccess =
                SyntaxFactory.ElementAccessExpression(
                    collectionExpression,
                    SyntaxFactory.BracketedArgumentList(
                        SyntaxFactory.SingletonSeparatedList(
                            SyntaxFactory.Argument(counterIdentifier)
                            )
                        )
                    );

            var rewriter = new ForeachToForLoopBodyRewriter(
                elementAccess,
                forEachStatement.Identifier.Text,
                semanticModel.GetDeclaredSymbol(forEachStatement),
                semanticModel);

            var newLoopBody = (StatementSyntax)forEachStatement.Statement.Accept(rewriter);

            var forStatement = SyntaxFactory.ForStatement(
                counterDeclaration,
                SyntaxFactory.SeparatedList <ExpressionSyntax>(),
                condition,
                SyntaxFactory.SingletonSeparatedList <ExpressionSyntax>(counterIncrementor),
                newLoopBody);

            forStatement = forStatement
                           .WithTriviaFrom(forEachStatement)
                           .WithAdditionalAnnotations(Simplifier.Annotation);

            return(forStatement);
        }
Пример #9
0
    private static async Task <Document> ConvertToSourceGenerator(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
    {
        var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);

        var generator     = editor.Generator;
        var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

        var compilation = semanticModel !.Compilation;

        var regexSymbol = compilation.GetTypeByMetadataName("System.Text.RegularExpressions.Regex");
        var regexGeneratorAttributeSymbol = compilation.GetTypeByMetadataName("System.Text.RegularExpressions.RegexGeneratorAttribute");

        if (regexSymbol is null || regexGeneratorAttributeSymbol is null)
        {
            return(document);
        }

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

        var nodeToFix       = root?.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: false);
        var typeDeclaration = nodeToFix?.Ancestors().OfType <TypeDeclarationSyntax>().FirstOrDefault();

        if (root == null || nodeToFix == null || typeDeclaration == null)
        {
            return(document);
        }

        // Get type info before changing the root
        var properties = diagnostic.Properties;
        var operation  = semanticModel.GetOperation(nodeToFix, cancellationToken);

        if (operation == null)
        {
            return(document);
        }

        // Generate unique method name
        var methodName = "MyRegex";
        var typeSymbol = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken);

        if (typeSymbol is not null)
        {
            var members = typeSymbol.GetAllMembers();
            while (members.Any(m => m.Name == methodName))
            {
                methodName += "_";
            }
        }

        // Add partial to the type hierarchy
        var count = 0;

        root = root.ReplaceNodes(nodeToFix.Ancestors().OfType <TypeDeclarationSyntax>(), (_, r) =>
        {
            if (!r.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)))
            {
                count++;
                return(r.AddModifiers(Token(SyntaxKind.PartialKeyword)).WithAdditionalAnnotations(Simplifier.Annotation));
            }

            return(r);
        });

        // Get the new node to fix in the new syntax tree
        nodeToFix = root.FindNode(new Microsoft.CodeAnalysis.Text.TextSpan(nodeToFix.Span.Start + (count * "partial".Length), nodeToFix.Span.Length));
        if (nodeToFix == null)
        {
            return(document);
        }

        typeDeclaration = nodeToFix.Ancestors().OfType <TypeDeclarationSyntax>().FirstOrDefault();
        if (typeDeclaration == null)
        {
            return(document);
        }

        var newTypeDeclaration = typeDeclaration;

        // Use new method
        if (operation is IObjectCreationOperation)
        {
            var invokeMethod = generator.InvocationExpression(generator.IdentifierName(methodName));
            newTypeDeclaration = newTypeDeclaration.ReplaceNode(nodeToFix, invokeMethod);
        }
        else if (operation is IInvocationOperation invocationOperation)
        {
            var arguments = invocationOperation.Arguments;
            var indices   = new[]
            {
                TryParseInt32(properties, UseRegexSourceGeneratorAnalyzer.PatternIndexName),
                TryParseInt32(properties, UseRegexSourceGeneratorAnalyzer.RegexOptionsIndexName),
                TryParseInt32(properties, UseRegexSourceGeneratorAnalyzer.RegexTimeoutIndexName),
            };
            foreach (var index in indices.Where(value => value != null).OrderByDescending(value => value))
            {
                arguments = arguments.RemoveAt(index.GetValueOrDefault());
            }

            var createRegexMethod = generator.InvocationExpression(generator.IdentifierName(methodName));
            var method            = generator.InvocationExpression(generator.MemberAccessExpression(createRegexMethod, invocationOperation.TargetMethod.Name), arguments.Select(arg => arg.Syntax).ToArray());

            newTypeDeclaration = newTypeDeclaration.ReplaceNode(nodeToFix, method);
        }

        // Generate method
        SyntaxNode?patternValue      = null;
        SyntaxNode?regexOptionsValue = null;
        SyntaxNode?timeoutValue      = null;

        var timeout = TryParseInt32(properties, UseRegexSourceGeneratorAnalyzer.RegexTimeoutName);

        if (timeout != null)
        {
            timeoutValue = generator.LiteralExpression(timeout.Value);
        }

        if (operation is IObjectCreationOperation objectCreationOperation)
        {
            patternValue      = GetNode(objectCreationOperation.Arguments, properties, UseRegexSourceGeneratorAnalyzer.PatternIndexName);
            regexOptionsValue = GetNode(objectCreationOperation.Arguments, properties, UseRegexSourceGeneratorAnalyzer.RegexOptionsIndexName);
        }
        else if (operation is IInvocationOperation invocationOperation)
        {
            patternValue      = GetNode(invocationOperation.Arguments, properties, UseRegexSourceGeneratorAnalyzer.PatternIndexName);
            regexOptionsValue = GetNode(invocationOperation.Arguments, properties, UseRegexSourceGeneratorAnalyzer.RegexOptionsIndexName);
        }

        if (timeoutValue != null && regexOptionsValue is null)
        {
            regexOptionsValue = generator.MemberAccessExpression(generator.TypeExpression(compilation.GetTypeByMetadataName("System.Text.RegularExpressions.RegexOptions") !), "None");
        }

        var newMethod = (MethodDeclarationSyntax)generator.MethodDeclaration(
            name: methodName,
            returnType: generator.TypeExpression(regexSymbol),
            modifiers: DeclarationModifiers.Static | DeclarationModifiers.Partial,
            accessibility: Accessibility.Private);

        newMethod = newMethod.ReplaceToken(newMethod.Identifier, Identifier(methodName).WithAdditionalAnnotations(RenameAnnotation.Create()));

        // Extract arguments (pattern,options,timeout)
        var attributes = generator.Attribute(generator.TypeExpression(regexGeneratorAttributeSymbol), attributeArguments: (patternValue, regexOptionsValue, timeoutValue) switch
        {
            ({ }, null, null) => new[] { patternValue },
        protected override Task <Tuple <Document, SyntaxNode, int> > IntroduceFieldAsync(
            SemanticDocument document,
            ExpressionSyntax expression,
            bool allOccurrences,
            bool isConstant,
            CancellationToken cancellationToken)
        {
            var oldTypeDeclaration = expression.GetAncestorOrThis <TypeDeclarationSyntax>();

            var oldType = oldTypeDeclaration != null
                                ? document.SemanticModel.GetDeclaredSymbol(oldTypeDeclaration, cancellationToken) as INamedTypeSymbol
                                : document.SemanticModel.Compilation.ScriptClass;

            var newNameToken = (SyntaxToken)GenerateUniqueFieldName(document, expression, isConstant, cancellationToken);

            var newQualifiedName = oldTypeDeclaration != null
                                ? SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParseName(oldType.ToDisplayString(Ambience.NameFormat)), SyntaxFactory.IdentifierName(newNameToken))
                                : (ExpressionSyntax)SyntaxFactory.IdentifierName(newNameToken);

            newQualifiedName = newQualifiedName.WithAdditionalAnnotations(Simplifier.Annotation);

            var newFieldDeclaration = SyntaxFactory.FieldDeclaration(
                default(SyntaxList <AttributeListSyntax>),
                MakeFieldModifiers(isConstant, inScript: oldType.IsScriptClass),
                SyntaxFactory.VariableDeclaration(
                    GetTypeSymbol(document, expression, cancellationToken).GenerateTypeSyntax(),
                    SyntaxFactory.SingletonSeparatedList(
                        SyntaxFactory.VariableDeclarator(
                            newNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()),
                            null,
                            SyntaxFactory.EqualsValueClause(expression))))).WithAdditionalAnnotations(Formatter.Annotation);

            if (oldTypeDeclaration != null)
            {
                var newTypeDeclaration = Rewrite(
                    document, expression, newQualifiedName, document, oldTypeDeclaration, allOccurrences, cancellationToken);

                var insertionIndex = isConstant ?
                                     DetermineConstantInsertPosition(oldTypeDeclaration.Members, newTypeDeclaration.Members) :
                                     DetermineFieldInsertPosition(oldTypeDeclaration.Members, newTypeDeclaration.Members);

                var finalTypeDeclaration = InsertMember(newTypeDeclaration, newFieldDeclaration, insertionIndex);

                SyntaxNode destination = oldTypeDeclaration;
                var        newRoot     = document.Root.ReplaceNode(oldTypeDeclaration, finalTypeDeclaration);
                return(Task.FromResult(Tuple.Create(document.Document.WithSyntaxRoot(newRoot), destination, insertionIndex)));
            }
            else
            {
                var oldCompilationUnit = (CompilationUnitSyntax)document.Root;
                var newCompilationUnit = Rewrite(
                    document, expression, newQualifiedName, document, oldCompilationUnit, allOccurrences, cancellationToken);

                var insertionIndex = isConstant ?
                                     DetermineConstantInsertPosition(oldCompilationUnit.Members, newCompilationUnit.Members) :
                                     DetermineFieldInsertPosition(oldCompilationUnit.Members, newCompilationUnit.Members);

                SyntaxNode destination = oldCompilationUnit;
                var        newRoot     = newCompilationUnit.WithMembers(newCompilationUnit.Members.Insert(insertionIndex, newFieldDeclaration));
                return(Task.FromResult(Tuple.Create(document.Document.WithSyntaxRoot(newRoot), destination, insertionIndex)));
            }
        }
Пример #11
0
        static async Task <RenameResult> RenameSymbolAsync(Document document, SyntaxNode root, SyntaxNode startNode, ParameterSyntax declarationNode, string newName)
        {
            var identifierToken = declarationNode.Identifier;

            var methodAnnotation = new SyntaxAnnotation(SELECTED_METHOD_ANNOTATION);
            var changeDic        = new Dictionary <SyntaxNode, SyntaxNode>();

            if (startNode != null)
            {
                changeDic.Add(startNode, startNode.WithAdditionalAnnotations(methodAnnotation));
            }

            changeDic.Add(declarationNode, declarationNode.WithIdentifier(identifierToken.WithAdditionalAnnotations(RenameAnnotation.Create())));

            var annotatedRoot = root.ReplaceNodes(changeDic.Keys, (x, y) => changeDic[x]);

            var newSolution = await RenameSymbolAsync(document, annotatedRoot, identifierToken, methodAnnotation, newName);

            return(await GetNewStartNodeAsync(newSolution, document, methodAnnotation, startNode));
        }
Пример #12
0
 static CodeAction AddCompareIssue(Document document, SemanticModel semanticModel, SyntaxNode root, BinaryExpressionSyntax node, string floatType)
 {
     return(CodeActionFactory.Create(node.Span, DiagnosticSeverity.Warning, "Fix floating point number comparison", token =>
     {
         SyntaxNode newRoot;
         ExpressionSyntax expr;
         var arguments = new SeparatedSyntaxList <ArgumentSyntax>();
         arguments = arguments.Add(SyntaxFactory.Argument(SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, node.Left, node.Right)));
         expr = SyntaxFactory.BinaryExpression(
             node.IsKind(SyntaxKind.EqualsExpression) ? SyntaxKind.LessThanExpression : SyntaxKind.GreaterThanExpression,
             SyntaxFactory.InvocationExpression(
                 SyntaxFactory.MemberAccessExpression(
                     SyntaxKind.SimpleMemberAccessExpression,
                     SyntaxFactory.ParseTypeName("System.Math").WithAdditionalAnnotations(Microsoft.CodeAnalysis.Simplification.Simplifier.Annotation),
                     SyntaxFactory.IdentifierName("Abs")
                     ),
                 SyntaxFactory.ArgumentList(
                     arguments
                     )
                 ),
             SyntaxFactory.IdentifierName(SyntaxFactory.Identifier("EPSILON").WithAdditionalAnnotations(RenameAnnotation.Create()))
             );
         expr = expr.WithAdditionalAnnotations(Formatter.Annotation);
         newRoot = root.ReplaceNode((SyntaxNode)node, expr);
         return Task.FromResult(document.WithSyntaxRoot(newRoot));
     }));
 }
Пример #13
0
        private static void InsertNewVariableDeclaration(
            BinaryExpressionSyntax asExpression,
            SyntaxToken newIdentifier,
            SyntaxNode nodeLocation,
            DocumentEditor editor)
        {
            var newEqualsClause = SyntaxFactory.EqualsValueClause(asExpression);
            var newDeclarator   = SyntaxFactory.VariableDeclarator(newIdentifier.WithAdditionalAnnotations(RenameAnnotation.Create()), null, newEqualsClause);
            var newDeclaration  = SyntaxFactory.VariableDeclaration(SyntaxFactory.IdentifierName("var"), SyntaxFactory.SeparatedList(new[] { newDeclarator }));
            var newLocal        = SyntaxFactory.LocalDeclarationStatement(newDeclaration).WithAdditionalAnnotations(Formatter.Annotation);

            // If we are in an else statement, we have to add the new local before the initial if-statement. e.g.:
            //   if(o is int) { }
            //   else if(o is string) { }
            // If we are currently handling the second statement, we have to add the local before the first
            // However because there can be multiple chained if-else statements, we have to go up to the first one and add it there.
            nodeLocation = GetOuterIfStatement(nodeLocation);

            editor.InsertBefore(nodeLocation, newLocal);
        }
Пример #14
0
        protected void IntroduceCollectionStatement(
            SemanticModel model, ForEachInfo foreachInfo, SyntaxEditor editor,
            SyntaxNode type, SyntaxNode foreachCollectionExpression, SyntaxNode collectionVariable)
        {
            if (!foreachInfo.RequireCollectionStatement)
            {
                return;
            }

            // TODO: refactor introduce variable refactoring to real service and use that service here to introduce local variable
            var generator = editor.Generator;

            // attach rename annotation to control variable
            var collectionVariableToken = generator.Identifier(collectionVariable.ToString()).WithAdditionalAnnotations(RenameAnnotation.Create());

            // this expression is from user code. don't simplify this.
            var expression          = foreachCollectionExpression.WithoutAnnotations(SimplificationHelpers.DontSimplifyAnnotation);
            var collectionStatement = generator.LocalDeclarationStatement(
                type,
                collectionVariableToken,
                foreachInfo.RequireExplicitCastInterface
                    ? generator.CastExpression(foreachInfo.ExplicitCastInterface, expression) : expression);

            // attach trivia to right place
            collectionStatement = collectionStatement.WithLeadingTrivia(foreachInfo.ForEachStatement.GetFirstToken().LeadingTrivia);

            editor.InsertBefore(foreachInfo.ForEachStatement, collectionStatement);
        }
        protected override Task <Document> IntroduceQueryLocalAsync(
            SemanticDocument document,
            ExpressionSyntax expression,
            bool allOccurrences,
            CancellationToken cancellationToken
            )
        {
            var oldOutermostQuery = expression
                                    .GetAncestorsOrThis <QueryExpressionSyntax>()
                                    .LastOrDefault();

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

            var letClause = SyntaxFactory
                            .LetClause(
                newLocalNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()),
                expression
                )
                            .WithAdditionalAnnotations(Formatter.Annotation);

            var matches = FindMatches(
                document,
                expression,
                document,
                oldOutermostQuery,
                allOccurrences,
                cancellationToken
                );
            var innermostClauses = new HashSet <SyntaxNode>(
                matches.Select(
                    expr => expr.GetAncestorsOrThis <SyntaxNode>().First(IsAnyQueryClause)
                    )
                );

            if (innermostClauses.Count == 1)
            {
                // If there was only one match, or all the matches came from the same
                // statement, then we want to place the declaration right above that
                // statement. Note: we special case this because the statement we are going
                // to go above might not be in a block and we may have to generate it
                return(Task.FromResult(
                           IntroduceQueryLocalForSingleOccurrence(
                               document,
                               expression,
                               newLocalName,
                               letClause,
                               allOccurrences,
                               cancellationToken
                               )
                           ));
            }

            var oldInnerMostCommonQuery = matches.FindInnermostCommonNode <QueryExpressionSyntax>();
            var newInnerMostQuery       = Rewrite(
                document,
                expression,
                newLocalName,
                document,
                oldInnerMostCommonQuery,
                allOccurrences,
                cancellationToken
                );

            var allAffectedClauses = new HashSet <SyntaxNode>(
                matches.SelectMany(
                    expr => expr.GetAncestorsOrThis <SyntaxNode>().Where(IsAnyQueryClause)
                    )
                );

            var oldClauses = oldInnerMostCommonQuery.GetAllClauses();
            var newClauses = newInnerMostQuery.GetAllClauses();

            var firstClauseAffectedInQuery = oldClauses.First(allAffectedClauses.Contains);
            var firstClauseAffectedIndex   = oldClauses.IndexOf(firstClauseAffectedInQuery);

            var finalClauses = newClauses
                               .Take(firstClauseAffectedIndex)
                               .Concat(letClause)
                               .Concat(newClauses.Skip(firstClauseAffectedIndex))
                               .ToList();

            var finalQuery = newInnerMostQuery.WithAllClauses(finalClauses);
            var newRoot    = document.Root.ReplaceNode(oldInnerMostCommonQuery, finalQuery);

            return(Task.FromResult(document.Document.WithSyntaxRoot(newRoot)));
        }
        protected override async Task <Document> IntroduceLocalAsync(
            SemanticDocument document,
            ExpressionSyntax expression,
            bool allOccurrences,
            bool isConstant,
            CancellationToken cancellationToken)
        {
            var newLocalNameToken = GenerateUniqueLocalName(document, expression, isConstant, cancellationToken);
            var newLocalName      = SyntaxFactory.IdentifierName(newLocalNameToken);

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

            var options = await document.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var declarationStatement = SyntaxFactory.LocalDeclarationStatement(
                modifiers,
                SyntaxFactory.VariableDeclaration(
                    this.GetTypeSyntax(document, options, expression, isConstant, 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(IntroduceLocalDeclarationIntoLambda(
                           document, expression, newLocalName, declarationStatement, parentLambda, allOccurrences, cancellationToken));
            }
            else if (IsInExpressionBodiedMember(expression))
            {
                return(RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
                           document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken));
            }
            else
            {
                return(await IntroduceLocalDeclarationIntoBlockAsync(
                           document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(false));
            }
        }
        protected override async Task <Document> IntroduceLocalAsync(
            SemanticDocument document,
            ExpressionSyntax expression,
            bool allOccurrences,
            bool isConstant,
            CancellationToken cancellationToken)
        {
            var containerToGenerateInto = expression.Ancestors().FirstOrDefault(s =>
                                                                                s is BlockSyntax || s is ArrowExpressionClauseSyntax || s is LambdaExpressionSyntax);

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

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

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

            // If we're inserting into a multi-line parent, then add a newline after the local-var
            // we're adding.  That way we don't end up having it and the starting statement be on
            // the same line (which will cause indentation to be computed incorrectly).
            var text = await document.Document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            if (!text.AreOnSameLine(containerToGenerateInto.GetFirstToken(), containerToGenerateInto.GetLastToken()))
            {
                declarationStatement = declarationStatement.WithAppendedTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed);
            }

            switch (containerToGenerateInto)
            {
            case BlockSyntax block:
                return(await IntroduceLocalDeclarationIntoBlockAsync(
                           document, block, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(false));

            case ArrowExpressionClauseSyntax arrowExpression:
                // this will be null for expression-bodied properties & indexer (not for individual getters & setters, those do have a symbol),
                // both of which are a shorthand for the getter and always return a value
                var method = document.SemanticModel.GetDeclaredSymbol(arrowExpression.Parent, cancellationToken) as IMethodSymbol;
                var createReturnStatement = !method?.ReturnsVoid ?? true;

                return(RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
                           document, arrowExpression, expression, newLocalName,
                           declarationStatement, allOccurrences, createReturnStatement, cancellationToken));

            case LambdaExpressionSyntax lambda:
                return(IntroduceLocalDeclarationIntoLambda(
                           document, lambda, expression, newLocalName, declarationStatement,
                           allOccurrences, cancellationToken));
            }

            throw new InvalidOperationException();
        }
Пример #18
0
        private static InvocationExpressionSyntax Merge(
            InvocationExpressionSyntax outerMostInvocation,
            MemberAccessExpressionSyntax innerMostWhereAccess,
            List <ExpressionSyntax> whereArguments,
            SemanticModel semanticModel)
        {
            var firstArgument = whereArguments[0];

            string               parameterName;
            ParameterSyntax      firstParameter;
            IdentifierNameSyntax firstParameterIdentifier;
            ExpressionSyntax     filterExpression;

            if (firstArgument.IsKind(SyntaxKind.SimpleLambdaExpression))
            {
                var lambda = (SimpleLambdaExpressionSyntax)firstArgument;
                firstParameter           = lambda.Parameter;
                parameterName            = firstParameter.Identifier.Text;
                firstParameterIdentifier = SyntaxFactory.IdentifierName(firstParameter.Identifier);
                filterExpression         = MakeExpressionFromLambdaBody(lambda.Body);
            }
            else
            {
                parameterName = NameHelper.GetLambdaParameterName(
                    outerMostInvocation.SpanStart,
                    semanticModel);

                var parameterIdentifier = SyntaxFactory
                                          .Identifier(parameterName)
                                          .WithAdditionalAnnotations(RenameAnnotation.Create());

                firstParameter = SyntaxFactory.Parameter(parameterIdentifier);

                firstParameterIdentifier = SyntaxFactory.IdentifierName(parameterIdentifier);

                filterExpression = ExtendedSyntaxFactory.MakeInvocation(
                    firstArgument,
                    firstParameterIdentifier);
            }


            for (int i = 1; i < whereArguments.Count; ++i)
            {
                ExpressionSyntax andOperand;

                if (whereArguments[i].IsKind(SyntaxKind.SimpleLambdaExpression))
                {
                    var currentLambda        = (SimpleLambdaExpressionSyntax)whereArguments[i];
                    var currentParameter     = currentLambda.Parameter;
                    var currentParameterName = currentParameter.Identifier.Text;

                    if (currentParameterName != parameterName)
                    {
                        var parameterSymbol = semanticModel.GetDeclaredSymbol(currentParameter);

                        var substituteRewriter = new SubstituteRewriter(
                            currentParameterName,
                            parameterSymbol,
                            semanticModel,
                            firstParameterIdentifier);

                        var newBody = (CSharpSyntaxNode)currentLambda.Body.Accept(substituteRewriter);

                        andOperand = MakeExpressionFromLambdaBody(newBody);
                    }
                    else
                    {
                        andOperand = MakeExpressionFromLambdaBody(currentLambda.Body);
                    }
                }
                else
                {
                    andOperand = ExtendedSyntaxFactory.MakeInvocation(
                        whereArguments[i],
                        firstParameterIdentifier);
                }

                filterExpression = SyntaxFactory.BinaryExpression(
                    SyntaxKind.LogicalAndExpression,
                    filterExpression,
                    andOperand);
            }

            var newLambda = SyntaxFactory.SimpleLambdaExpression(
                firstParameter,
                filterExpression);

            var newInvocation = ExtendedSyntaxFactory.MakeInvocation(
                innerMostWhereAccess,
                newLambda);

            return(newInvocation);
        }
Пример #19
0
        protected override async Task <Document> IntroduceLocalAsync(
            SemanticDocument document,
            ExpressionSyntax expression,
            bool allOccurrences,
            bool isConstant,
            CancellationToken cancellationToken)
        {
            var containerToGenerateInto = GetContainerToGenerateInto(document, expression, cancellationToken);

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

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

            var options = await document.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

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

            switch (containerToGenerateInto)
            {
            case BlockSyntax block:
                return(await IntroduceLocalDeclarationIntoBlockAsync(
                           document, block, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(false));

            case ArrowExpressionClauseSyntax arrowExpression:
                return(RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
                           document, arrowExpression, expression, newLocalName,
                           declarationStatement, allOccurrences, cancellationToken));

            case LambdaExpressionSyntax lambda:
                return(IntroduceLocalDeclarationIntoLambda(
                           document, lambda, expression, newLocalName, declarationStatement,
                           allOccurrences, cancellationToken));
            }

            throw new InvalidOperationException();
        }
Пример #20
0

        
        static ForEachStatementSyntax BuildForeach(ExpressionSyntax iterateOver)
        {
            var itemVariable = SyntaxFactory.Identifier("item").WithAdditionalAnnotations(RenameAnnotation.Create());

            return(SyntaxFactory.ForEachStatement(SyntaxFactory.ParseTypeName("var"), itemVariable, iterateOver, SyntaxFactory.Block())
                   .WithAdditionalAnnotations(Formatter.Annotation));
        }