public void GenericTypeNameRewriter_CanReplaceTypeParametersWithTypeArguments(string original, string expected) { // Arrange var visitor = new GenericTypeNameRewriter(new Dictionary <string, GenericTypeNameRewriter.Binding>() { { "TItem1", new GenericTypeNameRewriter.Binding() { Content = "Type1", } }, { "TItem2", new GenericTypeNameRewriter.Binding() { Content = "Type2", } }, { "TItem3", new GenericTypeNameRewriter.Binding() { Content = null, } }, }); var parsed = SyntaxFactory.ParseTypeName(original); // Act var actual = visitor.Visit(parsed); // Assert Assert.Equal(expected, actual.ToString()); }
private string RewriteTypeName(GenericTypeNameRewriter rewriter, string typeName) { var parsed = SyntaxFactory.ParseTypeName(typeName); var rewritten = (TypeSyntax)rewriter.Visit(parsed); return(rewritten.ToFullString()); }
private void Process(ComponentExtensionNode node) { // First collect all of the information we have about each type parameter var bindings = new Dictionary <string, GenericTypeNameRewriter.Binding>(); foreach (var attribute in node.Component.GetTypeParameters()) { bindings.Add(attribute.Name, new GenericTypeNameRewriter.Binding() { Attribute = attribute, }); } foreach (var typeArgumentNode in node.TypeArguments) { var binding = bindings[typeArgumentNode.TypeParameterName]; binding.Node = typeArgumentNode; binding.Content = GetContent(typeArgumentNode); } // Right now we don't have type inference, so all type arguments are required. var missing = new List <BoundAttributeDescriptor>(); foreach (var binding in bindings) { if (binding.Value.Node == null || string.IsNullOrWhiteSpace(binding.Value.Content)) { missing.Add(binding.Value.Attribute); } } if (missing.Count > 0) { // We add our own error for this because its likely the user will see other errors due // to incorrect codegen without the types. Our errors message will pretty clearly indicate // what to do, whereas the other errors might be confusing. node.Diagnostics.Add(BlazorDiagnosticFactory.Create_GenericComponentMissingTypeArgument(node.Source, node, missing)); } var rewriter = new GenericTypeNameRewriter(bindings); // Rewrite the component type name node.TypeName = RewriteTypeName(rewriter, node.TypeName); foreach (var attribute in node.Attributes) { if (attribute.BoundAttribute?.IsGenericTypedProperty() ?? false && attribute.TypeName != null) { // If we know the type name, then replace any generic type parameter inside it with // the known types. attribute.TypeName = RewriteTypeName(rewriter, attribute.TypeName); } } foreach (var childContent in node.ChildContents) { if (childContent.BoundAttribute?.IsGenericTypedProperty() ?? false && childContent.TypeName != null) { // If we know the type name, then replace any generic type parameter inside it with // the known types. childContent.TypeName = RewriteTypeName(rewriter, childContent.TypeName); } } }