diff --git a/src/Microsoft.AspNet.Razor/CSharpRazorCodeLanguage.cs b/src/Microsoft.AspNet.Razor/CSharpRazorCodeLanguage.cs index 2d26eb4365..f4faa54395 100644 --- a/src/Microsoft.AspNet.Razor/CSharpRazorCodeLanguage.cs +++ b/src/Microsoft.AspNet.Razor/CSharpRazorCodeLanguage.cs @@ -2,6 +2,8 @@ using System; using Microsoft.AspNet.Razor.Generator; +using Microsoft.AspNet.Razor.Generator.Compiler; +using Microsoft.AspNet.Razor.Generator.Compiler.CSharp; using Microsoft.AspNet.Razor.Parser; using Microsoft.CSharp; @@ -47,5 +49,10 @@ namespace Microsoft.AspNet.Razor { return new CSharpRazorCodeGenerator(className, rootNamespaceName, sourceFileName, host); } + + public override CodeBuilder CreateBuilder(CodeGeneratorContext codeGeneratorContext) + { + return new CSharpCodeBuilder(codeGeneratorContext); + } } } diff --git a/src/Microsoft.AspNet.Razor/Generator/CodeGeneratorContext.cs b/src/Microsoft.AspNet.Razor/Generator/CodeGeneratorContext.cs index 1e86d17041..2f9316989b 100644 --- a/src/Microsoft.AspNet.Razor/Generator/CodeGeneratorContext.cs +++ b/src/Microsoft.AspNet.Razor/Generator/CodeGeneratorContext.cs @@ -29,6 +29,8 @@ namespace Microsoft.AspNet.Razor.Generator // It's way safer to make them internal for now, especially with the code generator stuff in a bit of flux. internal ExpressionRenderingMode ExpressionRenderingMode { get; set; } public string SourceFile { get; internal set; } + public string RootNamespace { get; private set; } + public string ClassName { get; private set; } #region deletable #if NET45 @@ -46,6 +48,7 @@ namespace Microsoft.AspNet.Razor.Generator public CodeCompileUnit CompileUnit { get; internal set; } public CodeNamespace Namespace { get; internal set; } + public CodeTypeDeclaration GeneratedClass { get; internal set; } public CodeMemberMethod TargetMethod { get; set; } public IDictionary CodeMappings { get; private set; } @@ -320,6 +323,8 @@ namespace Microsoft.AspNet.Razor.Generator CodeTreeBuilder = new CodeTreeBuilder(), Host = host, SourceFile = shouldGenerateLinePragmas ? sourceFile : null, + RootNamespace = rootNamespace, + ClassName = className, #if NET45 // This section is #if'd because it contains SOME incompatible pieces but also will not be needed once we transition over // to using the CodeTree diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpCodeBuilder.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpCodeBuilder.cs index d0a03917c4..7735dbc7d6 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpCodeBuilder.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpCodeBuilder.cs @@ -1,72 +1,53 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp { public class CSharpCodeBuilder : CodeBuilder { - public CSharpCodeBuilder(CodeTree codeTree, string rootNamespace, RazorEngineHost host, string sourceFile) - : base(codeTree) + public CSharpCodeBuilder(CodeGeneratorContext context) + : base(context) { - Host = host; - RootNamespace = rootNamespace; - SourceFile = sourceFile; } - public RazorEngineHost Host { get; private set; } - public string RootNamespace { get; private set; } - public string SourceFile { get; private set; } + private CodeTree Tree { get { return Context.CodeTreeBuilder.CodeTree; } } + public RazorEngineHost Host { get { return Context.Host; } } public override CodeBuilderResult Build() { var writer = new CSharpCodeWriter(); - // TODO: Combine into one string (perf) - writer.WriteComment(new string('-', 78)) - .WriteComment("") - .WriteComment(" This code was generated by a tool.") - .WriteComment("") - .WriteComment(" Changes to this file may cause incorrect behavior and will be lost if") - .WriteComment(" the code is regenerated.") - .WriteComment("") - .WriteComment(new string('-', 78)) - .WriteLine(); - - using (writer.BuildNamespace(RootNamespace)) + using (writer.BuildNamespace(Context.RootNamespace)) { // Write out using directives AddImports(Tree, writer, Host.NamespaceImports); - - // TODO: Include current projects namespace? Does that happen to be included in the namespace imports? - - var baseTypeVisitor = new CSharpBaseTypeVisitor(writer); - - baseTypeVisitor.Accept(Tree.Chunks); - - string baseType = baseTypeVisitor.CurrentBaseType ?? Host.DefaultBaseClass; - // Separate the usings and the class writer.WriteLine(); + var baseTypeVisitor = new CSharpBaseTypeVisitor(writer); + baseTypeVisitor.Accept(Tree.Chunks); + + string baseType = baseTypeVisitor.CurrentBaseType ?? Host.DefaultBaseClass; new CSharpClassAttributeVisitor(writer).Accept(Tree.Chunks); - using (writer.BuildClassDeclaration("public", Host.DefaultClassName, String.IsNullOrEmpty(baseType) ? new string[0] : new string[] { baseType })) + IEnumerable baseTypes = String.IsNullOrEmpty(baseType) ? Enumerable.Empty() : + new string[] { baseType }; + using (writer.BuildClassDeclaration("public", Context.ClassName, baseTypes)) { if (Host.DesignTimeMode) { writer.WriteLine("private static object @__o;"); } - new CSharpHelperVisitor(writer, Host, SourceFile).Accept(Tree.Chunks); - new CSharpTypeMemberVisitor(writer, SourceFile).Accept(Tree.Chunks); - new CSharpDesignTimeHelpersVisitor(writer, Host, SourceFile).Accept(Tree); - + new CSharpHelperVisitor(writer, Context).Accept(Tree.Chunks); + new CSharpTypeMemberVisitor(writer, Context).Accept(Tree.Chunks); + new CSharpDesignTimeHelpersVisitor(writer, Context).Accept(Tree.Chunks); + // TODO: resolve variable declarations writer.WriteLineHiddenDirective(); - using (writer.BuildConstructor(Host.DefaultClassName)) + using (writer.BuildConstructor(Context.ClassName)) { // Any constructor based logic that we need to add? }; @@ -76,7 +57,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp using (writer.BuildMethodDeclaration("public override", "void", Host.GeneratedClassContext.ExecuteMethodName)) { - new CSharpCodeVisitor(writer, Host, SourceFile).Accept(Tree.Chunks); + new CSharpCodeVisitor(writer, Context).Accept(Tree.Chunks); } } } @@ -87,7 +68,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp private void AddImports(CodeTree codeTree, CSharpCodeWriter writer, IEnumerable defaultImports) { // Write out using directives - var usingVisitor = new CSharpUsingVisitor(writer, SourceFile); + var usingVisitor = new CSharpUsingVisitor(writer, Context.SourceFile); foreach (Chunk chunk in Tree.Chunks) { usingVisitor.Accept(chunk); diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpCodeVisitor.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpCodeVisitor.cs index 2d61a878a5..1a29e5f9cb 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpCodeVisitor.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpCodeVisitor.cs @@ -8,23 +8,20 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp { private const string ValueWriterName = "__razor_attribute_value_writer"; - private CSharpCodeWriter _writer; - // TODO: No need for the entire host - private RazorEngineHost _host; - private string _sourceFile; + private readonly CSharpCodeWriter _writer; + private readonly CodeGeneratorContext _context; - public CSharpCodeVisitor(CSharpCodeWriter writer, RazorEngineHost host, string sourceFile) + public CSharpCodeVisitor(CSharpCodeWriter writer, CodeGeneratorContext context) { _writer = writer; - _host = host; - _sourceFile = sourceFile; + _context = context; } protected override void Visit(SetLayoutChunk chunk) { - if (!_host.DesignTimeMode && !String.IsNullOrEmpty(_host.GeneratedClassContext.LayoutPropertyName)) + if (!_context.Host.DesignTimeMode && !String.IsNullOrEmpty(_context.Host.GeneratedClassContext.LayoutPropertyName)) { - _writer.Write(_host.GeneratedClassContext.LayoutPropertyName) + _writer.Write(_context.Host.GeneratedClassContext.LayoutPropertyName) .Write(" = ") .WriteStringLiteral(chunk.Layout) .WriteLine(";"); @@ -34,7 +31,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(TemplateChunk chunk) { _writer.Write(TemplateBlockCodeGenerator.ItemParameterName).Write(" => ") - .WriteStartNewObject(_host.GeneratedClassContext.TemplateTypeName); + .WriteStartNewObject(_context.Host.GeneratedClassContext.TemplateTypeName); using (_writer.BuildLambda(endLine: false, parameterNames: TemplateBlockCodeGenerator.TemplateWriterName)) { @@ -46,30 +43,30 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(ResolveUrlChunk chunk) { - if (!_host.DesignTimeMode && String.IsNullOrEmpty(chunk.Url)) + if (!_context.Host.DesignTimeMode && String.IsNullOrEmpty(chunk.Url)) { return; } // TODO: Add instrumentation - if (!String.IsNullOrEmpty(chunk.Url) && !_host.DesignTimeMode) + if (!String.IsNullOrEmpty(chunk.Url) && !_context.Host.DesignTimeMode) { if (chunk.RenderingMode == ExpressionRenderingMode.WriteToOutput) { if (!String.IsNullOrEmpty(chunk.WriterName)) { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteLiteralToMethodName) + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteLiteralToMethodName) .Write(chunk.WriterName) .WriteParameterSeparator(); } else { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteLiteralMethodName); + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteLiteralMethodName); } } - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.ResolveUrlMethodName) + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.ResolveUrlMethodName) .WriteStringLiteral(chunk.Url) .WriteEndMethodInvocation(endLine: false); @@ -82,24 +79,24 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(LiteralChunk chunk) { - if (!_host.DesignTimeMode && String.IsNullOrEmpty(chunk.Text)) + if (!_context.Host.DesignTimeMode && String.IsNullOrEmpty(chunk.Text)) { return; } // TODO: Add instrumentation - if (!String.IsNullOrEmpty(chunk.Text) && !_host.DesignTimeMode) + if (!String.IsNullOrEmpty(chunk.Text) && !_context.Host.DesignTimeMode) { if (!String.IsNullOrEmpty(chunk.WriterName)) { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteLiteralToMethodName) + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteLiteralToMethodName) .Write(chunk.WriterName) .WriteParameterSeparator(); } else { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteLiteralMethodName); + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteLiteralMethodName); } _writer.WriteStringLiteral(chunk.Text) @@ -114,13 +111,13 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp // TODO: Handle instrumentation // TODO: Refactor - if (!_host.DesignTimeMode && chunk.RenderingMode == ExpressionRenderingMode.InjectCode) + if (!_context.Host.DesignTimeMode && chunk.RenderingMode == ExpressionRenderingMode.InjectCode) { Visit((ChunkBlock)chunk); } else { - if (_host.DesignTimeMode) + if (_context.Host.DesignTimeMode) { _writer.WriteStartAssignment("__o"); } @@ -130,19 +127,19 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp if (!String.IsNullOrEmpty(chunk.WriterName)) { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteToMethodName) + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteToMethodName) .Write(chunk.WriterName) .WriteParameterSeparator(); } else { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteMethodName); + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteMethodName); } } Visit((ChunkBlock)chunk); - if (_host.DesignTimeMode) + if (_context.Host.DesignTimeMode) { _writer.WriteLine(";"); } @@ -155,7 +152,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(ExpressionChunk chunk) { - using (_writer.BuildLineMapping(chunk.Start, chunk.Code.Value.Length, _sourceFile)) + using (_writer.BuildLineMapping(chunk.Start, chunk.Code.Value.Length, _context.SourceFile)) { _writer.Indent(chunk.Start.CharacterIndex) .Write(chunk.Code.Value); @@ -166,7 +163,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp { foreach (Snippet snippet in chunk.Code) { - using (_writer.BuildLineMapping(chunk.Start, snippet.Value.Length, _sourceFile)) + using (_writer.BuildLineMapping(chunk.Start, snippet.Value.Length, _context.SourceFile)) { _writer.Indent(chunk.Start.CharacterIndex); _writer.WriteLine(snippet.Value); @@ -176,7 +173,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(DynamicCodeAttributeChunk chunk) { - if (_host.DesignTimeMode) + if (_context.Host.DesignTimeMode) { return; // Don't generate anything! } @@ -208,7 +205,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp .WriteLocationTaggedString(chunk.Prefix) .WriteParameterSeparator() .WriteStartMethodInvocation("Tuple.Create", new string[] { "System.Object", "System.Int32" }) - .WriteStartNewObject(_host.GeneratedClassContext.TemplateTypeName); + .WriteStartNewObject(_context.Host.GeneratedClassContext.TemplateTypeName); using (_writer.BuildLambda(endLine: false, parameterNames: ValueWriterName)) { @@ -227,7 +224,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(LiteralCodeAttributeChunk chunk) { - if (_host.DesignTimeMode) + if (_context.Host.DesignTimeMode) { return; // Don't generate anything! } @@ -262,20 +259,20 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(CodeAttributeChunk chunk) { - if (_host.DesignTimeMode) + if (_context.Host.DesignTimeMode) { return; // Don't generate anything! } if (!String.IsNullOrEmpty(chunk.WriterName)) { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteAttributeToMethodName) + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteAttributeToMethodName) .Write(chunk.WriterName) .WriteParameterSeparator(); } else { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteAttributeMethodName); + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteAttributeMethodName); } _writer.WriteStringLiteral(chunk.Attribute) @@ -291,7 +288,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(SectionChunk chunk) { - _writer.WriteStartMethodInvocation(_host.GeneratedClassContext.DefineSectionMethodName) + _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.DefineSectionMethodName) .WriteStringLiteral(chunk.Name) .WriteParameterSeparator(); diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpDesignTimeHelpersVisitor.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpDesignTimeHelpersVisitor.cs index 19de46aa9b..1c000663f8 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpDesignTimeHelpersVisitor.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpDesignTimeHelpersVisitor.cs @@ -5,27 +5,24 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp { internal const string InheritsHelper = "__inheritsHelper"; - private CSharpCodeWriter _writer; - // TODO: No need for the entire host - private RazorEngineHost _host; - private string _sourceFile; + private readonly CSharpCodeWriter _writer; + private readonly CodeGeneratorContext _context; - public CSharpDesignTimeHelpersVisitor(CSharpCodeWriter writer, RazorEngineHost host, string sourceFile) + public CSharpDesignTimeHelpersVisitor(CSharpCodeWriter writer, CodeGeneratorContext context) { _writer = writer; - _host = host; - _sourceFile = sourceFile; + _context = context; } - public void Accept(CodeTree tree) + public override void Accept(System.Collections.Generic.IList chunks) { - if(_host.DesignTimeMode) + if (_context.Host.DesignTimeMode) { - using(_writer.BuildMethodDeclaration("private","void", "@"+CodeGeneratorContext.DesignTimeHelperMethodName)) + using (_writer.BuildMethodDeclaration("private", "void", "@" + CodeGeneratorContext.DesignTimeHelperMethodName)) { using (_writer.BuildDisableWarningScope()) { - Accept(tree.Chunks); + Accept(chunks); } } } @@ -33,9 +30,9 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp protected override void Visit(SetBaseTypeChunk chunk) { - if (_host.DesignTimeMode) + if (_context.Host.DesignTimeMode) { - using (CSharpLineMappingWriter lineMappingWriter = _writer.BuildLineMapping(chunk.Start, chunk.TypeName.Length, _sourceFile)) + using (CSharpLineMappingWriter lineMappingWriter = _writer.BuildLineMapping(chunk.Start, chunk.TypeName.Length, _context.SourceFile)) { _writer.Indent(chunk.Start.CharacterIndex); diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpHelperVisitor.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpHelperVisitor.cs index 338c31fe50..6c0b36b7a1 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpHelperVisitor.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpHelperVisitor.cs @@ -6,28 +6,26 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp { private const string HelperWriterName = "__razor_helper_writer"; - private CSharpCodeWriter _writer; - private string _sourceFile; - private RazorEngineHost _host; + private readonly CSharpCodeWriter _writer; + private readonly CodeGeneratorContext _context; private CSharpCodeVisitor _codeVisitor; - public CSharpHelperVisitor(CSharpCodeWriter writer, RazorEngineHost host, string sourceFile) + public CSharpHelperVisitor(CSharpCodeWriter writer, CodeGeneratorContext context) { _writer = writer; - _sourceFile = sourceFile; - _host = host; - _codeVisitor = new CSharpCodeVisitor(writer, host, sourceFile); + _context = context; + _codeVisitor = new CSharpCodeVisitor(writer, context); } protected override void Visit(HelperChunk chunk) { IDisposable lambdaScope = null; - using (CSharpLineMappingWriter mappingWriter = _writer.BuildLineMapping(chunk.Signature.Location, chunk.Signature.Value.Length, _sourceFile)) + using (CSharpLineMappingWriter mappingWriter = _writer.BuildLineMapping(chunk.Signature.Location, chunk.Signature.Value.Length, _context.SourceFile)) { - string accessibility = "public " + (_host.StaticHelpers ? "static" : String.Empty); + string accessibility = "public " + (_context.Host.StaticHelpers ? "static" : String.Empty); - _writer.Write(accessibility).Write(" ").Write(_host.GeneratedClassContext.TemplateTypeName).Write(" "); + _writer.Write(accessibility).Write(" ").Write(_context.Host.GeneratedClassContext.TemplateTypeName).Write(" "); mappingWriter.MarkLineMappingStart(); _writer.Write(chunk.Signature); mappingWriter.MarkLineMappingEnd(); @@ -36,7 +34,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp if(chunk.HeaderComplete) { _writer.WriteStartReturn() - .WriteStartNewObject(_host.GeneratedClassContext.TemplateTypeName); + .WriteStartNewObject(_context.Host.GeneratedClassContext.TemplateTypeName); lambdaScope = _writer.BuildLambda(endLine: false, parameterNames: HelperWriterName); } @@ -52,7 +50,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp if(chunk.Footer != null && !String.IsNullOrEmpty(chunk.Footer.Value)) { - using(_writer.BuildLineMapping(chunk.Footer.Location, chunk.Footer.Value.Length, _sourceFile)) + using(_writer.BuildLineMapping(chunk.Footer.Location, chunk.Footer.Value.Length, _context.SourceFile)) { _writer.Write(chunk.Footer); } diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpTypeMemberVisitor.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpTypeMemberVisitor.cs index 5b915bbbd9..760c82cded 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpTypeMemberVisitor.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpTypeMemberVisitor.cs @@ -5,12 +5,12 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp public class CSharpTypeMemberVisitor : CodeVisitor { private CSharpCodeWriter _writer; - private string _sourceFile; + private CodeGeneratorContext _context; - public CSharpTypeMemberVisitor(CSharpCodeWriter writer, string sourceFile) + public CSharpTypeMemberVisitor(CSharpCodeWriter writer, CodeGeneratorContext context) { _writer = writer; - _sourceFile = sourceFile; + _context = context; } protected override void Visit(TypeMemberChunk chunk) @@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp if (code != null) { - using (_writer.BuildLineMapping(chunk.Start, code.Value.Length, _sourceFile)) + using (_writer.BuildLineMapping(chunk.Start, code.Value.Length, _context.SourceFile)) { _writer.WriteLine(code.Value); } diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/ChunkVisitor.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/ChunkVisitor.cs index 8e4028c5d7..d91309327f 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/ChunkVisitor.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/ChunkVisitor.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler { public abstract class ChunkVisitor : IChunkVisitor { - public void Accept(IList chunks) + public virtual void Accept(IList chunks) { if (chunks == null) { diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CodeBuilder.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CodeBuilder.cs index 35b65d02c6..f172a9ca7b 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CodeBuilder.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CodeBuilder.cs @@ -1,18 +1,20 @@  namespace Microsoft.AspNet.Razor.Generator.Compiler { - public class CodeBuilder + public abstract class CodeBuilder { - protected CodeTree Tree; + private readonly CodeGeneratorContext _context; - public CodeBuilder(CodeTree codeTree) + public CodeBuilder(CodeGeneratorContext context) { - Tree = codeTree; + _context = context; } - public virtual CodeBuilderResult Build() + protected CodeGeneratorContext Context { - return null; + get { return _context; } } + + public abstract CodeBuilderResult Build(); } } diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeTree/CodeTreeBuilder.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeTree/CodeTreeBuilder.cs index 0297284b81..3426f42365 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeTree/CodeTreeBuilder.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeTree/CodeTreeBuilder.cs @@ -6,8 +6,8 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler { public class CodeTreeBuilder { + private readonly Stack _blockChain; private Chunk _lastChunk; - private Stack _blockChain; public CodeTreeBuilder() { diff --git a/src/Microsoft.AspNet.Razor/RazorCodeLanguage.cs b/src/Microsoft.AspNet.Razor/RazorCodeLanguage.cs index a723301a0f..0e5830e6cf 100644 --- a/src/Microsoft.AspNet.Razor/RazorCodeLanguage.cs +++ b/src/Microsoft.AspNet.Razor/RazorCodeLanguage.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNet.Razor.Generator; +using Microsoft.AspNet.Razor.Generator.Compiler; using Microsoft.AspNet.Razor.Parser; namespace Microsoft.AspNet.Razor @@ -59,5 +60,7 @@ namespace Microsoft.AspNet.Razor /// Constructs the code generator. Must return a new instance on EVERY call to ensure thread-safety /// public abstract RazorCodeGenerator CreateCodeGenerator(string className, string rootNamespaceName, string sourceFileName, RazorEngineHost host); + + public abstract CodeBuilder CreateBuilder(CodeGeneratorContext codeGeneratorContext); } } diff --git a/src/Microsoft.AspNet.Razor/RazorTemplateEngine.cs b/src/Microsoft.AspNet.Razor/RazorTemplateEngine.cs index e178de4984..5a4ed0dac2 100644 --- a/src/Microsoft.AspNet.Razor/RazorTemplateEngine.cs +++ b/src/Microsoft.AspNet.Razor/RazorTemplateEngine.cs @@ -184,7 +184,7 @@ namespace Microsoft.AspNet.Razor #endif } - var builder = new CSharpCodeBuilder(generator.Context.CodeTreeBuilder.CodeTree, rootNamespace, Host, sourceFileName); + var builder = new CSharpCodeBuilder(generator.Context); CodeBuilderResult builderResult = builder.Build(); // Collect results and return diff --git a/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CSharpCodeBuilderTests.cs b/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CSharpCodeBuilderTests.cs new file mode 100644 index 0000000000..0b5305e008 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CSharpCodeBuilderTests.cs @@ -0,0 +1,52 @@ +using Microsoft.AspNet.Razor.Generator; +using Microsoft.AspNet.Razor.Generator.Compiler; +using Microsoft.AspNet.Razor.Generator.Compiler.CSharp; +using Microsoft.AspNet.Razor.Parser.SyntaxTree; +using Microsoft.TestCommon; +using Moq; + +namespace Microsoft.AspNet.Razor.Test.Generator.CodeTree +{ + public class CSharpCodeBuilderTests + { + [Fact] + public void CodeTreeWithUsings() + { + var syntaxTreeNode = Mock.Of(); + var language = new CSharpRazorCodeLanguage(); + RazorEngineHost host = new RazorEngineHost(language); + var context = CodeGeneratorContext.Create(host, "TestClass", "TestNamespace", "Foo.cs", shouldGenerateLinePragmas: false); + context.CodeTreeBuilder.AddUsingChunk("FakeNamespace1", syntaxTreeNode, context); + context.CodeTreeBuilder.AddUsingChunk("FakeNamespace2.SubNamespace", syntaxTreeNode, context); + CodeBuilder codeBuilder = language.CreateBuilder(context); + + // Act + CodeBuilderResult result = codeBuilder.Build(); + + // Assert + Assert.Equal(@"namespace TestNamespace +{ +#line 1 """" +using FakeNamespace1; +#line default +#line hidden +#line 1 """" +using FakeNamespace2.SubNamespace; +#line default +#line hidden + + public class TestClass + { + #line hidden + public TestClass() + { + } + + public override void Execute() + { + } + } +}", result.Code.TrimEnd()); + } + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeGenerationTest.cs b/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeGenerationTest.cs index ce90a2661d..7298a79c51 100644 --- a/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeGenerationTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeGenerationTest.cs @@ -6,7 +6,7 @@ using Microsoft.TestCommon; namespace Microsoft.AspNet.Razor.Test.Generator { public class CodeTreeGenerationTest : CSharpRazorCodeGeneratorTest - { + { [Fact] public void CodeTreeComparisonTest() { @@ -16,6 +16,6 @@ namespace Microsoft.AspNet.Razor.Test.Generator File.WriteAllText("./testfile_ct.cs", results.GeneratedCode); File.WriteAllText("./testfile_cd.cs", codDOMOutput); }, designTimeMode: true); - } + } } } diff --git a/test/Microsoft.AspNet.Razor.Test/Microsoft.AspNet.Razor.Test.csproj b/test/Microsoft.AspNet.Razor.Test/Microsoft.AspNet.Razor.Test.csproj index 5b760f77c6..8fe9209114 100644 --- a/test/Microsoft.AspNet.Razor.Test/Microsoft.AspNet.Razor.Test.csproj +++ b/test/Microsoft.AspNet.Razor.Test/Microsoft.AspNet.Razor.Test.csproj @@ -51,6 +51,7 @@ +