public static IEnumerable <IFieldSymbol> CreateFieldsForParameters( this SyntaxGenerator factory, IList <IParameterSymbol> parameters, IDictionary <string, string> parameterToNewFieldMap) { foreach (var parameter in parameters) { var refKind = parameter.RefKind; var parameterType = parameter.Type; var parameterName = parameter.Name; if (refKind != RefKind.Out) { // For non-out parameters, create a field and assign the parameter to it. // TODO: I'm not sure that's what we really want for ref parameters. string fieldName; if (TryGetValue(parameterToNewFieldMap, parameterName, out fieldName)) { yield return(CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: null, accessibility: Accessibility.Private, modifiers: default(DeclarationModifiers), type: parameterType, name: parameterToNewFieldMap[parameterName])); } } } }
private static IFieldSymbol GetBackingField(IPropertySymbol property) { var field = property.GetBackingFieldIfAny(); if (field == null) { return(null); } // If the field is something can be referenced with the name it has, then just use // it as the backing field we'll generate. This is the case in VB where the backing // field can be referenced as is. if (field.CanBeReferencedByName) { return(field); } // Otherwise, generate a good name for the backing field we're generating. This is // the case for C# where we have mangled names for the backing field and need something // actually usable in code. var uniqueName = NameGenerator.GenerateUniqueName( property.Name.ToCamelCase(), n => !property.ContainingType.GetMembers(n).Any()); return(CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: default(ImmutableArray <AttributeData>), accessibility: field.DeclaredAccessibility, modifiers: DeclarationModifiers.From(field), type: field.Type, name: uniqueName)); }
protected override async Task <Document> GetChangedDocumentAsync(CancellationToken cancellationToken) { var languageServices = _document.Project.Solution.Workspace.Services.GetLanguageServices(_state.TypeToGenerateIn.Language); var codeGenerator = languageServices.GetService <ICodeGenerationService>(); var semanticFacts = languageServices.GetService <ISemanticFactsService>(); var value = semanticFacts.LastEnumValueHasInitializer(_state.TypeToGenerateIn) ? EnumValueUtilities.GetNextEnumValue(_state.TypeToGenerateIn, cancellationToken) : null; var syntaxTree = await _document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var result = await codeGenerator.AddFieldAsync( _document.Project.Solution, _state.TypeToGenerateIn, CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: default(ImmutableArray <AttributeData>), accessibility: Accessibility.Public, modifiers: default(DeclarationModifiers), type: _state.TypeToGenerateIn, name: _state.IdentifierToken.ValueText, hasConstantValue: value != null, constantValue: value), new CodeGenerationOptions(contextLocation : _state.IdentifierToken.GetLocation()), cancellationToken) .ConfigureAwait(false); return(result); }
internal static async Task TestAddFieldAsync( string initial, string expected, Func<SemanticModel, ITypeSymbol> type = null, string name = "F", Accessibility accessibility = Accessibility.Public, Editing.DeclarationModifiers modifiers = default(Editing.DeclarationModifiers), CodeGenerationOptions codeGenerationOptions = null, bool hasConstantValue = false, object constantValue = null, bool addToCompilationUnit = false) { using (var context = await TestContext.CreateAsync(initial, expected)) { var typeSymbol = type != null ? type(context.SemanticModel) : null; var field = CodeGenerationSymbolFactory.CreateFieldSymbol( default(ImmutableArray<AttributeData>), accessibility, modifiers, typeSymbol, name, hasConstantValue, constantValue); if (!addToCompilationUnit) { context.Result = await context.Service.AddFieldAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), field, codeGenerationOptions); } else { var newRoot = context.Service.AddField(await context.Document.GetSyntaxRootAsync(), field, codeGenerationOptions); context.Result = context.Document.WithSyntaxRoot(newRoot); } } }
protected override async Task <Document> GetChangedDocumentAsync(CancellationToken cancellationToken) { var syntaxTree = await _document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var generateUnsafe = _state.TypeMemberType.IsUnsafe() && !_state.IsContainedInUnsafeType; if (_generateProperty) { var getAccessor = CodeGenerationSymbolFactory.CreateAccessorSymbol( attributes: null, accessibility: DetermineMaximalAccessibility(_state), statements: null); var setAccessor = _isReadonly ? null : CodeGenerationSymbolFactory.CreateAccessorSymbol( attributes: null, accessibility: DetermineMinimalAccessibility(_state), statements: null); var result = await CodeGenerator.AddPropertyDeclarationAsync( _document.Project.Solution, _state.TypeToGenerateIn, CodeGenerationSymbolFactory.CreatePropertySymbol( attributes: null, accessibility: DetermineMaximalAccessibility(_state), modifiers: new DeclarationModifiers(isStatic: _state.IsStatic, isUnsafe: generateUnsafe), type: _state.TypeMemberType, explicitInterfaceSymbol: null, name: _state.IdentifierToken.ValueText, isIndexer: _state.IsIndexer, parameters: _state.Parameters, getMethod: getAccessor, setMethod: setAccessor), new CodeGenerationOptions(contextLocation : _state.IdentifierToken.GetLocation()), cancellationToken : cancellationToken) .ConfigureAwait(false); return(result); } else { var result = await CodeGenerator.AddFieldDeclarationAsync( _document.Project.Solution, _state.TypeToGenerateIn, CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: null, accessibility: DetermineMinimalAccessibility(_state), modifiers: _isConstant ? new DeclarationModifiers(isConst: true, isUnsafe: generateUnsafe) : new DeclarationModifiers(isStatic: _state.IsStatic, isReadOnly: _isReadonly, isUnsafe: generateUnsafe), type: _state.TypeMemberType, name: _state.IdentifierToken.ValueText), new CodeGenerationOptions(contextLocation : _state.IdentifierToken.GetLocation()), cancellationToken : cancellationToken) .ConfigureAwait(false); return(result); } }
protected override async Task <Document> GetChangedDocumentAsync(CancellationToken cancellationToken) { var generateUnsafe = _state.TypeMemberType.IsUnsafe() && !_state.IsContainedInUnsafeType; if (_generateProperty) { var getAccessor = CodeGenerationSymbolFactory.CreateAccessorSymbol( attributes: null, accessibility: DetermineMaximalAccessibility(_state), statements: null); var setAccessor = _isReadonly ? null : CodeGenerationSymbolFactory.CreateAccessorSymbol( attributes: null, accessibility: DetermineMinimalAccessibility(_state), statements: null); var result = await ICSharpCode.NRefactory6.CSharp.CodeGenerator.AddPropertyDeclarationAsync( _document.Project.Solution, _state.TypeToGenerateIn, CodeGenerationSymbolFactory.CreatePropertySymbol( attributes: null, accessibility: DetermineMaximalAccessibility(_state), modifiers: DeclarationModifiers.None.WithIsStatic(_state.IsStatic).WithIsUnsafe(generateUnsafe), type: _state.TypeMemberType, explicitInterfaceSymbol: null, name: _state.IdentifierToken.ValueText, isIndexer: _state.IsIndexer, parameters: _state.Parameters, getMethod: getAccessor, setMethod: setAccessor), new CodeGenerationOptions(contextLocation : _state.IdentifierToken.GetLocation(), generateDefaultAccessibility : false), cancellationToken : cancellationToken) .ConfigureAwait(false); return(await AnnotateInsertionMode(_document.Project.Solution.GetDocument(result.Id), result)); } else { var result = await ICSharpCode.NRefactory6.CSharp.CodeGenerator.AddFieldDeclarationAsync( _document.Project.Solution, _state.TypeToGenerateIn, CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: null, accessibility: DetermineMinimalAccessibility(_state), modifiers: _isConstant ? DeclarationModifiers.None.WithIsConst(true).WithIsUnsafe(generateUnsafe) : DeclarationModifiers.None.WithIsStatic(_state.IsStatic).WithIsReadOnly(_isReadonly).WithIsUnsafe(generateUnsafe), type: _state.TypeMemberType, name: _state.IdentifierToken.ValueText), new CodeGenerationOptions(contextLocation : _state.IdentifierToken.GetLocation(), generateDefaultAccessibility : false), cancellationToken : cancellationToken) .ConfigureAwait(false); return(await AnnotateInsertionMode(_document.Project.Solution.GetDocument(result.Id), result)); } }
private IList <ISymbol> GetNewFieldsForRuleNameMultipleZero(INamedTypeSymbol enumType, IEnumerable <IFieldSymbol> zeroValuedFields, SyntaxGenerator syntaxFactoryService) { // Diagnostic: Remove all members that have the value zero from '{0}' except for one member that is named 'None'. // Fix: Remove all members that have the value zero except for one member that is named 'None'. bool needsNewZeroValuedNoneField = true; var set = zeroValuedFields.ToSet(); bool makeNextFieldExplicit = false; var newFields = new List <ISymbol>(); foreach (IFieldSymbol field in enumType.GetMembers().Where(m => m.Kind == SymbolKind.Field)) { var isZeroValued = set.Contains(field); var isZeroValuedNamedNone = isZeroValued && CA1008DiagnosticAnalyzer.IsMemberNamedNone(field); if (!isZeroValued || isZeroValuedNamedNone) { var newField = field; if (makeNextFieldExplicit) { newField = GetExplicitlyAssignedField(field, syntaxFactoryService); makeNextFieldExplicit = false; } newFields.Add(newField); if (isZeroValuedNamedNone) { needsNewZeroValuedNoneField = false; } } else { makeNextFieldExplicit = true; } } if (needsNewZeroValuedNoneField) { var firstZeroValuedField = zeroValuedFields.First(); var constantValueExpression = syntaxFactoryService.LiteralExpression(firstZeroValuedField.ConstantValue); var newInitializer = CreateConstantValueInitializer(constantValueExpression); var newField = CodeGenerationSymbolFactory.CreateFieldSymbol(firstZeroValuedField.GetAttributes(), firstZeroValuedField.DeclaredAccessibility, firstZeroValuedField.GetSymbolModifiers(), firstZeroValuedField.Type, "None", firstZeroValuedField.HasConstantValue, firstZeroValuedField.ConstantValue, newInitializer); newFields.Insert(0, newField); } return(newFields); }
protected override Task <Document> GetChangedDocumentAsync(CancellationToken cancellationToken) { var solution = _document.Project.Solution; var syntaxTree = _document.SyntaxTree; var generateUnsafe = _state.TypeMemberType.IsUnsafe() && !_state.IsContainedInUnsafeType; var otions = new CodeGenerationOptions( afterThisLocation: _state.AfterThisLocation, beforeThisLocation: _state.BeforeThisLocation, contextLocation: _state.IdentifierToken.GetLocation()); if (_generateProperty) { var getAccessor = CreateAccessor(DetermineMaximalAccessibility(_state), cancellationToken); var setAccessor = _isReadonly || _returnsByRef ? null : CreateAccessor(DetermineMinimalAccessibility(_state), cancellationToken); var propertySymbol = CodeGenerationSymbolFactory.CreatePropertySymbol( attributes: default(ImmutableArray <AttributeData>), accessibility: DetermineMaximalAccessibility(_state), modifiers: new DeclarationModifiers(isStatic: _state.IsStatic, isUnsafe: generateUnsafe), type: _state.TypeMemberType, returnsByRef: _returnsByRef, explicitInterfaceSymbol: null, name: _state.IdentifierToken.ValueText, isIndexer: _state.IsIndexer, parameters: _state.Parameters, getMethod: getAccessor, setMethod: setAccessor); return(CodeGenerator.AddPropertyDeclarationAsync( solution, _state.TypeToGenerateIn, propertySymbol, otions, cancellationToken)); } else { var fieldSymbol = CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: default(ImmutableArray <AttributeData>), accessibility: DetermineMinimalAccessibility(_state), modifiers: _isConstant ? new DeclarationModifiers(isConst: true, isUnsafe: generateUnsafe) : new DeclarationModifiers(isStatic: _state.IsStatic, isReadOnly: _isReadonly, isUnsafe: generateUnsafe), type: _state.TypeMemberType, name: _state.IdentifierToken.ValueText); return(CodeGenerator.AddFieldDeclarationAsync( solution, _state.TypeToGenerateIn, fieldSymbol, otions, cancellationToken)); } }
protected SyntaxNode CreateFieldDeclaration(SyntaxNode containerNode, string name, EnvDTE.vsCMAccess access, ITypeSymbol type) { var destination = CodeModelService.GetDestination(containerNode); var newFieldSymbol = CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: default(ImmutableArray <AttributeData>), accessibility: CodeModelService.GetAccessibility(access, SymbolKind.Field, destination), modifiers: new DeclarationModifiers(isWithEvents: CodeModelService.GetWithEvents(access)), type: type, name: name); return(CodeGenerationService.CreateFieldDeclaration( newFieldSymbol, destination, options: GetCodeGenerationOptions(access, containerNode.SyntaxTree.Options))); }
private IFieldSymbol GetExplicitlyAssignedField(IFieldSymbol originalField, SyntaxGenerator syntaxFactoryService) { var originalInitializer = GetFieldInitializer(originalField); if (originalInitializer != null || !originalField.HasConstantValue) { return(originalField); } var constantValueExpression = syntaxFactoryService.LiteralExpression(originalField.ConstantValue); var newInitializer = CreateConstantValueInitializer(constantValueExpression); return(CodeGenerationSymbolFactory.CreateFieldSymbol(originalField.GetAttributes(), originalField.DeclaredAccessibility, originalField.GetSymbolModifiers(), originalField.Type, originalField.Name, originalField.HasConstantValue, originalField.ConstantValue, newInitializer)); }
private static TypeDeclarationSyntax WithBackingFields(this TypeDeclarationSyntax node, IEnumerable <ExpandablePropertyInfo> properties, Workspace workspace) { foreach (var property in properties) { // When the getter doesn't have a body (i.e. an auto-prop), we'll need to generate a new field. var newField = CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: null, accessibility: Microsoft.CodeAnalysis.Accessibility.Private, modifiers: new SymbolModifiers(), type: property.Type, name: property.BackingFieldName); node = CodeGenerator.AddFieldDeclaration(node, newField, workspace); } return(node); }
private IFieldSymbol CreateField( IParameterSymbol parameter, ImmutableArray <NamingRule> rules, List <string> parameterNameParts) { foreach (var rule in rules) { if (rule.SymbolSpecification.AppliesTo(SymbolKind.Field, Accessibility.Private)) { var uniqueName = GenerateUniqueName(parameter, parameterNameParts, rule); return(CodeGenerationSymbolFactory.CreateFieldSymbol( default(ImmutableArray <AttributeData>), Accessibility.Private, DeclarationModifiers.ReadOnly, parameter.Type, uniqueName)); } } // We place a special rule in s_builtInRules that matches all fields. So we should // always find a matching rule. throw ExceptionUtilities.Unreachable; }
private IList <ISymbol> GetNewFieldsForRuleNameNoZeroValue(INamedTypeSymbol enumType, SyntaxGenerator syntaxFactoryService) { // Diagnostic: Add a member to '{0}' that has a value of zero with a suggested name of 'None'. // Fix: Add a zero-valued member 'None' to enum. var newFields = new List <ISymbol>(); var constantValueExpression = syntaxFactoryService.LiteralExpression(0); var newInitializer = CreateConstantValueInitializer(constantValueExpression); var newField = CodeGenerationSymbolFactory.CreateFieldSymbol(SpecializedCollections.EmptyList <AttributeData>(), Accessibility.Public, default(SymbolModifiers), enumType.EnumUnderlyingType, "None", true, 0, newInitializer); newFields.Add(newField); foreach (var member in enumType.GetMembers()) { if (!CA1008DiagnosticAnalyzer.IsMemberNamedNone(member)) { newFields.Add(member); } } return(newFields); }
protected override async Task <Document> GetChangedDocumentAsync(CancellationToken cancellationToken) { var value = _state.TypeToGenerateIn.LastEnumValueHasInitializer() ? EnumValueUtilities.GetNextEnumValue(_state.TypeToGenerateIn, cancellationToken) : null; var result = await new CSharpCodeGenerationService(_document.Project.Solution.Workspace).AddFieldAsync( _document.Project.Solution, _state.TypeToGenerateIn, CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: null, accessibility: Accessibility.Public, modifiers: default(DeclarationModifiers), type: _state.TypeToGenerateIn, name: _state.IdentifierToken.ValueText, hasConstantValue: value != null, constantValue: value), new CodeGenerationOptions(contextLocation: _state.IdentifierToken.GetLocation(), generateDefaultAccessibility: false), cancellationToken) .ConfigureAwait(false); return(result); }
private IList <ISymbol> GetNewFieldsForRuleNameRename(INamedTypeSymbol enumType, IFieldSymbol zeroValuedField) { // Diagnostic: In enum '{0}', change the name of '{1}' to 'None'. // Fix: Rename zero-valued enum field to 'None'. var newFields = new List <ISymbol>(); foreach (IFieldSymbol field in enumType.GetMembers().Where(m => m.Kind == SymbolKind.Field)) { if (field != zeroValuedField) { newFields.Add(field); } else { var newInitializer = GetFieldInitializer(field); var newField = CodeGenerationSymbolFactory.CreateFieldSymbol(field.GetAttributes(), field.DeclaredAccessibility, field.GetSymbolModifiers(), field.Type, "None", field.HasConstantValue, field.ConstantValue, newInitializer); newFields.Add(newField); } } return(newFields); }
internal static void TestAddField( string initial, string expected, Func <SemanticModel, ITypeSymbol> type = null, string name = "F", Accessibility accessibility = Accessibility.Public, DeclarationModifiers modifiers = default(DeclarationModifiers), CodeGenerationOptions codeGenerationOptions = default(CodeGenerationOptions), bool compareTokens = true, bool hasConstantValue = false, object constantValue = null, bool addToCompilationUnit = false) { using (var context = new TestContext(initial, expected, compareTokens)) { var typeSymbol = type != null?type(context.SemanticModel) : null; var field = CodeGenerationSymbolFactory.CreateFieldSymbol( null, accessibility, modifiers, typeSymbol, name, hasConstantValue, constantValue); if (!addToCompilationUnit) { context.Result = context.Service.AddFieldAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), field, codeGenerationOptions).Result; } else { var newRoot = context.Service.AddField(context.Document.GetSyntaxRootAsync().Result, field, codeGenerationOptions); context.Result = context.Document.WithSyntaxRoot(newRoot); } } }
internal static Func <SemanticModel, ISymbol> CreateField(Accessibility accessibility, DeclarationModifiers modifiers, Type type, string name) { return(s => CodeGenerationSymbolFactory.CreateFieldSymbol( null, accessibility, modifiers, GetTypeSymbol(type)(s), name)); }
internal static Func <SemanticModel, ISymbol> CreateField(Accessibility accessibility, DeclarationModifiers modifiers, Type type, string name) { return(s => CodeGenerationSymbolFactory.CreateFieldSymbol( default(ImmutableArray <AttributeData>), accessibility, modifiers, GetTypeSymbol(type)(s), name)); }
private static Func <SemanticModel, ISymbol> CreateEnumField(string name, object value) { return(s => CodeGenerationSymbolFactory.CreateFieldSymbol( null, Accessibility.Public, new DeclarationModifiers(), GetTypeSymbol(typeof(int))(s), name, value != null, value)); }
protected async override Task <SyntaxNode> RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var declarator = root.GetAnnotatedNodes <VariableDeclaratorSyntax>(declarationAnnotation).FirstOrDefault(); // There may be no field to rewrite if this document is part of a set of linked files // and the declaration is not conditionally compiled in this document's project. if (declarator == null) { return(root); } var tempAnnotation = new SyntaxAnnotation(); var escapedName = originalFieldName.EscapeIdentifier(); var newIdentifier = SyntaxFactory.Identifier( leading: SyntaxTriviaList.Create(SyntaxFactory.ElasticMarker), contextualKind: SyntaxKind.IdentifierName, text: escapedName, valueText: originalFieldName, trailing: SyntaxTriviaList.Create(SyntaxFactory.ElasticMarker)) .WithTrailingTrivia(declarator.Identifier.TrailingTrivia) .WithLeadingTrivia(declarator.Identifier.LeadingTrivia); var updatedDeclarator = declarator.WithIdentifier(newIdentifier).WithAdditionalAnnotations(tempAnnotation); root = root.ReplaceNode(declarator, updatedDeclarator); document = document.WithSyntaxRoot(root); var declaration = root.GetAnnotatedNodes <SyntaxNode>(tempAnnotation).First().Parent as VariableDeclarationSyntax; if (declaration.Variables.Count == 1) { var fieldSyntax = declaration.Parent as FieldDeclarationSyntax; var modifierKinds = new[] { SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.InternalKeyword, SyntaxKind.PublicKeyword }; if (makePrivate) { var modifiers = SpecializedCollections.SingletonEnumerable(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)) .Concat(fieldSyntax.Modifiers.Where(m => !modifierKinds.Contains(m.Kind()))); root = root.ReplaceNode(fieldSyntax, fieldSyntax.WithModifiers( SyntaxFactory.TokenList(modifiers)) .WithAdditionalAnnotations(Formatter.Annotation) .WithLeadingTrivia(fieldSyntax.GetLeadingTrivia()) .WithTrailingTrivia(fieldSyntax.GetTrailingTrivia())); } } else if (declaration.Variables.Count > 1 && makePrivate) { document = document.WithSyntaxRoot(root); var codeGenService = document.GetLanguageService <ICodeGenerationService>(); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); declarator = root.GetAnnotatedNodes <VariableDeclaratorSyntax>(tempAnnotation).First(); declaration = declarator.Parent as VariableDeclarationSyntax; var field = semanticModel.GetDeclaredSymbol(declarator, cancellationToken) as IFieldSymbol; var fieldToAdd = declarationAnnotation.AddAnnotationToSymbol(CodeGenerationSymbolFactory.CreateFieldSymbol( field.GetAttributes(), Accessibility.Private, new DeclarationModifiers(isStatic: field.IsStatic, isReadOnly: field.IsReadOnly, isConst: field.IsConst), field.Type, field.Name, field.HasConstantValue, field.ConstantValue, declarator.Initializer)); var withField = await codeGenService.AddFieldAsync(document.Project.Solution, field.ContainingType, fieldToAdd, new CodeGenerationOptions(), cancellationToken).ConfigureAwait(false); root = await withField.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); declarator = root.GetAnnotatedNodes <VariableDeclaratorSyntax>(tempAnnotation).First(); declaration = declarator.Parent as VariableDeclarationSyntax; return(root.RemoveNode(declarator, SyntaxRemoveOptions.KeepNoTrivia)); } return(root); }
public void TestTrackNodesWithDocument() { var pid = ProjectId.CreateNewId(); var did = DocumentId.CreateNewId(pid); var sourceText = @"public class C { void M() { } }"; var sol = new CustomWorkspace().CurrentSolution .AddProject(pid, "proj", "proj", LanguageNames.CSharp) .AddDocument(did, "doc", sourceText); var doc = sol.GetDocument(did); // find initial nodes of interest var root = doc.GetSyntaxRootAsync().Result; var classDecl = root.DescendantNodes().OfType <ClassDeclarationSyntax>().First(); var methodDecl = classDecl.DescendantNodes().OfType <MethodDeclarationSyntax>().First(); // track these nodes var trackedRoot = root.TrackNodes(classDecl, methodDecl); // use some fancy document centric rewrites var comp = doc.Project.GetCompilationAsync().Result; var cgenField = CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: null, accessibility: Accessibility.Private, modifiers: new SymbolModifiers(), type: comp.GetSpecialType(SpecialType.System_Int32), name: "X"); var currentClassDecl = trackedRoot.GetCurrentNodes(classDecl).First(); var classDeclWithField = Formatter.Format( CodeGenerator.AddFieldDeclaration(currentClassDecl, cgenField, sol.Workspace), sol.Workspace); // we can find related bits even from sub-tree fragments var latestMethod = classDeclWithField.GetCurrentNodes(methodDecl).First(); Assert.NotNull(latestMethod); Assert.NotEqual(latestMethod, methodDecl); trackedRoot = trackedRoot.ReplaceNode(currentClassDecl, classDeclWithField); // put back into document (branch solution, etc) doc = doc.WithSyntaxRoot(trackedRoot); // re-get root of new document var root2 = doc.GetSyntaxRootAsync().Result; Assert.NotEqual(trackedRoot, root2); // we can still find the tracked node in the new document var finalClassDecl = root2.GetCurrentNodes(classDecl).First(); Assert.Equal(@"public class C { private int X; void M() { } }", finalClassDecl.ToString()); // and other tracked nodes too var finalMethodDecl = root2.GetCurrentNodes(methodDecl).First(); Assert.NotNull(finalMethodDecl); Assert.NotEqual(finalMethodDecl, methodDecl); }