private RootTypeTransformationResult TransformType(ITypeAnalyzationResult rootTypeResult, INamespaceTransformationMetadata namespaceMetadata) { var anyMissingMembers = rootTypeResult.Conversion != TypeConversion.Partial && rootTypeResult.GetSelfAndDescendantsTypes() .Any(o => o.MethodsAndAccessors.Any(m => m.Missing)); var result = TransformType(rootTypeResult, namespaceMetadata, false); if (anyMissingMembers) { result.Partial = TransformType(rootTypeResult, namespaceMetadata, true); var transformedNode = result.Partial.Transformed; // We need to remove all directives while (transformedNode.ContainsDirectives) { transformedNode = transformedNode.RemoveNode(transformedNode.GetFirstDirective(), SyntaxRemoveOptions.KeepNoTrivia); } result.Partial.Transformed = transformedNode; result.OriginalModified = result.Partial.OriginalModified; } return(result); }
private RootTypeTransformationResult TransformType(ITypeAnalyzationResult rootTypeResult, INamespaceTransformationMetadata namespaceMetadata, bool onlyMissingMembers) { var rootTypeNode = rootTypeResult.Node; var startRootTypeSpan = rootTypeNode.SpanStart; var rootTransformResult = new RootTypeTransformationResult(rootTypeResult) { MemberNames = rootTypeResult.Symbol.MemberNames.ToImmutableHashSet() }; // We do this here because we want that the root node has span start equal to 0 rootTypeNode = rootTypeNode.WithAdditionalAnnotations(new SyntaxAnnotation(rootTransformResult.Annotation)); startRootTypeSpan -= rootTypeNode.SpanStart; // Before any modification we need to annotate nodes that will be transformed in order to find them later on. // We cannot rely on spans as they changes each time the node is modified. // We need to annotate also the ignored types to be later removed foreach (var typeResult in rootTypeResult.GetSelfAndDescendantsTypes()) { var typeSpanStart = typeResult.Node.SpanStart - startRootTypeSpan; var typeSpanLength = typeResult.Node.Span.Length; var typeNode = rootTypeNode.DescendantNodesAndSelf().OfType <TypeDeclarationSyntax>() .First(o => o.SpanStart == typeSpanStart && o.Span.Length == typeSpanLength); var leadingWhitespace = typeNode.GetLeadingWhitespace(); TypeTransformationResult transformResult; if (typeNode == rootTypeNode) { transformResult = rootTransformResult; transformResult.IndentTrivia = typeNode.GetIndent(leadingWhitespace, namespaceMetadata.LeadingWhitespaceTrivia); } else { transformResult = new TypeTransformationResult(typeResult) { MemberNames = typeResult.Symbol.MemberNames.ToImmutableHashSet(), IndentTrivia = typeNode.GetIndent(leadingWhitespace) }; rootTypeNode = rootTypeNode.ReplaceNode(typeNode, typeNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformResult.Annotation))); rootTransformResult.DescendantTransformedTypes.Add(transformResult); } transformResult.LeadingWhitespaceTrivia = leadingWhitespace; transformResult.EndOfLineTrivia = typeNode.GetEndOfLine(); if (typeResult.Conversion == TypeConversion.Ignore) { continue; // The ignored type shall be only annotated } // TypeReferences can be changes only if we create a new type if (typeResult.Conversion == TypeConversion.NewType || typeResult.Conversion == TypeConversion.Copy) { foreach (var typeReference in typeResult.TypeReferences.Where(o => o.TypeAnalyzationResult.Conversion == TypeConversion.NewType)) { var reference = typeReference.ReferenceLocation; var refSpanStart = reference.Location.SourceSpan.Start - startRootTypeSpan; var refSpanLength = reference.Location.SourceSpan.Length; var nameNode = rootTypeNode.GetSimpleName(refSpanStart, refSpanLength, typeReference.IsCref); var transformedNode = new TransformationResult(nameNode) { Transformed = nameNode.WithIdentifier(Identifier(nameNode.Identifier.ValueText + "Async").WithTriviaFrom(nameNode.Identifier)) }; transformResult.TransformedNodes.Add(transformedNode); rootTypeNode = rootTypeNode.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation))); } } foreach (var fieldResult in typeResult.Fields) { var fieldSpanStart = fieldResult.Node.SpanStart - startRootTypeSpan; var fieldSpanLength = fieldResult.Node.Span.Length; var fieldNode = rootTypeNode.DescendantNodes() .OfType <BaseFieldDeclarationSyntax>() .First(o => o.SpanStart == fieldSpanStart && o.Span.Length == fieldSpanLength); var transformedNode = new FieldTransformationResult(fieldResult); transformResult.TransformedFields.Add(transformedNode); rootTypeNode = rootTypeNode.ReplaceNode(fieldNode, fieldNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation))); } // Annotate and save an empty method transformation result foreach (var methodResult in typeResult.Methods /*.Where(o => o.Conversion != MethodConversion.Ignore)*/) { var methodSpanStart = methodResult.Node.SpanStart - startRootTypeSpan; var methodSpanLength = methodResult.Node.Span.Length; var methodNode = rootTypeNode.DescendantNodes() .OfType <MethodDeclarationSyntax>() .First(o => o.SpanStart == methodSpanStart && o.Span.Length == methodSpanLength); // Only create the transformation result for the method and transform the method later as the method may change // (a directive may be added to the method when removing type members) var transformedNode = new MethodTransformationResult(methodResult); transformResult.TransformedMethods.Add(transformedNode); rootTypeNode = rootTypeNode.ReplaceNode(methodNode, methodNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation))); // Annotate all locks inside the method before the transformations begins as will be easier to transform them if needed foreach (var lockData in methodResult.Locks) { var lockSpanStart = lockData.Node.SpanStart - startRootTypeSpan; var lockSpanLength = lockData.Node.Span.Length; var lockNode = rootTypeNode.DescendantNodes() .OfType <LockStatementSyntax>() .First(o => o.SpanStart == lockSpanStart && o.Span.Length == lockSpanLength); var lockTransformedNode = new LockTransformationResult(lockData); transformedNode.TransformedLocks.Add(lockTransformedNode); rootTypeNode = rootTypeNode.ReplaceNode(lockNode, lockNode.WithAdditionalAnnotations(new SyntaxAnnotation(lockTransformedNode.Annotation))); } } foreach (var methodResult in typeResult.SpecialMethods) { var methodSpanStart = methodResult.GetNode().SpanStart - startRootTypeSpan; var methodSpanLength = methodResult.GetNode().Span.Length; var methodNode = rootTypeNode.DescendantNodes() .OfType <BaseMethodDeclarationSyntax>() .First(o => o.SpanStart == methodSpanStart && o.Span.Length == methodSpanLength); var transformedNode = new FunctionTransformationResult(methodResult); transformResult.TransformedSpecialMethods.Add(transformedNode); rootTypeNode = rootTypeNode.ReplaceNode(methodNode, methodNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation))); } foreach (var propertyResult in typeResult.Properties) { var spanStart = propertyResult.Node.SpanStart - startRootTypeSpan; var spanLength = propertyResult.Node.Span.Length; var node = rootTypeNode.DescendantNodes() .OfType <PropertyDeclarationSyntax>() .First(o => o.SpanStart == spanStart && o.Span.Length == spanLength); var transformedNode = new PropertyTransformationResult(propertyResult); transformResult.TransformedProperties.Add(transformedNode); rootTypeNode = rootTypeNode.ReplaceNode(node, node.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation))); } } // Save the orignal node that was only annotated var originalAnnotatedNode = rootTypeNode; // Now we can start transforming the type. Start from the bottom in order to preserve replaced nested types foreach (var transformResult in rootTransformResult.GetSelfAndDescendantTransformedTypes().OrderByDescending(o => o.OriginalNode.SpanStart)) { var typeResult = transformResult.AnalyzationResult; // Add partial keyword on the original node if not present if ((typeResult.Conversion == TypeConversion.Partial || onlyMissingMembers) && !typeResult.IsPartial) { if (rootTransformResult.OriginalModified == null) { rootTransformResult.OriginalModified = originalAnnotatedNode; } var typeNode = rootTransformResult.OriginalModified.GetAnnotatedNodes(transformResult.Annotation).OfType <TypeDeclarationSyntax>().First(); rootTransformResult.OriginalModified = rootTransformResult.OriginalModified.ReplaceNode(typeNode, typeNode.AddPartial()); } if (typeResult.Conversion == TypeConversion.Ignore || ( onlyMissingMembers && !typeResult.GetSelfAndDescendantsTypes().SelectMany(o => o.MethodsAndAccessors).Any(o => o.Missing) )) { rootTypeNode = rootTypeNode.RemoveNodeKeepDirectives(transformResult.Annotation, transformResult.LeadingWhitespaceTrivia, transformResult.EndOfLineTrivia); continue; } var memberWhitespace = Whitespace(transformResult.LeadingWhitespaceTrivia.ToFullString() + transformResult.IndentTrivia.ToFullString()); if (typeResult.Conversion == TypeConversion.Partial || onlyMissingMembers) { // First we need to remove ignored method var typeNode = rootTypeNode.GetAnnotatedNodes(transformResult.Annotation).OfType <TypeDeclarationSyntax>().First(); // We need to remove the attributes as they cannot be defined in both partial classes var newTypeNode = typeNode.AddPartial().WithoutAttributes(); // We need to remove all other members that are not methods, properties or types newTypeNode = newTypeNode.RemoveMembersKeepDirectives(o => !(o is BaseMethodDeclarationSyntax || o is TypeDeclarationSyntax || o is PropertyDeclarationSyntax || o is BaseFieldDeclarationSyntax), memberWhitespace, transformResult.EndOfLineTrivia); rootTypeNode = TransformTypeMembers(namespaceMetadata, onlyMissingMembers, transformResult, newTypeNode, memberWhitespace, rootTypeNode, typeNode); } // If the root type has to be a new type then all nested types have to be new types else if (typeResult.Conversion == TypeConversion.NewType || typeResult.Conversion == TypeConversion.Copy) { var typeNode = rootTypeNode.GetAnnotatedNodes(transformResult.Annotation).OfType <TypeDeclarationSyntax>().First(); var identifierToken = typeNode.ChildTokens().First(o => o.IsKind(SyntaxKind.IdentifierToken)); var newTypeNode = typeResult.Conversion == TypeConversion.NewType ? typeNode.ReplaceToken(identifierToken, Identifier(identifierToken.ValueText + "Async").WithTriviaFrom(identifierToken)) : typeNode; rootTypeNode = TransformTypeMembers(namespaceMetadata, onlyMissingMembers, transformResult, newTypeNode, memberWhitespace, rootTypeNode, typeNode); } } rootTransformResult.Transformed = rootTypeNode; return(rootTransformResult); }
public RootTypeTransformationResult(ITypeAnalyzationResult analyzationResult) : base(analyzationResult) { }
// TODO: Missing members private TypeTransformationResult TransformType(ITypeAnalyzationResult rootTypeResult) { var rootTypeNode = rootTypeResult.Node; var startRootTypeSpan = rootTypeNode.SpanStart; var typeResultMetadatas = new Dictionary <ITypeAnalyzationResult, TypeTransformationMetadata>(); var rootMetadata = new TypeTransformationMetadata { ReservedFieldNames = new HashSet <string>(rootTypeResult.Symbol.MemberNames) }; // We do this here because we want that the root node has span start equal to 0 rootTypeNode = rootTypeNode.WithAdditionalAnnotations(new SyntaxAnnotation(rootMetadata.Annotation)); startRootTypeSpan -= rootTypeNode.SpanStart; // Before any modification we need to annotate nodes that will be transformed in order to find them later on. // We cannot rely on spans as they changes each time the node is modified. foreach (var typeResult in rootTypeResult.GetSelfAndDescendantsTypes(o => o.Conversion != TypeConversion.Ignore)) { var typeSpanStart = typeResult.Node.SpanStart - startRootTypeSpan; var typeSpanLength = typeResult.Node.Span.Length; var typeNode = rootTypeNode.DescendantNodesAndSelf().OfType <TypeDeclarationSyntax>() .First(o => o.SpanStart == typeSpanStart && o.Span.Length == typeSpanLength); TypeTransformationMetadata metadata; if (typeNode == rootTypeNode) { metadata = rootMetadata; } else { metadata = new TypeTransformationMetadata { ReservedFieldNames = new HashSet <string>(typeResult.Symbol.MemberNames) }; rootTypeNode = rootTypeNode.ReplaceNode(typeNode, typeNode.WithAdditionalAnnotations(new SyntaxAnnotation(metadata.Annotation))); } // TypeReferences can be changes only if we create a new type if (rootTypeResult.Conversion == TypeConversion.NewType) { foreach (var typeReference in typeResult.TypeReferences) { var reference = typeReference.ReferenceLocation; var refSpanStart = reference.Location.SourceSpan.Start - startRootTypeSpan; var refSpanLength = reference.Location.SourceSpan.Length; if (refSpanStart < 0) { // TODO: cref //var startSpan = reference.Location.SourceSpan.Start - rootTypeInfo.Node.GetLeadingTrivia().Span.Start; //var crefNode = leadingTrivia.First(o => o.SpanStart == startSpan && o.Span.Length == refSpanLength); continue; } var nameNode = rootTypeNode.GetSimpleName(refSpanStart, refSpanLength); var transformedNode = new TransformationResult(nameNode) { TransformedNode = nameNode.WithIdentifier(Identifier(nameNode.Identifier.ValueText + "Async")) }; metadata.TransformedNodes.Add(transformedNode); rootTypeNode = rootTypeNode.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation))); } } // Annotate and save the transformed methods foreach (var methodResult in typeResult.Methods) { var methodSpanStart = methodResult.Node.SpanStart - startRootTypeSpan; var methodSpanLength = methodResult.Node.Span.Length; var methodNode = rootTypeNode.DescendantNodes() .OfType <MethodDeclarationSyntax>() .First(o => o.SpanStart == methodSpanStart && o.Span.Length == methodSpanLength); var transformedNode = TransformMethod(metadata, methodResult); metadata.TransformedMethods.Add(transformedNode); rootTypeNode = rootTypeNode.ReplaceNode(methodNode, methodNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation))); } typeResultMetadatas.Add(typeResult, metadata); } // Save the orignal node that was only annotated var result = new TypeTransformationResult(rootTypeNode); // Now we can start transforming the type. Start from the bottom in order to preserve replaced nested types foreach (var typeResult in rootTypeResult.GetSelfAndDescendantsTypes(o => o.Conversion != TypeConversion.Ignore) .OrderByDescending(o => o.Node.SpanStart)) { var metadata = typeResultMetadatas[typeResult]; // Add partial keyword on the original node if not present if (typeResult.Conversion == TypeConversion.Partial && !typeResult.IsPartial) { var typeNode = rootTypeNode.GetAnnotatedNodes(metadata.Annotation).OfType <TypeDeclarationSyntax>().First(); result.OriginalModifiedNode = result.Node.ReplaceNode(typeNode, typeNode.AddPartial()); } // If the root type has to be a new type then all nested types have to be new types if (typeResult.Conversion == TypeConversion.NewType) { // Replace all rewritten nodes foreach (var rewNode in metadata.TransformedNodes) { var node = rootTypeNode.GetAnnotatedNodes(rewNode.Annotation).First(); if (rewNode.TransformedNode == null) { //TODO: fix regions rootTypeNode = rootTypeNode.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia); } else { rootTypeNode = rootTypeNode.ReplaceNode(node, rewNode.TransformedNode); } } } else if (typeResult.Conversion == TypeConversion.Partial) { var typeNode = rootTypeNode.GetAnnotatedNodes(metadata.Annotation).OfType <TypeDeclarationSyntax>().First(); var newNodes = metadata.TransformedNodes .Union(metadata.TransformedMethods) .Where(o => o.TransformedNode != null) .OrderBy(o => o.Node.SpanStart) .Select(o => o.TransformedNode) .Union(typeNode.DescendantNodes().OfType <TypeDeclarationSyntax>()) .ToList(); if (!newNodes.Any()) { //TODO: fix regions rootTypeNode = rootTypeNode.RemoveNode(typeNode, SyntaxRemoveOptions.KeepNoTrivia); } else { // We need to remove the attributes as they cannot be defined in both partial classes var newTypeNode = typeNode.AddPartial().WithoutAttributes(); // Add fields for async lock if any. We need a lock field for each synchronized method foreach (var methodTransform in metadata.TransformedMethods.Where(o => o.AsyncLockField != null).OrderBy(o => o.Node.SpanStart)) { newNodes.Insert(0, methodTransform.AsyncLockField); } newTypeNode = newTypeNode.WithMembers(List(newNodes)); //TODO: fix regions rootTypeNode = rootTypeNode.ReplaceNode(typeNode, newTypeNode /*.RemoveLeadingDirectives()*/); } } } result.TransformedNode = rootTypeNode; return(result); }
public TypeTransformationResult(ITypeAnalyzationResult analyzationResult) : base(analyzationResult.Node) { AnalyzationResult = analyzationResult; }
private static IEnumerable <ITypeAnalyzationResult> GetSelfAndDescendantsTypesRecursively(ITypeAnalyzationResult typeData, Func <ITypeAnalyzationResult, bool> predicate = null) { if (predicate?.Invoke(typeData) == false) { yield break; } yield return(typeData); foreach (var subTypeData in typeData.NestedTypes) { if (predicate?.Invoke(subTypeData) == false) { continue; } foreach (var td in GetSelfAndDescendantsTypesRecursively(subTypeData, predicate)) { yield return(td); } } }
public static IEnumerable <ITypeAnalyzationResult> GetSelfAndDescendantsTypes(this ITypeAnalyzationResult typeResult, Func <ITypeAnalyzationResult, bool> predicate = null) { return(GetSelfAndDescendantsTypesRecursively(typeResult, predicate)); }