diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs index c4dab36a6b..3a1c536e1c 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs @@ -6,8 +6,8 @@ using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Intermediate; -using Microsoft.AspNetCore.Razor.Language.Legacy; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions .Add(new IntermediateToken() { Kind = IntermediateToken.TokenKind.CSharp, - Content = writer.Builder.ToString() + Content = writer.GenerateCode() }); @class.Children.Add(statement); @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var tagHelperTypeName = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper"; var className = GetVCTHClassName(descriptor); - using (writer.BuildClassDeclaration("public", className, new[] { tagHelperTypeName })) + using (writer.BuildClassDeclaration("public", className, tagHelperTypeName, interfaces: null)) { // Add view component helper. writer.WriteVariableDeclaration( @@ -122,11 +122,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions private void BuildConstructorString(CSharpCodeWriter writer, string className) { - var helperPair = new KeyValuePair( - $"global::Microsoft.AspNetCore.Mvc.IViewComponentHelper", - "helper"); - - using (writer.BuildConstructor("public", className, new[] { helperPair })) + writer.Write("public ") + .Write(className) + .Write("(") + .Write("global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper") + .WriteLine(")"); + using (writer.BuildScope()) { writer.WriteStartAssignment("_helper") .Write("helper") diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeWriter.cs b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/CSharpCodeWriter.cs similarity index 70% rename from src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeWriter.cs rename to src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/CSharpCodeWriter.cs index 84cda5424e..9467dcdba2 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeWriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/CSharpCodeWriter.cs @@ -6,11 +6,11 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; -using Microsoft.AspNetCore.Razor.Language.CodeGeneration; +using System.Text; -namespace Microsoft.AspNetCore.Razor.Language.Legacy +namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration { - public class CSharpCodeWriter : CodeWriter + public sealed class CSharpCodeWriter { private const string InstanceMethodFormat = "{0}.{1}"; @@ -26,44 +26,155 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy '\u2029', }; - public new CSharpCodeWriter Write(string data) + private static readonly char[] NewLineCharacters = { '\r', '\n' }; + + private string _cache = string.Empty; + private bool _dirty; + + private int _absoluteIndex; + private int _currentLineIndex; + private int _currentLineCharacterIndex; + + internal StringBuilder Builder { get; } = new StringBuilder(); + + public int CurrentIndent { get; set; } + + public bool IsAfterNewLine { get; private set; } + + public string NewLine { get; set; } = Environment.NewLine; + + public SourceLocation Location => new SourceLocation(_absoluteIndex, _currentLineIndex, _currentLineCharacterIndex); + + // Internal for testing. + internal CSharpCodeWriter Indent(int size) { - return (CSharpCodeWriter)base.Write(data); + if (IsAfterNewLine) + { + Builder.Append(' ', size); + + _currentLineCharacterIndex += size; + _absoluteIndex += size; + + _dirty = true; + IsAfterNewLine = false; + } + + return this; } - public new CSharpCodeWriter Indent(int size) + public CSharpCodeWriter Write(string data) { - return (CSharpCodeWriter)base.Indent(size); + if (data == null) + { + return this; + } + + return Write(data, 0, data.Length); } - public new CSharpCodeWriter ResetIndent() + public CSharpCodeWriter Write(string data, int index, int count) { - return (CSharpCodeWriter)base.ResetIndent(); + if (data == null || count == 0) + { + return this; + } + + Indent(CurrentIndent); + + Builder.Append(data, index, count); + + _dirty = true; + IsAfterNewLine = false; + + _absoluteIndex += count; + + // The data string might contain a partial newline where the previously + // written string has part of the newline. + var i = index; + int? trailingPartStart = null; + + if ( + // Check the last character of the previous write operation. + Builder.Length - count - 1 >= 0 && + Builder[Builder.Length - count - 1] == '\r' && + + // Check the first character of the current write operation. + Builder[Builder.Length - count] == '\n') + { + // This is newline that's spread across two writes. Skip the first character of the + // current write operation. + // + // We don't need to increment our newline counter because we already did that when we + // saw the \r. + i += 1; + trailingPartStart = 1; + } + + // Iterate the string, stopping at each occurrence of a newline character. This lets us count the + // newline occurrences and keep the index of the last one. + while ((i = data.IndexOfAny(NewLineCharacters, i)) >= 0) + { + // Newline found. + _currentLineIndex++; + _currentLineCharacterIndex = 0; + + i++; + + // We might have stopped at a \r, so check if it's followed by \n and then advance the index to + // start the next search after it. + if (count > i && + data[i - 1] == '\r' && + data[i] == '\n') + { + i++; + } + + // The 'suffix' of the current line starts after this newline token. + trailingPartStart = i; + } + + if (trailingPartStart == null) + { + // No newlines, just add the length of the data buffer + _currentLineCharacterIndex += count; + } + else + { + // Newlines found, add the trailing part of 'data' + _currentLineCharacterIndex += (count - trailingPartStart.Value); + } + + return this; } - public new CSharpCodeWriter SetIndent(int size) + public CSharpCodeWriter WriteLine() { - return (CSharpCodeWriter)base.SetIndent(size); + Builder.Append(NewLine); + + _currentLineIndex++; + _currentLineCharacterIndex = 0; + _absoluteIndex += NewLine.Length; + + _dirty = true; + IsAfterNewLine = true; + + return this; } - public new CSharpCodeWriter IncreaseIndent(int size) + public CSharpCodeWriter WriteLine(string data) { - return (CSharpCodeWriter)base.IncreaseIndent(size); + return Write(data).WriteLine(); } - public new CSharpCodeWriter DecreaseIndent(int size) + public string GenerateCode() { - return (CSharpCodeWriter)base.DecreaseIndent(size); - } + if (_dirty) + { + _cache = Builder.ToString(); + _dirty = false; + } - public new CSharpCodeWriter WriteLine(string data) - { - return (CSharpCodeWriter)base.WriteLine(data); - } - - public new CSharpCodeWriter WriteLine() - { - return (CSharpCodeWriter)base.WriteLine(); + return _cache; } public CSharpCodeWriter WritePadding(int offset, SourceSpan? span, CSharpRenderingContext context) @@ -143,11 +254,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return this; } - public CSharpCodeWriter WriteComment(string comment) - { - return Write("// ").WriteLine(comment); - } - public CSharpCodeWriter WriteBooleanLiteral(bool value) { return Write(value.ToString().ToLowerInvariant()); @@ -168,15 +274,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return Write("new ").Write(typeName).Write("("); } - public CSharpCodeWriter WriteLocationTaggedString(LocationTagged value) - { - WriteStringLiteral(value.Value); - WriteParameterSeparator(); - Write(value.Location.AbsoluteIndex.ToString(CultureInfo.InvariantCulture)); - - return this; - } - public CSharpCodeWriter WriteStringLiteral(string literal) { if (literal.Length >= 256 && literal.Length <= 1500 && literal.IndexOf('\0') == -1) @@ -191,16 +288,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return this; } - public CSharpCodeWriter WriteLineHiddenDirective() - { - return WriteLine("#line hidden"); - } - - public CSharpCodeWriter WritePragma(string value) - { - return Write("#pragma ").WriteLine(value); - } - public CSharpCodeWriter WriteUsing(string name) { return WriteUsing(name, endLine: true); @@ -219,33 +306,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return this; } - public CSharpCodeWriter WriteLineDefaultDirective() - { - return WriteLine("#line default"); - } - - public CSharpCodeWriter WriteStartReturn() - { - return Write("return "); - } - - public CSharpCodeWriter WriteReturn(string value) - { - return WriteReturn(value, endLine: true); - } - - public CSharpCodeWriter WriteReturn(string value, bool endLine) - { - Write("return ").Write(value); - - if (endLine) - { - Write(";"); - } - - return WriteLine(); - } - /// /// Writes a #line pragma directive for the line number at the specified . /// @@ -269,19 +329,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } public CSharpCodeWriter WriteStartMethodInvocation(string methodName) - { - return WriteStartMethodInvocation(methodName, new string[0]); - } - - public CSharpCodeWriter WriteStartMethodInvocation(string methodName, params string[] genericArguments) { Write(methodName); - if (genericArguments.Length > 0) - { - Write("<").Write(string.Join(", ", genericArguments)).Write(">"); - } - return Write("("); } @@ -302,9 +352,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } // Writes a method invocation for the given instance name. - public CSharpCodeWriter WriteInstanceMethodInvocation(string instanceName, - string methodName, - params string[] parameters) + public CSharpCodeWriter WriteInstanceMethodInvocation( + string instanceName, + string methodName, + params string[] parameters) { if (instanceName == null) { @@ -320,10 +371,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } // Writes a method invocation for the given instance name. - public CSharpCodeWriter WriteInstanceMethodInvocation(string instanceName, - string methodName, - bool endLine, - params string[] parameters) + public CSharpCodeWriter WriteInstanceMethodInvocation( + string instanceName, + string methodName, + bool endLine, + params string[] parameters) { if (instanceName == null) { @@ -341,8 +393,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy parameters); } - public CSharpCodeWriter WriteStartInstanceMethodInvocation(string instanceName, - string methodName) + public CSharpCodeWriter WriteStartInstanceMethodInvocation(string instanceName, string methodName) { if (instanceName == null) { @@ -490,27 +541,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return this; } - public CSharpDisableWarningScope BuildDisableWarningScope(int warning) - { - return new CSharpDisableWarningScope(this, warning); - } - public CSharpCodeWritingScope BuildScope() { return new CSharpCodeWritingScope(this); } - public CSharpCodeWritingScope BuildLambda(bool endLine, params string[] parameterNames) + public CSharpCodeWritingScope BuildLambda(params string[] parameterNames) { - return BuildLambda(endLine, async: false, parameterNames: parameterNames); + return BuildLambda(async: false, parameterNames: parameterNames); } - public CSharpCodeWritingScope BuildAsyncLambda(bool endLine, params string[] parameterNames) + public CSharpCodeWritingScope BuildAsyncLambda(params string[] parameterNames) { - return BuildLambda(endLine, async: true, parameterNames: parameterNames); + return BuildLambda(async: true, parameterNames: parameterNames); } - private CSharpCodeWritingScope BuildLambda(bool endLine, bool async, string[] parameterNames) + private CSharpCodeWritingScope BuildLambda(bool async, string[] parameterNames) { if (async) { @@ -521,15 +567,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy var scope = new CSharpCodeWritingScope(this); - if (endLine) - { - // End the lambda with a semicolon - scope.OnClose += () => - { - WriteLine(";"); - }; - } - return scope; } @@ -540,27 +577,35 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return new CSharpCodeWritingScope(this); } - public CSharpCodeWritingScope BuildClassDeclaration(string accessibility, string name) - { - return BuildClassDeclaration(accessibility, name, Enumerable.Empty()); - } - - public CSharpCodeWritingScope BuildClassDeclaration(string accessibility, string name, string baseType) - { - return BuildClassDeclaration(accessibility, name, new string[] { baseType }); - } - public CSharpCodeWritingScope BuildClassDeclaration( string accessibility, string name, - IEnumerable baseTypes) + string baseType, + IEnumerable interfaces) { Write(accessibility).Write(" class ").Write(name); - if (baseTypes.Count() > 0) + var hasBaseType = !string.IsNullOrEmpty(baseType); + var hasInterfaces = interfaces != null && interfaces.Count() > 0; + + if (hasBaseType || hasInterfaces) { Write(" : "); - Write(string.Join(", ", baseTypes)); + + if (hasBaseType) + { + Write(baseType); + + if (hasInterfaces) + { + WriteParameterSeparator(); + } + } + + if (hasInterfaces) + { + Write(string.Join(", ", interfaces)); + } } WriteLine(); @@ -568,36 +613,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return new CSharpCodeWritingScope(this); } - public CSharpCodeWritingScope BuildConstructor(string name) - { - return BuildConstructor("public", name); - } - - public CSharpCodeWritingScope BuildConstructor(string accessibility, string name) - { - return BuildConstructor(accessibility, name, Enumerable.Empty>()); - } - - public CSharpCodeWritingScope BuildConstructor( - string accessibility, - string name, - IEnumerable> parameters) - { - Write(accessibility) - .Write(" ") - .Write(name) - .Write("(") - .Write(string.Join(", ", parameters.Select(p => p.Key + " " + p.Value))) - .WriteLine(")"); - - return new CSharpCodeWritingScope(this); - } - - public CSharpCodeWritingScope BuildMethodDeclaration(string accessibility, string returnType, string name) - { - return BuildMethodDeclaration(accessibility, returnType, name, Enumerable.Empty>()); - } - public CSharpCodeWritingScope BuildMethodDeclaration( string accessibility, string returnType, @@ -707,6 +722,61 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Write("\""); } + public struct CSharpCodeWritingScope : IDisposable + { + private CSharpCodeWriter _writer; + private bool _autoSpace; + private int _tabSize; + private int _startIndent; + + public CSharpCodeWritingScope(CSharpCodeWriter writer, int tabSize = 4, bool autoSpace = true) + { + _writer = writer; + _autoSpace = true; + _tabSize = tabSize; + _startIndent = -1; // Set in WriteStartScope + + WriteStartScope(); + } + + public void Dispose() + { + WriteEndScope(); + } + + private void WriteStartScope() + { + TryAutoSpace(" "); + + _writer.WriteLine("{"); + _writer.CurrentIndent += _tabSize; + _startIndent = _writer.CurrentIndent; + } + + private void WriteEndScope() + { + TryAutoSpace(_writer.NewLine); + + // Ensure the scope hasn't been modified + if (_writer.CurrentIndent == _startIndent) + { + _writer.CurrentIndent -= _tabSize; + } + + _writer.WriteLine("}"); + } + + private void TryAutoSpace(string spaceCharacter) + { + if (_autoSpace && + _writer.Builder.Length > 0 && + !char.IsWhiteSpace(_writer.Builder[_writer.Builder.Length - 1])) + { + _writer.Write(spaceCharacter); + } + } + } + private class LinePragmaWriter : IDisposable { private readonly CSharpCodeWriter _writer; @@ -721,7 +791,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy _writer = writer; _startIndent = _writer.CurrentIndent; - _writer.ResetIndent(); + _writer.CurrentIndent = 0; _writer.WriteLineNumberDirective(documentLocation, documentLocation.FilePath); } @@ -742,9 +812,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } _writer - .WriteLineDefaultDirective() - .WriteLineHiddenDirective() - .SetIndent(_startIndent); + .WriteLine("#line default") + .WriteLine("#line hidden"); + + _writer.CurrentIndent = _startIndent; } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/CSharpRenderingContext.cs b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/CSharpRenderingContext.cs index 24135183ad..f1e0357262 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/CSharpRenderingContext.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/CSharpRenderingContext.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Razor.Language.Intermediate; -using Microsoft.AspNetCore.Razor.Language.Legacy; namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration { @@ -52,7 +51,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var source = node.Source.Value; - var generatedLocation = new SourceSpan(Writer.GetCurrentSourceLocation(), source.Length); + var generatedLocation = new SourceSpan(Writer.Location, source.Length); var lineMapping = new LineMapping(source, generatedLocation); LineMappings.Add(lineMapping); diff --git a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DefaultDocumentWriter.cs b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DefaultDocumentWriter.cs index 99a0bf25be..067bd26fb1 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DefaultDocumentWriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DefaultDocumentWriter.cs @@ -109,55 +109,16 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration public override void VisitNamespaceDeclaration(NamespaceDeclarationIntermediateNode node) { - Context.Writer - .Write("namespace ") - .WriteLine(node.Content); - - using (Context.Writer.BuildScope()) + using (Context.Writer.BuildNamespace(node.Content)) { - Context.Writer.WriteLineHiddenDirective(); + Context.Writer.WriteLine("#line hidden"); RenderChildren(node); } } public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node) { - Context.Writer - .Write(node.AccessModifier) - .Write(" class ") - .Write(node.Name); - - if (node.BaseType != null || node.Interfaces != null) - { - Context.Writer.Write(" : "); - } - - if (node.BaseType != null) - { - Context.Writer.Write(node.BaseType); - - if (node.Interfaces != null) - { - Context.Writer.WriteParameterSeparator(); - } - } - - if (node.Interfaces != null) - { - for (var i = 0; i < node.Interfaces.Count; i++) - { - Context.Writer.Write(node.Interfaces[i]); - - if (i + 1 < node.Interfaces.Count) - { - Context.Writer.WriteParameterSeparator(); - } - } - } - - Context.Writer.WriteLine(); - - using (Context.Writer.BuildScope()) + using (Context.Writer.BuildClassDeclaration(node.AccessModifier, node.Name, node.BaseType, node.Interfaces)) { RenderChildren(node); } diff --git a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DesignTimeDirectiveTargetExtension.cs b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DesignTimeDirectiveTargetExtension.cs index d22795d0d4..97db440718 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DesignTimeDirectiveTargetExtension.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DesignTimeDirectiveTargetExtension.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration public void WriteDesignTimeDirective(CSharpRenderingContext context, DesignTimeDirectiveIntermediateNode node) { context.Writer - .WritePragma("warning disable 219") + .WriteLine("#pragma warning disable 219") .WriteLine($"private void {DirectiveTokenHelperMethodName}() {{"); for (var i = 0; i < node.Children.Count; i++) @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration context.Writer .WriteLine("}") - .WritePragma("warning restore 219"); + .WriteLine("#pragma warning restore 219"); } private void WriteDesignTimeDirectiveToken(CSharpRenderingContext context, DirectiveTokenIntermediateNode node) @@ -48,10 +48,10 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration .Write("((") .Write(typeof(Action).FullName) .Write(")("); - using (context.Writer.BuildLambda(endLine: false)) + using (context.Writer.BuildLambda()) { var originalIndent = context.Writer.CurrentIndent; - context.Writer.ResetIndent(); + context.Writer.CurrentIndent = 0; switch (tokenKind) { case DirectiveTokenKind.Type: @@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration context.Writer.WriteLine(";"); break; } - context.Writer.SetIndent(originalIndent); + context.Writer.CurrentIndent = originalIndent; } context.Writer.WriteLine("))();"); } diff --git a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DesignTimeTagHelperWriter.cs b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DesignTimeTagHelperWriter.cs index f665a9a585..f9a1806156 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DesignTimeTagHelperWriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/DesignTimeTagHelperWriter.cs @@ -44,10 +44,8 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration context.Writer .WriteStartAssignment(tagHelperVariableName) - .WriteStartMethodInvocation( - CreateTagHelperMethodName, - "global::" + node.TagHelperTypeName) - .WriteEndMethodInvocation(); + .Write(CreateTagHelperMethodName) + .WriteLine($"();"); } public override void WriteAddTagHelperHtmlAttribute(CSharpRenderingContext context, AddTagHelperHtmlAttributeIntermediateNode node) diff --git a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeBasicWriter.cs b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeBasicWriter.cs index 7bf08b784b..8ac19bd7be 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeBasicWriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeBasicWriter.cs @@ -252,7 +252,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration context.Writer.WriteStartNewObject(TemplateTypeName); - using (context.Writer.BuildAsyncLambda(endLine: false, parameterNames: ValueWriterName)) + using (context.Writer.BuildAsyncLambda(ValueWriterName)) { BeginWriterScope(context, ValueWriterName); diff --git a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeTagHelperWriter.cs b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeTagHelperWriter.cs index a6efe33d8c..4e8cf6d7f7 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeTagHelperWriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/RuntimeTagHelperWriter.cs @@ -70,15 +70,15 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration public override void WriteDeclareTagHelperFields(CSharpRenderingContext context, DeclareTagHelperFieldsIntermediateNode node) { - context.Writer.WriteLineHiddenDirective(); + context.Writer.WriteLine("#line hidden"); // Need to disable the warning "X is assigned to but never used." for the value buffer since // whether it's used depends on how a TagHelper is used. context.Writer - .WritePragma("warning disable 0414") + .WriteLine("#pragma warning disable 0414") .Write("private ") .WriteVariableDeclaration("string", StringValueBufferVariableName, value: null) - .WritePragma("warning restore 0414"); + .WriteLine("#pragma warning restore 0414"); context.Writer .Write("private ") @@ -131,7 +131,10 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration .WriteEndMethodInvocation(); } - context.Writer.WriteReturn(backedScopeManageVariableName); + context.Writer + .Write("return ") + .Write(backedScopeManageVariableName) + .WriteLine(";"); } } @@ -213,7 +216,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration using (context.Push(new RuntimeBasicWriter())) using (context.Push(new RuntimeTagHelperWriter())) { - using (context.Writer.BuildAsyncLambda(endLine: false)) + using (context.Writer.BuildAsyncLambda()) { context.RenderChildren(node); } @@ -228,10 +231,8 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration context.Writer .WriteStartAssignment(tagHelperVariableName) - .WriteStartMethodInvocation( - CreateTagHelperMethodName, - "global::" + node.TagHelperTypeName) - .WriteEndMethodInvocation(); + .Write(CreateTagHelperMethodName) + .WriteLine($"();"); context.Writer.WriteInstanceMethodInvocation( ExecutionContextVariableName, diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorCSharpLoweringPhase.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorCSharpLoweringPhase.cs index c22fcfa0c0..460f6a3a13 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorCSharpLoweringPhase.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorCSharpLoweringPhase.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Intermediate; -using Microsoft.AspNetCore.Razor.Language.Legacy; namespace Microsoft.AspNetCore.Razor.Language { diff --git a/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionTargetExtension.cs b/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionTargetExtension.cs index 8eef5d8123..74383e319a 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionTargetExtension.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionTargetExtension.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions .Write(node.Name) .Write("\", "); - using (context.Writer.BuildAsyncLambda(endLine: false, parameterNames: writerName)) + using (context.Writer.BuildAsyncLambda(writerName)) { context.RenderChildren(node); } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Extensions/TemplateTargetExtension.cs b/src/Microsoft.AspNetCore.Razor.Language/Extensions/TemplateTargetExtension.cs index 370036616c..24b9d511a3 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Extensions/TemplateTargetExtension.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Extensions/TemplateTargetExtension.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions .Write(ItemParameterName).Write(" => ") .WriteStartNewObject(TemplateTypeName); - using (context.Writer.BuildAsyncLambda(endLine: false, parameterNames: TemplateWriterName)) + using (context.Writer.BuildAsyncLambda(TemplateWriterName)) { context.BasicWriter.BeginWriterScope(context, TemplateWriterName); diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeWritingScope.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeWritingScope.cs deleted file mode 100644 index 1fbe429f6f..0000000000 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeWritingScope.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; - -namespace Microsoft.AspNetCore.Razor.Language.Legacy -{ - public struct CSharpCodeWritingScope : IDisposable - { - private CodeWriter _writer; - private bool _autoSpace; - private int _tabSize; - private int _startIndent; - - public CSharpCodeWritingScope(CodeWriter writer) : this(writer, true) { } - public CSharpCodeWritingScope(CodeWriter writer, int tabSize) : this(writer, tabSize, true) { } - // TODO: Make indents (tabs) environment specific - public CSharpCodeWritingScope(CodeWriter writer, bool autoSpace) : this(writer, 4, autoSpace) { } - public CSharpCodeWritingScope(CodeWriter writer, int tabSize, bool autoSpace) - { - _writer = writer; - _autoSpace = true; - _tabSize = tabSize; - _startIndent = -1; // Set in WriteStartScope - - OnClose = () => { }; - - WriteStartScope(); - } - - public Action OnClose; - - public void Dispose() - { - WriteEndScope(); - OnClose(); - } - - private void WriteStartScope() - { - TryAutoSpace(" "); - - _writer.WriteLine("{").IncreaseIndent(_tabSize); - _startIndent = _writer.CurrentIndent; - } - - private void WriteEndScope() - { - TryAutoSpace(_writer.NewLine); - - // Ensure the scope hasn't been modified - if (_writer.CurrentIndent == _startIndent) - { - _writer.DecreaseIndent(_tabSize); - } - - _writer.WriteLine("}"); - } - - private void TryAutoSpace(string spaceCharacter) - { - if (_autoSpace && - _writer.Builder.Length > 0 && - !char.IsWhiteSpace(_writer.Builder[_writer.Builder.Length - 1])) - { - _writer.Write(spaceCharacter); - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpDisableWarningScope.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpDisableWarningScope.cs deleted file mode 100644 index af9be09a8a..0000000000 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpDisableWarningScope.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNetCore.Razor.Language.Legacy -{ - public struct CSharpDisableWarningScope : IDisposable - { - private CSharpCodeWriter _writer; - int _warningNumber; - - public CSharpDisableWarningScope(CSharpCodeWriter writer) : this(writer, 219) - { } - - public CSharpDisableWarningScope(CSharpCodeWriter writer, int warningNumber) - { - _writer = writer; - _warningNumber = warningNumber; - - _writer.WritePragma("warning disable " + _warningNumber); - } - - public void Dispose() - { - _writer.WritePragma("warning restore " + _warningNumber); - } - } -} diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CodeWriter.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CodeWriter.cs deleted file mode 100644 index fca048f564..0000000000 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CodeWriter.cs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text; - -namespace Microsoft.AspNetCore.Razor.Language.Legacy -{ - public class CodeWriter : IDisposable - { - private static readonly char[] NewLineCharacters = { '\r', '\n' }; - - private string _cache = string.Empty; - private bool _dirty; - - private int _absoluteIndex; - private int _currentLineIndex; - private int _currentLineCharacterIndex; - - public StringBuilder Builder { get; } = new StringBuilder(); - - public int CurrentIndent { get; private set; } - - public bool IsAfterNewLine { get; private set; } - - public string NewLine { get; set; } = Environment.NewLine; - - public CodeWriter ResetIndent() - { - return SetIndent(0); - } - - public CodeWriter IncreaseIndent(int size) - { - CurrentIndent += size; - - return this; - } - - public CodeWriter DecreaseIndent(int size) - { - CurrentIndent -= size; - - return this; - } - - public CodeWriter SetIndent(int size) - { - CurrentIndent = size; - - return this; - } - - public CodeWriter Indent(int size) - { - if (IsAfterNewLine) - { - Builder.Append(' ', size); - - _currentLineCharacterIndex += size; - _absoluteIndex += size; - - _dirty = true; - IsAfterNewLine = false; - } - - return this; - } - - public CodeWriter Write(string data) - { - if (data == null) - { - return this; - } - - return Write(data, 0, data.Length); - } - - public CodeWriter Write(string data, int index, int count) - { - if (data == null || count == 0) - { - return this; - } - - Indent(CurrentIndent); - - Builder.Append(data, index, count); - - _dirty = true; - IsAfterNewLine = false; - - _absoluteIndex += count; - - // The data string might contain a partial newline where the previously - // written string has part of the newline. - var i = index; - int? trailingPartStart = null; - - if ( - // Check the last character of the previous write operation. - Builder.Length - count - 1 >= 0 && - Builder[Builder.Length - count - 1] == '\r' && - - // Check the first character of the current write operation. - Builder[Builder.Length - count] == '\n') - { - // This is newline that's spread across two writes. Skip the first character of the - // current write operation. - // - // We don't need to increment our newline counter because we already did that when we - // saw the \r. - i += 1; - trailingPartStart = 1; - } - - // Iterate the string, stopping at each occurrence of a newline character. This lets us count the - // newline occurrences and keep the index of the last one. - while ((i = data.IndexOfAny(NewLineCharacters, i)) >= 0) - { - // Newline found. - _currentLineIndex++; - _currentLineCharacterIndex = 0; - - i++; - - // We might have stopped at a \r, so check if it's followed by \n and then advance the index to - // start the next search after it. - if (count > i && - data[i - 1] == '\r' && - data[i] == '\n') - { - i++; - } - - // The 'suffix' of the current line starts after this newline token. - trailingPartStart = i; - } - - if (trailingPartStart == null) - { - // No newlines, just add the length of the data buffer - _currentLineCharacterIndex += count; - } - else - { - // Newlines found, add the trailing part of 'data' - _currentLineCharacterIndex += (count - trailingPartStart.Value); - } - - return this; - } - - public CodeWriter WriteLine() - { - Builder.Append(NewLine); - - _currentLineIndex++; - _currentLineCharacterIndex = 0; - _absoluteIndex += NewLine.Length; - - _dirty = true; - IsAfterNewLine = true; - - return this; - } - - public CodeWriter WriteLine(string data) - { - return Write(data).WriteLine(); - } - - public string GenerateCode() - { - if (_dirty) - { - _cache = Builder.ToString(); - _dirty = false; - } - - return _cache; - } - - public SourceLocation GetCurrentSourceLocation() - { - return new SourceLocation(_absoluteIndex, _currentLineIndex, _currentLineCharacterIndex); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - Builder.Clear(); - } - } - - public void Dispose() - { - Dispose(disposing: true); - } - } -} diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/CSharpCodeWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/CSharpCodeWriterTest.cs new file mode 100644 index 0000000000..f0465d4b8d --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/CSharpCodeWriterTest.cs @@ -0,0 +1,360 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration +{ + public class CSharpCodeWriterTest + { + // The length of the newline string written by writer.WriteLine. + private static readonly int WriterNewLineLength = Environment.NewLine.Length; + + public static IEnumerable NewLines + { + get + { + return new object[][] + { + new object[] { "\r" }, + new object[] { "\n" }, + new object[] { "\r\n" }, + }; + } + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithWrite() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("1234"); + + // Assert + var location = writer.Location; + var expected = new SourceLocation(absoluteIndex: 4, lineIndex: 0, characterIndex: 4); + + Assert.Equal(expected, location); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithIndent() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.WriteLine(); + writer.Indent(size: 3); + + // Assert + var location = writer.Location; + var expected = new SourceLocation(absoluteIndex: 3 + WriterNewLineLength, lineIndex: 1, characterIndex: 3); + + Assert.Equal(expected, location); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithWriteLine() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.WriteLine("1234"); + + // Assert + var location = writer.Location; + + var expected = new SourceLocation(absoluteIndex: 4 + WriterNewLineLength, lineIndex: 1, characterIndex: 0); + + Assert.Equal(expected, location); + } + + [Theory] + [MemberData(nameof(NewLines))] + public void CSharpCodeWriter_TracksPosition_WithWriteLine_WithNewLineInContent(string newLine) + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.WriteLine("1234" + newLine + "12"); + + // Assert + var location = writer.Location; + + var expected = new SourceLocation( + absoluteIndex: 6 + newLine.Length + WriterNewLineLength, + lineIndex: 2, + characterIndex: 0); + + Assert.Equal(expected, location); + } + + [Theory] + [MemberData(nameof(NewLines))] + public void CSharpCodeWriter_TracksPosition_WithWrite_WithNewlineInContent(string newLine) + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("1234" + newLine + "123" + newLine + "12"); + + // Assert + var location = writer.Location; + + var expected = new SourceLocation( + absoluteIndex: 9 + newLine.Length + newLine.Length, + lineIndex: 2, + characterIndex: 2); + + Assert.Equal(expected, location); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithWrite_WithNewlineInContent_RepeatedN() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("1234\n\n123"); + + // Assert + var location = writer.Location; + + var expected = new SourceLocation( + absoluteIndex: 9, + lineIndex: 2, + characterIndex: 3); + + Assert.Equal(expected, location); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithWrite_WithMixedNewlineInContent() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("1234\r123\r\n12\n1"); + + // Assert + var location = writer.Location; + + var expected = new SourceLocation( + absoluteIndex: 14, + lineIndex: 3, + characterIndex: 1); + + Assert.Equal(expected, location); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithNewline_SplitAcrossWrites() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("1234\r"); + var location1 = writer.Location; + + writer.Write("\n"); + var location2 = writer.Location; + + // Assert + var expected1 = new SourceLocation(absoluteIndex: 5, lineIndex: 1, characterIndex: 0); + Assert.Equal(expected1, location1); + + var expected2 = new SourceLocation(absoluteIndex: 6, lineIndex: 1, characterIndex: 0); + Assert.Equal(expected2, location2); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithTwoNewline_SplitAcrossWrites_R() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("1234\r"); + var location1 = writer.Location; + + writer.Write("\r"); + var location2 = writer.Location; + + // Assert + var expected1 = new SourceLocation(absoluteIndex: 5, lineIndex: 1, characterIndex: 0); + Assert.Equal(expected1, location1); + + var expected2 = new SourceLocation(absoluteIndex: 6, lineIndex: 2, characterIndex: 0); + Assert.Equal(expected2, location2); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithTwoNewline_SplitAcrossWrites_N() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("1234\n"); + var location1 = writer.Location; + + writer.Write("\n"); + var location2 = writer.Location; + + // Assert + var expected1 = new SourceLocation(absoluteIndex: 5, lineIndex: 1, characterIndex: 0); + Assert.Equal(expected1, location1); + + var expected2 = new SourceLocation(absoluteIndex: 6, lineIndex: 2, characterIndex: 0); + Assert.Equal(expected2, location2); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithTwoNewline_SplitAcrossWrites_Reversed() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("1234\n"); + var location1 = writer.Location; + + writer.Write("\r"); + var location2 = writer.Location; + + // Assert + var expected1 = new SourceLocation(absoluteIndex: 5, lineIndex: 1, characterIndex: 0); + Assert.Equal(expected1, location1); + + var expected2 = new SourceLocation(absoluteIndex: 6, lineIndex: 2, characterIndex: 0); + Assert.Equal(expected2, location2); + } + + [Fact] + public void CSharpCodeWriter_TracksPosition_WithNewline_SplitAcrossWrites_AtBeginning() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.Write("\r"); + var location1 = writer.Location; + + writer.Write("\n"); + var location2 = writer.Location; + + // Assert + var expected1 = new SourceLocation(absoluteIndex: 1, lineIndex: 1, characterIndex: 0); + Assert.Equal(expected1, location1); + + var expected2 = new SourceLocation(absoluteIndex: 2, lineIndex: 1, characterIndex: 0); + Assert.Equal(expected2, location2); + } + + [Fact] + public void WriteLineNumberDirective_UsesFilePath_WhenFileInSourceLocationIsNull() + { + // Arrange + var filePath = "some-path"; + var writer = new CSharpCodeWriter(); + var expected = $"#line 5 \"{filePath}\"" + writer.NewLine; + var sourceLocation = new SourceLocation(10, 4, 3); + var mappingLocation = new SourceSpan(sourceLocation, 9); + + // Act + writer.WriteLineNumberDirective(mappingLocation, filePath); + var code = writer.GenerateCode(); + + // Assert + Assert.Equal(expected, code); + } + + [Theory] + [InlineData("")] + [InlineData("source-location-file-path")] + public void WriteLineNumberDirective_UsesSourceLocationFilePath_IfAvailable( + string sourceLocationFilePath) + { + // Arrange + var filePath = "some-path"; + var writer = new CSharpCodeWriter(); + var expected = $"#line 5 \"{sourceLocationFilePath}\"" + writer.NewLine; + var sourceLocation = new SourceLocation(sourceLocationFilePath, 10, 4, 3); + var mappingLocation = new SourceSpan(sourceLocation, 9); + + // Act + writer.WriteLineNumberDirective(mappingLocation, filePath); + var code = writer.GenerateCode(); + + // Assert + Assert.Equal(expected, code); + } + + [Fact] + public void WriteField_WritesFieldDeclaration() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.WriteField("private", "global::System.String", "_myString"); + + // Assert + var output = writer.GenerateCode(); + Assert.Equal("private global::System.String _myString;" + Environment.NewLine, output); + } + + [Fact] + public void WriteField_WithModifiers_WritesFieldDeclaration() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.WriteField("private", new[] { "readonly", "static" }, "global::System.String", "_myString"); + + // Assert + var output = writer.GenerateCode(); + Assert.Equal("private readonly static global::System.String _myString;" + Environment.NewLine, output); + } + + [Fact] + public void WriteAutoPropertyDeclaration_WritesPropertyDeclaration() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.WriteAutoPropertyDeclaration("public", "global::System.String", "MyString"); + + // Assert + var output = writer.GenerateCode(); + Assert.Equal("public global::System.String MyString { get; set; }" + Environment.NewLine, output); + } + + [Fact] + public void WriteAutoPropertyDeclaration_WithModifiers_WritesPropertyDeclaration() + { + // Arrange + var writer = new CSharpCodeWriter(); + + // Act + writer.WriteAutoPropertyDeclaration("public", new[] { "static" }, "global::System.String", "MyString"); + + // Assert + var output = writer.GenerateCode(); + Assert.Equal("public static global::System.String MyString { get; set; }" + Environment.NewLine, output); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DefaultDocumentWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DefaultDocumentWriterTest.cs index b6e4c24b0a..507223059e 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DefaultDocumentWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DefaultDocumentWriterTest.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var context = new CSharpRenderingContext() { Options = options, - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), CodeDocument = codeDocument }; @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var context = new CSharpRenderingContext() { Options = options, - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), CodeDocument = codeDocument }; @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var context = new CSharpRenderingContext() { Options = options, - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), CodeDocument = codeDocument }; @@ -124,7 +124,7 @@ namespace TestNamespace var context = new CSharpRenderingContext() { Options = options, - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), CodeDocument = codeDocument }; var writer = new DefaultDocumentWriter(target, context); @@ -165,7 +165,7 @@ internal class TestClass : TestBase, IFoo, IBar var context = new CSharpRenderingContext() { Options = options, - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), CodeDocument = codeDocument }; var writer = new DefaultDocumentWriter(target, context); @@ -208,7 +208,7 @@ internal virtual async string TestMethod() var context = new CSharpRenderingContext() { Options = options, - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), CodeDocument = codeDocument }; var writer = new DefaultDocumentWriter(target, context); @@ -247,7 +247,7 @@ internal readonly string _foo; var context = new CSharpRenderingContext() { Options = options, - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), CodeDocument = codeDocument }; var writer = new DefaultDocumentWriter(target, context); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeBasicWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeBasicWriterTest.cs index 211bee2ac2..262a75e089 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeBasicWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeBasicWriterTest.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var writer = new DesignTimeBasicWriter(); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter() + Writer = new CSharpCodeWriter() }; var node = new UsingStatementIntermediateNode() @@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var sourceDocument = TestRazorSourceDocument.Create("@using System;"); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), CodeDocument = RazorCodeDocument.Create(sourceDocument) }; @@ -85,7 +85,7 @@ using System; var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode(); @@ -117,7 +117,7 @@ using System; var context = new CSharpRenderingContext() { Options = RazorCodeGenerationOptions.CreateDefault(), - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode() @@ -155,7 +155,7 @@ __o = i++; var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode(); @@ -197,7 +197,7 @@ __o = i++; { Options = RazorCodeGenerationOptions.CreateDefault(), CodeDocument = RazorCodeDocument.Create(sourceDocument), - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode() @@ -243,7 +243,7 @@ __o = i++; var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpCodeIntermediateNode(); @@ -270,7 +270,7 @@ __o = i++; var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), Options = RazorCodeGenerationOptions.CreateDefault(), }; @@ -305,7 +305,7 @@ __o = i++; var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpCodeIntermediateNode(); @@ -336,7 +336,7 @@ __o = i++; var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), Options = RazorCodeGenerationOptions.CreateDefault(), }; @@ -375,7 +375,7 @@ if (true) { } var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), Options = RazorCodeGenerationOptions.CreateDefault(), }; @@ -502,7 +502,7 @@ Render Node - CSharpExpressionIntermediateNode private static CSharpRenderingContext GetCSharpRenderingContext(BasicWriter writer) { var options = RazorCodeGenerationOptions.CreateDefault(); - var codeWriter = new Legacy.CSharpCodeWriter(); + var codeWriter = new CSharpCodeWriter(); var context = new CSharpRenderingContext() { Writer = codeWriter, diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeTagHelperWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeTagHelperWriterTest.cs index 85a8a9df99..035c77834f 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeTagHelperWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeTagHelperWriterTest.cs @@ -196,7 +196,7 @@ __InputTagHelper.FooProp[""bound""] = 42; private static CSharpRenderingContext GetCSharpRenderingContext(TagHelperWriter writer, RazorCodeDocument codeDocument = null) { var options = RazorCodeGenerationOptions.CreateDefault(); - var codeWriter = new Legacy.CSharpCodeWriter(); + var codeWriter = new CSharpCodeWriter(); var context = new CSharpRenderingContext() { Writer = codeWriter, diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/LiteralRuntimeBasicWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/LiteralRuntimeBasicWriterTest.cs index 811ecae196..86c0f983a8 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/LiteralRuntimeBasicWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/LiteralRuntimeBasicWriterTest.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var context = new CSharpRenderingContext() { Options = RazorCodeGenerationOptions.CreateDefault(), - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode() diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeBasicWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeBasicWriterTest.cs index b853eefddf..01043e5a83 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeBasicWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeBasicWriterTest.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var writer = new RuntimeBasicWriter(); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter() + Writer = new CSharpCodeWriter() }; var node = new UsingStatementIntermediateNode() @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration var writer = new RuntimeBasicWriter(); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter() + Writer = new CSharpCodeWriter() }; var node = new UsingStatementIntermediateNode() @@ -81,7 +81,7 @@ using System; var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode(); @@ -116,7 +116,7 @@ using System; var context = new CSharpRenderingContext() { Options = RazorCodeGenerationOptions.CreateDefault(), - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode() @@ -157,7 +157,7 @@ Test(i++); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode(); @@ -202,7 +202,7 @@ Test(i++); { Options = RazorCodeGenerationOptions.CreateDefault(), CodeDocument = RazorCodeDocument.Create(sourceDocument), - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpExpressionIntermediateNode() @@ -248,7 +248,7 @@ Test(i++); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpCodeIntermediateNode(); @@ -275,7 +275,7 @@ Test(i++); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), }; var node = new CSharpCodeIntermediateNode(); @@ -306,7 +306,7 @@ Test(i++); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), Options = RazorCodeGenerationOptions.CreateDefault(), }; @@ -345,7 +345,7 @@ if (true) { } var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), Options = RazorCodeGenerationOptions.CreateDefault(), }; @@ -383,7 +383,7 @@ if (true) { } var writer = new RuntimeBasicWriter(); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), Options = RazorCodeGenerationOptions.CreateDefault(), }; @@ -413,7 +413,7 @@ if (true) { } var writer = new RuntimeBasicWriter(); var context = new CSharpRenderingContext() { - Writer = new Legacy.CSharpCodeWriter(), + Writer = new CSharpCodeWriter(), Options = RazorCodeGenerationOptions.CreateDefault(), }; @@ -601,7 +601,7 @@ WriteAttributeValue("" "", 27, false, 28, 6, false); private static CSharpRenderingContext GetCSharpRenderingContext(BasicWriter writer) { var options = RazorCodeGenerationOptions.CreateDefault(); - var codeWriter = new Legacy.CSharpCodeWriter(); + var codeWriter = new CSharpCodeWriter(); var context = new CSharpRenderingContext() { Writer = codeWriter, diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeTagHelperWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeTagHelperWriterTest.cs index 32411dbd3f..d0da4dcb11 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeTagHelperWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeTagHelperWriterTest.cs @@ -433,7 +433,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelpe private static CSharpRenderingContext GetCSharpRenderingContext(TagHelperWriter writer, RazorCodeDocument codeDocument = null) { var options = RazorCodeGenerationOptions.CreateDefault(); - var codeWriter = new Legacy.CSharpCodeWriter(); + var codeWriter = new CSharpCodeWriter(); var context = new CSharpRenderingContext() { Writer = codeWriter, diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/TagHelperHtmlAttributeRuntimeBasicWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/TagHelperHtmlAttributeRuntimeBasicWriterTest.cs index 6d07b210bd..056eb71ae0 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/TagHelperHtmlAttributeRuntimeBasicWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/TagHelperHtmlAttributeRuntimeBasicWriterTest.cs @@ -98,7 +98,7 @@ AddHtmlAttributeValue("" "", 27, false, 28, 6, false); private static CSharpRenderingContext GetCSharpRenderingContext(BasicWriter writer) { var options = RazorCodeGenerationOptions.CreateDefault(); - var codeWriter = new Legacy.CSharpCodeWriter(); + var codeWriter = new CSharpCodeWriter(); var context = new CSharpRenderingContext() { Writer = codeWriter, diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpCodeWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpCodeWriterTest.cs deleted file mode 100644 index cb5b385d4d..0000000000 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpCodeWriterTest.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Xunit; - -namespace Microsoft.AspNetCore.Razor.Language.Legacy -{ - public class CSharpCodeWriterTest - { - [Fact] - public void WriteLineNumberDirective_UsesFilePath_WhenFileInSourceLocationIsNull() - { - // Arrange - var filePath = "some-path"; - var writer = new CSharpCodeWriter(); - var expected = $"#line 5 \"{filePath}\"" + writer.NewLine; - var sourceLocation = new SourceLocation(10, 4, 3); - var mappingLocation = new SourceSpan(sourceLocation, 9); - - // Act - writer.WriteLineNumberDirective(mappingLocation, filePath); - var code = writer.GenerateCode(); - - // Assert - Assert.Equal(expected, code); - } - - [Theory] - [InlineData("")] - [InlineData("source-location-file-path")] - public void WriteLineNumberDirective_UsesSourceLocationFilePath_IfAvailable( - string sourceLocationFilePath) - { - // Arrange - var filePath = "some-path"; - var writer = new CSharpCodeWriter(); - var expected = $"#line 5 \"{sourceLocationFilePath}\"" + writer.NewLine; - var sourceLocation = new SourceLocation(sourceLocationFilePath, 10, 4, 3); - var mappingLocation = new SourceSpan(sourceLocation, 9); - - // Act - writer.WriteLineNumberDirective(mappingLocation, filePath); - var code = writer.GenerateCode(); - - // Assert - Assert.Equal(expected, code); - } - - [Fact] - public void WriteField_WritesFieldDeclaration() - { - // Arrange - var writer = new CSharpCodeWriter(); - - // Act - writer.WriteField("private", "global::System.String", "_myString"); - - // Assert - var output = writer.GenerateCode(); - Assert.Equal("private global::System.String _myString;" + Environment.NewLine, output); - } - - [Fact] - public void WriteField_WithModifiers_WritesFieldDeclaration() - { - // Arrange - var writer = new CSharpCodeWriter(); - - // Act - writer.WriteField("private", new[] { "readonly", "static" }, "global::System.String", "_myString"); - - // Assert - var output = writer.GenerateCode(); - Assert.Equal("private readonly static global::System.String _myString;" + Environment.NewLine, output); - } - - [Fact] - public void WriteAutoPropertyDeclaration_WritesPropertyDeclaration() - { - // Arrange - var writer = new CSharpCodeWriter(); - - // Act - writer.WriteAutoPropertyDeclaration("public", "global::System.String", "MyString"); - - // Assert - var output = writer.GenerateCode(); - Assert.Equal("public global::System.String MyString { get; set; }" + Environment.NewLine, output); - } - - [Fact] - public void WriteAutoPropertyDeclaration_WithModifiers_WritesPropertyDeclaration() - { - // Arrange - var writer = new CSharpCodeWriter(); - - // Act - writer.WriteAutoPropertyDeclaration("public", new[] { "static" }, "global::System.String", "MyString"); - - // Assert - var output = writer.GenerateCode(); - Assert.Equal("public static global::System.String MyString { get; set; }" + Environment.NewLine, output); - } - } -} diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CodeWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CodeWriterTest.cs deleted file mode 100644 index 8bc5188a4d..0000000000 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CodeWriterTest.cs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using Xunit; - -namespace Microsoft.AspNetCore.Razor.Language.Legacy -{ - public class CodeWriterTest - { - // The length of the newline string written by writer.WriteLine. - private static readonly int WriterNewLineLength = Environment.NewLine.Length; - - public static IEnumerable NewLines - { - get - { - return new object[][] - { - new object[] { "\r" }, - new object[] { "\n" }, - new object[] { "\r\n" }, - }; - } - } - - [Fact] - public void CodeWriter_TracksPosition_WithWrite() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("1234"); - - // Assert - var location = writer.GetCurrentSourceLocation(); - var expected = new SourceLocation(absoluteIndex: 4, lineIndex: 0, characterIndex: 4); - - Assert.Equal(expected, location); - } - - [Fact] - public void CodeWriter_TracksPosition_WithIndent() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.WriteLine(); - writer.Indent(size: 3); - - // Assert - var location = writer.GetCurrentSourceLocation(); - var expected = new SourceLocation(absoluteIndex: 3 + WriterNewLineLength, lineIndex: 1, characterIndex: 3); - - Assert.Equal(expected, location); - } - - [Fact] - public void CodeWriter_TracksPosition_WithWriteLine() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.WriteLine("1234"); - - // Assert - var location = writer.GetCurrentSourceLocation(); - - var expected = new SourceLocation(absoluteIndex: 4 + WriterNewLineLength, lineIndex: 1, characterIndex: 0); - - Assert.Equal(expected, location); - } - - [Theory] - [MemberData(nameof(NewLines))] - public void CodeWriter_TracksPosition_WithWriteLine_WithNewLineInContent(string newLine) - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.WriteLine("1234" + newLine + "12"); - - // Assert - var location = writer.GetCurrentSourceLocation(); - - var expected = new SourceLocation( - absoluteIndex: 6 + newLine.Length + WriterNewLineLength, - lineIndex: 2, - characterIndex: 0); - - Assert.Equal(expected, location); - } - - [Theory] - [MemberData(nameof(NewLines))] - public void CodeWriter_TracksPosition_WithWrite_WithNewlineInContent(string newLine) - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("1234" + newLine + "123" + newLine + "12"); - - // Assert - var location = writer.GetCurrentSourceLocation(); - - var expected = new SourceLocation( - absoluteIndex: 9 + newLine.Length + newLine.Length, - lineIndex: 2, - characterIndex: 2); - - Assert.Equal(expected, location); - } - - [Fact] - public void CodeWriter_TracksPosition_WithWrite_WithNewlineInContent_RepeatedN() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("1234\n\n123"); - - // Assert - var location = writer.GetCurrentSourceLocation(); - - var expected = new SourceLocation( - absoluteIndex: 9, - lineIndex: 2, - characterIndex: 3); - - Assert.Equal(expected, location); - } - - [Fact] - public void CodeWriter_TracksPosition_WithWrite_WithMixedNewlineInContent() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("1234\r123\r\n12\n1"); - - // Assert - var location = writer.GetCurrentSourceLocation(); - - var expected = new SourceLocation( - absoluteIndex: 14, - lineIndex: 3, - characterIndex: 1); - - Assert.Equal(expected, location); - } - - [Fact] - public void CodeWriter_TracksPosition_WithNewline_SplitAcrossWrites() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("1234\r"); - var location1 = writer.GetCurrentSourceLocation(); - - writer.Write("\n"); - var location2 = writer.GetCurrentSourceLocation(); - - // Assert - var expected1 = new SourceLocation(absoluteIndex: 5, lineIndex: 1, characterIndex: 0); - Assert.Equal(expected1, location1); - - var expected2 = new SourceLocation(absoluteIndex: 6, lineIndex: 1, characterIndex: 0); - Assert.Equal(expected2, location2); - } - - [Fact] - public void CodeWriter_TracksPosition_WithTwoNewline_SplitAcrossWrites_R() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("1234\r"); - var location1 = writer.GetCurrentSourceLocation(); - - writer.Write("\r"); - var location2 = writer.GetCurrentSourceLocation(); - - // Assert - var expected1 = new SourceLocation(absoluteIndex: 5, lineIndex: 1, characterIndex: 0); - Assert.Equal(expected1, location1); - - var expected2 = new SourceLocation(absoluteIndex: 6, lineIndex: 2, characterIndex: 0); - Assert.Equal(expected2, location2); - } - - [Fact] - public void CodeWriter_TracksPosition_WithTwoNewline_SplitAcrossWrites_N() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("1234\n"); - var location1 = writer.GetCurrentSourceLocation(); - - writer.Write("\n"); - var location2 = writer.GetCurrentSourceLocation(); - - // Assert - var expected1 = new SourceLocation(absoluteIndex: 5, lineIndex: 1, characterIndex: 0); - Assert.Equal(expected1, location1); - - var expected2 = new SourceLocation(absoluteIndex: 6, lineIndex: 2, characterIndex: 0); - Assert.Equal(expected2, location2); - } - - [Fact] - public void CodeWriter_TracksPosition_WithTwoNewline_SplitAcrossWrites_Reversed() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("1234\n"); - var location1 = writer.GetCurrentSourceLocation(); - - writer.Write("\r"); - var location2 = writer.GetCurrentSourceLocation(); - - // Assert - var expected1 = new SourceLocation(absoluteIndex: 5, lineIndex: 1, characterIndex: 0); - Assert.Equal(expected1, location1); - - var expected2 = new SourceLocation(absoluteIndex: 6, lineIndex: 2, characterIndex: 0); - Assert.Equal(expected2, location2); - } - - [Fact] - public void CodeWriter_TracksPosition_WithNewline_SplitAcrossWrites_AtBeginning() - { - // Arrange - var writer = new CodeWriter(); - - // Act - writer.Write("\r"); - var location1 = writer.GetCurrentSourceLocation(); - - writer.Write("\n"); - var location2 = writer.GetCurrentSourceLocation(); - - // Assert - var expected1 = new SourceLocation(absoluteIndex: 1, lineIndex: 1, characterIndex: 0); - Assert.Equal(expected1, location1); - - var expected2 = new SourceLocation(absoluteIndex: 2, lineIndex: 1, characterIndex: 0); - Assert.Equal(expected2, location2); - } - } -}