示例#1
0
        public void WriteDocument_WritesNamespace()
        {
            // Arrange
            var document = new DocumentIntermediateNode();
            var builder  = IntermediateNodeBuilder.Create(document);

            builder.Add(new NamespaceDeclarationIntermediateNode()
            {
                Content = "TestNamespace",
            });

            var codeDocument = TestRazorCodeDocument.CreateEmpty();
            var options      = RazorCodeGenerationOptions.CreateDefault();

            var target = CodeTarget.CreateDefault(codeDocument, options);
            var writer = new DefaultDocumentWriter(target, options);

            // Act
            var result = writer.WriteDocument(codeDocument, document);

            // Assert
            var csharp = result.GeneratedCode;

            Assert.Equal(
                @"#pragma checksum ""test.cshtml"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""da39a3ee5e6b4b0d3255bfef95601890afd80709""
// <auto-generated/>
#pragma warning disable 1591
namespace TestNamespace
{
    #line hidden
}
#pragma warning restore 1591
",
                csharp,
                ignoreLineEndingDifferences: true);
        }
示例#2
0
        public void Execute_NoOps_IfClassNameNodeIsMissing()
        {
            // Arrange
            var irDocument = new DocumentIntermediateNode();
            var builder    = IntermediateNodeBuilder.Create(irDocument);
            var @namespace = new NamespaceDeclarationIntermediateNode()
            {
                Content = "SomeNamespace"
            };

            builder.Push(@namespace);

            var pass = new AssemblyAttributeInjectionPass
            {
                Engine = RazorEngine.Create(),
            };

            // Act
            pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);

            // Assert
            Assert.Collection(irDocument.Children,
                              node => Assert.Same(@namespace, node));
        }
示例#3
0
        public void WriteCSharpCode_WhitespaceContent_DoesNothing()
        {
            // Arrange
            var codeWriter = new CodeWriter();
            var writer     = new RuntimeNodeWriter();
            var context    = TestCodeRenderingContext.CreateRuntime();

            var node = new CSharpCodeIntermediateNode();

            IntermediateNodeBuilder.Create(node)
            .Add(new IntermediateToken()
            {
                Kind    = TokenKind.CSharp,
                Content = "  \t"
            });

            // Act
            writer.WriteCSharpCode(context, node);

            // Assert
            var csharp = context.CodeWriter.GenerateCode();

            Assert.Empty(csharp);
        }
示例#4
0
        public void Execute_HasRequiredInfo_AndImport_AddsItemAndSourceChecksum()
        {
            // Arrange
            var engine = CreateEngine();
            var pass   = new MetadataAttributePass()
            {
                Engine = engine,
            };

            var sourceDocument = TestRazorSourceDocument.Create("", new RazorSourceDocumentProperties(null, "Foo\\Bar.cshtml"));
            var import         = TestRazorSourceDocument.Create("@using System", new RazorSourceDocumentProperties(null, "Foo\\Import.cshtml"));
            var codeDocument   = RazorCodeDocument.Create(sourceDocument, new[] { import, });

            var irDocument = new DocumentIntermediateNode()
            {
                DocumentKind = "test",
                Options      = RazorCodeGenerationOptions.Create((o) => { }),
            };
            var builder    = IntermediateNodeBuilder.Create(irDocument);
            var @namespace = new NamespaceDeclarationIntermediateNode
            {
                Annotations =
                {
                    [CommonAnnotations.PrimaryNamespace] = CommonAnnotations.PrimaryNamespace,
                },
                Content = "Some.Namespace"
            };

            builder.Push(@namespace);
            var @class = new ClassDeclarationIntermediateNode
            {
                Annotations =
                {
                    [CommonAnnotations.PrimaryClass] = CommonAnnotations.PrimaryClass,
                },
                ClassName = "Test",
            };

            builder.Add(@class);

            // Act
            pass.Execute(codeDocument, irDocument);

            // Assert
            Assert.Equal(2, irDocument.Children.Count);

            var item = Assert.IsType <RazorCompiledItemAttributeIntermediateNode>(irDocument.Children[0]);

            Assert.Equal("/Foo/Bar.cshtml", item.Identifier);
            Assert.Equal("test", item.Kind);
            Assert.Equal("Some.Namespace.Test", item.TypeName);

            Assert.Equal(3, @namespace.Children.Count);
            var checksum = Assert.IsType <RazorSourceChecksumAttributeIntermediateNode>(@namespace.Children[0]);

            Assert.NotNull(checksum.Checksum); // Not verifying the checksum here
            Assert.Equal("SHA1", checksum.ChecksumAlgorithm);
            Assert.Equal("/Foo/Bar.cshtml", checksum.Identifier);

            checksum = Assert.IsType <RazorSourceChecksumAttributeIntermediateNode>(@namespace.Children[1]);
            Assert.NotNull(checksum.Checksum); // Not verifying the checksum here
            Assert.Equal("SHA1", checksum.ChecksumAlgorithm);
            Assert.Equal("/Foo/Import.cshtml", checksum.Identifier);
        }
示例#5
0
 public Visitor(IntermediateNodeBuilder document, IntermediateNodeBuilder @namespace, IntermediateNodeBuilder @class, IntermediateNodeBuilder method)
 {
     _document  = document;
     _namespace = @namespace;
     _class     = @class;
     _method    = method;
 }
        public void Execute_AddsRazorPagettribute_ToPage()
        {
            // Arrange
            var expectedAttribute = "[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(@\"/Views/Index.cshtml\", typeof(SomeNamespace.SomeName), null)]";
            var irDocument        = new DocumentIntermediateNode
            {
                DocumentKind = RazorPageDocumentClassifierPass.RazorPageDocumentKind,
                Options      = RazorCodeGenerationOptions.CreateDefault(),
            };
            var builder       = IntermediateNodeBuilder.Create(irDocument);
            var pageDirective = new DirectiveIntermediateNode
            {
                Directive = PageDirective.Directive,
            };

            builder.Add(pageDirective);

            var @namespace = new NamespaceDeclarationIntermediateNode
            {
                Content     = "SomeNamespace",
                Annotations =
                {
                    [CommonAnnotations.PrimaryNamespace] = CommonAnnotations.PrimaryNamespace
                },
            };

            builder.Push(@namespace);
            var @class = new ClassDeclarationIntermediateNode
            {
                ClassName   = "SomeName",
                Annotations =
                {
                    [CommonAnnotations.PrimaryClass] = CommonAnnotations.PrimaryClass,
                },
            };

            builder.Add(@class);

            var pass = new AssemblyAttributeInjectionPass
            {
                Engine = RazorProjectEngine.Create().Engine,
            };

            var source   = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "/Views/Index.cshtml"));
            var document = RazorCodeDocument.Create(source);

            // Act
            pass.Execute(document, irDocument);

            // Assert
            Assert.Collection(irDocument.Children,
                              node => Assert.Same(pageDirective, node),
                              node =>
            {
                var csharpCode = Assert.IsType <CSharpCodeIntermediateNode>(node);
                var token      = Assert.IsType <IntermediateToken>(Assert.Single(csharpCode.Children));
                Assert.Equal(TokenKind.CSharp, token.Kind);
                Assert.Equal(expectedAttribute, token.Content);
            },
                              node => Assert.Same(@namespace, node));
        }
示例#7
0
        public void WriteDocument_WritesMethod()
        {
            // Arrange
            var document = new DocumentIntermediateNode();
            var builder  = IntermediateNodeBuilder.Create(document);

            builder.Add(new MethodDeclarationIntermediateNode()
            {
                Modifiers =
                {
                    "internal",
                    "virtual",
                    "async",
                },
                MethodName = "TestMethod",
                Parameters =
                {
                    new MethodParameter()
                    {
                        Modifiers =
                        {
                            "readonly",
                            "ref",
                        },
                        ParameterName = "a",
                        TypeName      = "int",
                    },
                    new MethodParameter()
                    {
                        ParameterName = "b",
                        TypeName      = "string",
                    }
                },
                ReturnType = "string",
            });

            var codeDocument = TestRazorCodeDocument.CreateEmpty();
            var options      = RazorCodeGenerationOptions.CreateDefault();

            var target = CodeTarget.CreateDefault(codeDocument, options);
            var writer = new DefaultDocumentWriter(target, options);

            // Act
            var result = writer.WriteDocument(codeDocument, document);

            // Assert
            var csharp = result.GeneratedCode;

            Assert.Equal(
                @"#pragma checksum ""test.cshtml"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""da39a3ee5e6b4b0d3255bfef95601890afd80709""
// <auto-generated/>
#pragma warning disable 1591
#pragma warning disable 1998
internal virtual async string TestMethod(readonly ref int a, string b)
{
}
#pragma warning restore 1998
#pragma warning restore 1591
",
                csharp,
                ignoreLineEndingDifferences: true);
        }
 public ImportBuilder(IntermediateNodeBuilder innerBuilder)
 {
     _innerBuilder = innerBuilder;
 }
 public ImportsVisitor(DocumentIntermediateNode document, IntermediateNodeBuilder builder, Dictionary <string, SourceSpan?> namespaces)
     : base(document, new ImportBuilder(builder), namespaces)
 {
 }
 public MainSourceVisitor(DocumentIntermediateNode document, IntermediateNodeBuilder builder, Dictionary <string, SourceSpan?> namespaces, string tagHelperPrefix)
     : base(document, builder, namespaces)
 {
     _tagHelperPrefix = tagHelperPrefix;
 }
        protected override void ExecuteCore(RazorCodeDocument codeDocument)
        {
            var syntaxTree = codeDocument.GetSyntaxTree();

            ThrowForMissingDocumentDependency(syntaxTree);

            // This might not have been set if there are no tag helpers.
            var tagHelperContext = codeDocument.GetTagHelperContext();

            var document = new DocumentIntermediateNode();
            var builder  = IntermediateNodeBuilder.Create(document);

            document.Options = _optionsFeature.GetOptions();

            var namespaces = new Dictionary <string, SourceSpan?>(StringComparer.Ordinal);

            // The import documents should be inserted logically before the main document.
            var imports = codeDocument.GetImportSyntaxTrees();

            if (imports != null)
            {
                var importsVisitor = new ImportsVisitor(document, builder, namespaces);

                for (var j = 0; j < imports.Count; j++)
                {
                    var import = imports[j];

                    importsVisitor.FilePath = import.Source.FilePath;
                    importsVisitor.VisitBlock(import.Root);
                }
            }

            var tagHelperPrefix = tagHelperContext?.Prefix;
            var visitor         = new MainSourceVisitor(document, builder, namespaces, tagHelperPrefix)
            {
                FilePath = syntaxTree.Source.FilePath,
            };

            visitor.VisitBlock(syntaxTree.Root);

            // In each lowering piece above, namespaces were tracked. We render them here to ensure every
            // lowering action has a chance to add a source location to a namespace. Ultimately, closest wins.

            var i = 0;

            foreach (var @namespace in namespaces)
            {
                var @using = new UsingDirectiveIntermediateNode()
                {
                    Content = @namespace.Key,
                    Source  = @namespace.Value,
                };

                builder.Insert(i++, @using);
            }

            ImportDirectives(document);

            // The document should contain all errors that currently exist in the system. This involves
            // adding the errors from the primary and imported syntax trees.
            for (i = 0; i < syntaxTree.Diagnostics.Count; i++)
            {
                document.Diagnostics.Add(syntaxTree.Diagnostics[i]);
            }

            if (imports != null)
            {
                for (i = 0; i < imports.Count; i++)
                {
                    var import = imports[i];
                    for (var j = 0; j < import.Diagnostics.Count; j++)
                    {
                        document.Diagnostics.Add(import.Diagnostics[j]);
                    }
                }
            }

            codeDocument.SetDocumentIntermediateNode(document);
        }
 public LoweringVisitor(DocumentIntermediateNode document, IntermediateNodeBuilder builder, Dictionary <string, SourceSpan?> namespaces)
 {
     _document   = document;
     _builder    = builder;
     _namespaces = namespaces;
 }
 public ImportsVisitor(DocumentIntermediateNode document, IntermediateNodeBuilder builder, RazorParserFeatureFlags featureFlags)
     : base(document, new ImportBuilder(builder), featureFlags)
 {
 }
 public MainSourceVisitor(DocumentIntermediateNode document, IntermediateNodeBuilder builder, string tagHelperPrefix, RazorParserFeatureFlags featureFlags)
     : base(document, builder, featureFlags)
 {
     _tagHelperPrefix = tagHelperPrefix;
 }
        protected override void ExecuteCore(RazorCodeDocument codeDocument)
        {
            var syntaxTree = codeDocument.GetSyntaxTree();

            ThrowForMissingDocumentDependency(syntaxTree);

            // This might not have been set if there are no tag helpers.
            var tagHelperContext = codeDocument.GetTagHelperContext();

            var document = new DocumentIntermediateNode();
            var builder  = IntermediateNodeBuilder.Create(document);

            document.Options = codeDocument.GetCodeGenerationOptions() ?? _optionsFeature.GetOptions();

            IReadOnlyList <UsingReference> importedUsings = Array.Empty <UsingReference>();

            // The import documents should be inserted logically before the main document.
            var imports = codeDocument.GetImportSyntaxTrees();

            if (imports != null)
            {
                var importsVisitor = new ImportsVisitor(document, builder, syntaxTree.Options.FeatureFlags);

                for (var j = 0; j < imports.Count; j++)
                {
                    var import = imports[j];

                    importsVisitor.FilePath = import.Source.FilePath;
                    importsVisitor.VisitBlock(import.Root);
                }

                importedUsings = importsVisitor.Usings;
            }

            var tagHelperPrefix = tagHelperContext?.Prefix;
            var visitor         = new MainSourceVisitor(document, builder, tagHelperPrefix, syntaxTree.Options.FeatureFlags)
            {
                FilePath = syntaxTree.Source.FilePath,
            };

            visitor.VisitBlock(syntaxTree.Root);

            // 1. Prioritize non-imported usings over imported ones.
            // 2. Don't import usings that already exist in primary document.
            // 3. Allow duplicate usings in primary document (C# warning).
            var usingReferences = new List <UsingReference>(visitor.Usings);

            for (var j = importedUsings.Count - 1; j >= 0; j--)
            {
                if (!usingReferences.Contains(importedUsings[j]))
                {
                    usingReferences.Insert(0, importedUsings[j]);
                }
            }

            // In each lowering piece above, namespaces were tracked. We render them here to ensure every
            // lowering action has a chance to add a source location to a namespace. Ultimately, closest wins.

            var i = 0;

            foreach (var reference in usingReferences)
            {
                var @using = new UsingDirectiveIntermediateNode()
                {
                    Content = reference.Namespace,
                    Source  = reference.Source,
                };

                builder.Insert(i++, @using);
            }

            ImportDirectives(document);

            // The document should contain all errors that currently exist in the system. This involves
            // adding the errors from the primary and imported syntax trees.
            for (i = 0; i < syntaxTree.Diagnostics.Count; i++)
            {
                document.Diagnostics.Add(syntaxTree.Diagnostics[i]);
            }

            if (imports != null)
            {
                for (i = 0; i < imports.Count; i++)
                {
                    var import = imports[i];
                    for (var j = 0; j < import.Diagnostics.Count; j++)
                    {
                        document.Diagnostics.Add(import.Diagnostics[j]);
                    }
                }
            }

            codeDocument.SetDocumentIntermediateNode(document);
        }