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