Remove CodeDOM from net45 Razor.

Removed all System.CodeDOM related code from net45.  This involved modifying some existing code paths and most of all reducing the complexity of all of the CodeGenerators.  Added some factory creation methods to build CodeBuilders.  Ran code analysis and made adjustments to pass analysis.
This commit is contained in:
N. Taylor Mullen 2014-03-13 12:48:28 -07:00
parent 10c10ab2e7
commit b1c49a2535
41 changed files with 109 additions and 2427 deletions

View File

@ -1,12 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
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;
#if NET45
using Microsoft.CSharp;
#endif
namespace Microsoft.AspNet.Razor
@ -25,17 +24,7 @@ namespace Microsoft.AspNet.Razor
{
get { return CSharpLanguageName; }
}
#if NET45
// No CodeDOM in CoreCLR
/// <summary>
/// Returns the type of the CodeDOM provider for this language
/// </summary>
public override Type CodeDomProviderType
{
get { return typeof(CSharpCodeProvider); }
}
#endif
/// <summary>
/// Constructs a new instance of the code parser for this language
/// </summary>
@ -52,7 +41,7 @@ namespace Microsoft.AspNet.Razor
return new CSharpRazorCodeGenerator(className, rootNamespaceName, sourceFileName, host);
}
public override CodeBuilder CreateBuilder(CodeGeneratorContext codeGeneratorContext)
public override CodeBuilder CreateCodeBuilder(CodeGeneratorContext codeGeneratorContext)
{
return new CSharpCodeBuilder(codeGeneratorContext);
}

View File

@ -1,9 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using System.Linq;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
@ -20,49 +17,16 @@ namespace Microsoft.AspNet.Razor.Generator
public string Namespace { get; private set; }
public int NamespaceKeywordLength { get; set; }
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
string ns = Namespace;
if (!String.IsNullOrEmpty(ns) && Char.IsWhiteSpace(ns[0]))
{
ns = ns.Substring(1);
}
codeTreeBuilder.AddUsingChunk(ns, target);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM in CoreCLR.
// #if'd the entire section because once we transition over to the CodeTree we will not need all this code.
// Try to find the namespace in the existing imports
string ns = Namespace;
if (!String.IsNullOrEmpty(ns) && Char.IsWhiteSpace(ns[0]))
{
ns = ns.Substring(1);
}
CodeNamespaceImport import = context.Namespace
.Imports
.OfType<CodeNamespaceImport>()
.Where(i => String.Equals(i.Namespace, ns.Trim(), StringComparison.Ordinal))
.FirstOrDefault();
if (import == null)
{
// It doesn't exist, create it
import = new CodeNamespaceImport(ns);
context.Namespace.Imports.Add(import);
}
// Attach our info to the existing/new import.
import.LinePragma = context.GenerateLinePragma(target);
#endif
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.AddUsingChunk(ns, target);
}
public override string ToString()

View File

@ -22,76 +22,18 @@ namespace Microsoft.AspNet.Razor.Generator
public LocationTagged<string> Prefix { get; private set; }
public LocationTagged<string> Suffix { get; private set; }
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
CodeAttributeChunk chunk = codeTreeBuilder.StartChunkBlock<CodeAttributeChunk>(target);
var chunk = context.CodeTreeBuilder.StartChunkBlock<CodeAttributeChunk>(target);
chunk.Attribute = Name;
chunk.Prefix = Prefix;
chunk.Suffix = Suffix;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM in CoreCLR.
// #if'd the entire section because once we transition over to the CodeTree we will not need all this code.
if (context.Host.DesignTimeMode)
{
return; // Don't generate anything!
}
context.FlushBufferedStatement();
context.AddStatement(context.BuildCodeString(cw =>
{
if (!String.IsNullOrEmpty(context.TargetWriterName))
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.WriteAttributeToMethodName);
cw.WriteSnippet(context.TargetWriterName);
cw.WriteParameterSeparator();
}
else
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.WriteAttributeMethodName);
}
cw.WriteStringLiteral(Name);
cw.WriteParameterSeparator();
cw.WriteLocationTaggedString(Prefix);
cw.WriteParameterSeparator();
cw.WriteLocationTaggedString(Suffix);
}));
#endif
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM in CoreCLR (AddStatement and FlushBufferedStatement etc. utilize it).
// #if'd the entire section because once we transition over to the CodeTree we will not need all this code.
if (context.Host.DesignTimeMode)
{
return; // Don't generate anything!
}
context.FlushBufferedStatement();
context.AddStatement(context.BuildCodeString(cw =>
{
cw.WriteEndMethodInvoke();
cw.WriteEndStatement();
}));
#endif
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.EndChunkBlock();
}
public override string ToString()

View File

@ -1,77 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNet.Razor.Generator
{
internal abstract class BaseCodeWriter : CodeWriter
{
public override void WriteSnippet(string snippet)
{
InnerWriter.Write(snippet);
}
protected internal override void EmitStartMethodInvoke(string methodName)
{
EmitStartMethodInvoke(methodName, new string[0]);
}
protected internal override void EmitStartMethodInvoke(string methodName, params string[] genericArguments)
{
InnerWriter.Write(methodName);
if (genericArguments != null && genericArguments.Length > 0)
{
WriteStartGenerics();
for (int i = 0; i < genericArguments.Length; i++)
{
if (i > 0)
{
WriteParameterSeparator();
}
WriteSnippet(genericArguments[i]);
}
WriteEndGenerics();
}
InnerWriter.Write("(");
}
protected internal override void EmitEndMethodInvoke()
{
InnerWriter.Write(")");
}
protected internal override void EmitEndConstructor()
{
InnerWriter.Write(")");
}
protected internal override void EmitEndLambdaExpression()
{
}
public override void WriteParameterSeparator()
{
InnerWriter.Write(", ");
}
protected internal void WriteCommaSeparatedList<T>(T[] items, Action<T> writeItemAction)
{
for (int i = 0; i < items.Length; i++)
{
if (i > 0)
{
InnerWriter.Write(", ");
}
writeItemAction(items[i]);
}
}
protected internal virtual void WriteStartGenerics()
{
}
protected internal virtual void WriteEndGenerics()
{
}
}
}

View File

@ -1,250 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace Microsoft.AspNet.Razor.Generator
{
internal class CSharpCodeWriter : BaseCodeWriter
{
protected internal override void WriteStartGenerics()
{
InnerWriter.Write("<");
}
protected internal override void WriteEndGenerics()
{
InnerWriter.Write(">");
}
public override int WriteVariableDeclaration(string type, string name, string value)
{
InnerWriter.Write(type);
InnerWriter.Write(" ");
InnerWriter.Write(name);
if (!String.IsNullOrEmpty(value))
{
InnerWriter.Write(" = ");
InnerWriter.Write(value);
}
else
{
InnerWriter.Write(" = null");
}
return 0;
}
public override void WriteDisableUnusedFieldWarningPragma()
{
InnerWriter.Write("#pragma warning disable 219");
}
public override void WriteRestoreUnusedFieldWarningPragma()
{
InnerWriter.Write("#pragma warning restore 219");
}
public override void WriteStringLiteral(string literal)
{
if (literal == null)
{
throw new ArgumentNullException("literal");
}
// From CSharpCodeProvider in CodeDOM
// If the string is short, use C style quoting (e.g "\r\n")
// Also do it if it is too long to fit in one line
// If the string contains '\0', verbatim style won't work.
if (literal.Length >= 256 && literal.Length <= 1500 && literal.IndexOf('\0') == -1)
{
WriteVerbatimStringLiteral(literal);
}
else
{
WriteCStyleStringLiteral(literal);
}
}
private void WriteVerbatimStringLiteral(string literal)
{
// From CSharpCodeGenerator.QuoteSnippetStringVerbatim in CodeDOM
InnerWriter.Write("@\"");
for (int i = 0; i < literal.Length; i++)
{
if (literal[i] == '\"')
{
InnerWriter.Write("\"\"");
}
else
{
InnerWriter.Write(literal[i]);
}
}
InnerWriter.Write("\"");
}
private void WriteCStyleStringLiteral(string literal)
{
// From CSharpCodeGenerator.QuoteSnippetStringCStyle in CodeDOM
InnerWriter.Write("\"");
for (int i = 0; i < literal.Length; i++)
{
switch (literal[i])
{
case '\r':
InnerWriter.Write("\\r");
break;
case '\t':
InnerWriter.Write("\\t");
break;
case '\"':
InnerWriter.Write("\\\"");
break;
case '\'':
InnerWriter.Write("\\\'");
break;
case '\\':
InnerWriter.Write("\\\\");
break;
case '\0':
InnerWriter.Write("\\\0");
break;
case '\n':
InnerWriter.Write("\\n");
break;
case '\u2028':
case '\u2029':
// Inlined CSharpCodeGenerator.AppendEscapedChar
InnerWriter.Write("\\u");
InnerWriter.Write(((int)literal[i]).ToString("X4", CultureInfo.InvariantCulture));
break;
default:
InnerWriter.Write(literal[i]);
break;
}
if (i > 0 && i % 80 == 0)
{
// If current character is a high surrogate and the following
// character is a low surrogate, don't break them.
// Otherwise when we write the string to a file, we might lose
// the characters.
if (Char.IsHighSurrogate(literal[i])
&& (i < literal.Length - 1)
&& Char.IsLowSurrogate(literal[i + 1]))
{
InnerWriter.Write(literal[++i]);
}
InnerWriter.Write("\" +");
InnerWriter.Write(Environment.NewLine);
InnerWriter.Write('\"');
}
}
InnerWriter.Write("\"");
}
public override void WriteEndStatement()
{
InnerWriter.WriteLine(";");
}
public override void WriteIdentifier(string identifier)
{
InnerWriter.Write("@" + identifier);
}
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Lowercase is intended here. C# boolean literals are all lowercase")]
public override void WriteBooleanLiteral(bool value)
{
WriteSnippet(value.ToString().ToLowerInvariant());
}
protected internal override void EmitStartLambdaExpression(string[] parameterNames)
{
if (parameterNames == null)
{
throw new ArgumentNullException("parameterNames");
}
if (parameterNames.Length == 0 || parameterNames.Length > 1)
{
InnerWriter.Write("(");
}
WriteCommaSeparatedList(parameterNames, InnerWriter.Write);
if (parameterNames.Length == 0 || parameterNames.Length > 1)
{
InnerWriter.Write(")");
}
InnerWriter.Write(" => ");
}
protected internal override void EmitStartLambdaDelegate(string[] parameterNames)
{
if (parameterNames == null)
{
throw new ArgumentNullException("parameterNames");
}
EmitStartLambdaExpression(parameterNames);
InnerWriter.WriteLine("{");
}
protected internal override void EmitEndLambdaDelegate()
{
InnerWriter.Write("}");
}
protected internal override void EmitStartConstructor(string typeName)
{
if (typeName == null)
{
throw new ArgumentNullException("typeName");
}
InnerWriter.Write("new ");
InnerWriter.Write(typeName);
InnerWriter.Write("(");
}
public override void WriteReturn()
{
InnerWriter.Write("return ");
}
public override void WriteLinePragma(int? lineNumber, string fileName)
{
InnerWriter.WriteLine();
if (lineNumber != null)
{
InnerWriter.Write("#line ");
InnerWriter.Write(lineNumber);
InnerWriter.Write(" \"");
InnerWriter.Write(fileName);
InnerWriter.Write("\"");
InnerWriter.WriteLine();
}
else
{
InnerWriter.WriteLine("#line default");
InnerWriter.WriteLine("#line hidden");
}
}
public override void WriteHiddenLinePragma()
{
InnerWriter.WriteLine("#line hidden");
}
public override void WriteHelperHeaderPrefix(string templateTypeName, bool isStatic)
{
InnerWriter.Write("public ");
if (isStatic)
{
InnerWriter.Write("static ");
}
InnerWriter.Write(templateTypeName);
InnerWriter.Write(" ");
}
}
}

View File

@ -1,35 +1,19 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.AspNet.Razor.Generator
{
public class CSharpRazorCodeGenerator : RazorCodeGenerator
{
private const string HiddenLinePragma = "#line hidden";
public CSharpRazorCodeGenerator(string className, string rootNamespaceName, string sourceFileName, RazorEngineHost host)
: base(className, rootNamespaceName, sourceFileName, host)
{
}
internal override Func<CodeWriter> CodeWriterFactory
{
get { return () => new CSharpCodeWriter(); }
}
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.CodeDom.CodeSnippetTypeMember.#ctor(System.String)", Justification = "Value is never to be localized")]
protected override void Initialize(CodeGeneratorContext context)
{
base.Initialize(context);
#if NET45
// No CodeDOM in CoreCLR.
// #if'd the entire section because once we transition over to the CodeTree we will not need all this code.
context.GeneratedClass.Members.Insert(0, new CodeSnippetTypeMember(HiddenLinePragma));
#endif
}
}
}

View File

@ -1,24 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Text;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Utils;
namespace Microsoft.AspNet.Razor.Generator
{
public class CodeGeneratorContext
{
internal const string DesignTimeHelperMethodName = "__RazorDesignTimeHelpers__";
private CodeGeneratorContext()
{
ExpressionRenderingMode = ExpressionRenderingMode.WriteToOutput;
@ -30,281 +17,6 @@ namespace Microsoft.AspNet.Razor.Generator
public string SourceFile { get; internal set; }
public string RootNamespace { get; private set; }
public string ClassName { get; private set; }
#region deletable
#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
private int _nextDesignTimePragmaId = 1;
private bool _expressionHelperVariableWriten;
private CodeMemberMethod _designTimeHelperMethod;
private StatementBuffer _currentBuffer = new StatementBuffer();
private Action<string, CodeLinePragma> StatementCollector { get; set; }
private Func<CodeWriter> CodeWriterFactory { get; set; }
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<int, GeneratedCodeMapping> CodeMappings { get; private set; }
public string CurrentBufferedStatement
{
get { return _currentBuffer == null ? String.Empty : _currentBuffer.Builder.ToString(); }
}
public void AddDesignTimeHelperStatement(CodeSnippetStatement statement)
{
if (_designTimeHelperMethod == null)
{
_designTimeHelperMethod = new CodeMemberMethod()
{
Name = DesignTimeHelperMethodName,
Attributes = MemberAttributes.Private
};
_designTimeHelperMethod.Statements.Add(
new CodeSnippetStatement(BuildCodeString(cw => cw.WriteDisableUnusedFieldWarningPragma())));
_designTimeHelperMethod.Statements.Add(
new CodeSnippetStatement(BuildCodeString(cw => cw.WriteRestoreUnusedFieldWarningPragma())));
GeneratedClass.Members.Insert(0, _designTimeHelperMethod);
}
_designTimeHelperMethod.Statements.Insert(_designTimeHelperMethod.Statements.Count - 1, statement);
}
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow", MessageId = "generatedCodeStart+1", Justification = "There is no risk of overflow in this case")]
public int AddCodeMapping(SourceLocation sourceLocation, int generatedCodeStart, int generatedCodeLength)
{
if (generatedCodeStart == Int32.MaxValue)
{
throw new ArgumentOutOfRangeException("generatedCodeStart");
}
GeneratedCodeMapping mapping = new GeneratedCodeMapping(
startOffset: sourceLocation.AbsoluteIndex,
startLine: sourceLocation.LineIndex + 1,
startColumn: sourceLocation.CharacterIndex + 1,
startGeneratedColumn: generatedCodeStart + 1,
codeLength: generatedCodeLength);
int id = _nextDesignTimePragmaId++;
CodeMappings[id] = mapping;
return id;
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This method requires that a Span be provided")]
public CodeLinePragma GenerateLinePragma(Span target)
{
return GenerateLinePragma(target, 0);
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This method requires that a Span be provided")]
public CodeLinePragma GenerateLinePragma(Span target, int generatedCodeStart)
{
return GenerateLinePragma(target, generatedCodeStart, target.Content.Length);
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This method requires that a Span be provided")]
public CodeLinePragma GenerateLinePragma(Span target, int generatedCodeStart, int codeLength)
{
return GenerateLinePragma(target.Start, generatedCodeStart, codeLength);
}
public CodeLinePragma GenerateLinePragma(SourceLocation start, int generatedCodeStart, int codeLength)
{
if (!String.IsNullOrEmpty(SourceFile))
{
if (Host.DesignTimeMode)
{
int mappingId = AddCodeMapping(start, generatedCodeStart, codeLength);
return new CodeLinePragma(SourceFile, mappingId);
}
return new CodeLinePragma(SourceFile, start.LineIndex + 1);
}
return null;
}
public void BufferStatementFragment(Span sourceSpan)
{
BufferStatementFragment(sourceSpan.Content, sourceSpan);
}
public void BufferStatementFragment(string fragment)
{
BufferStatementFragment(fragment, null);
}
public void BufferStatementFragment(string fragment, Span sourceSpan)
{
if (sourceSpan != null && _currentBuffer.LinePragmaSpan == null)
{
_currentBuffer.LinePragmaSpan = sourceSpan;
// Pad the output as necessary
int start = _currentBuffer.Builder.Length;
if (_currentBuffer.GeneratedCodeStart != null)
{
start = _currentBuffer.GeneratedCodeStart.Value;
}
int paddingLength; // unused, in this case there is enough context in the original code to calculate the right padding length
// (padded.Length - _currentBuffer.Builder.Length)
string padded = CodeGeneratorPaddingHelper.Pad(Host, _currentBuffer.Builder.ToString(), sourceSpan, start, out paddingLength);
_currentBuffer.GeneratedCodeStart = start + (padded.Length - _currentBuffer.Builder.Length);
_currentBuffer.Builder.Clear();
_currentBuffer.Builder.Append(padded);
}
_currentBuffer.Builder.Append(fragment);
}
public void MarkStartOfGeneratedCode()
{
_currentBuffer.MarkStart();
}
public void MarkEndOfGeneratedCode()
{
_currentBuffer.MarkEnd();
}
public void FlushBufferedStatement()
{
if (_currentBuffer.Builder.Length > 0)
{
CodeLinePragma pragma = null;
if (_currentBuffer.LinePragmaSpan != null)
{
int start = _currentBuffer.Builder.Length;
if (_currentBuffer.GeneratedCodeStart != null)
{
start = _currentBuffer.GeneratedCodeStart.Value;
}
int len = _currentBuffer.Builder.Length - start;
if (_currentBuffer.CodeLength != null)
{
len = _currentBuffer.CodeLength.Value;
}
pragma = GenerateLinePragma(_currentBuffer.LinePragmaSpan, start, len);
}
AddStatement(_currentBuffer.Builder.ToString(), pragma);
_currentBuffer.Reset();
}
}
public void AddStatement(string generatedCode)
{
AddStatement(generatedCode, null);
}
public void AddStatement(string body, CodeLinePragma pragma)
{
if (StatementCollector == null)
{
TargetMethod.Statements.Add(new CodeSnippetStatement(body) { LinePragma = pragma });
}
else
{
StatementCollector(body, pragma);
}
}
public void EnsureExpressionHelperVariable()
{
if (!_expressionHelperVariableWriten)
{
GeneratedClass.Members.Insert(0,
new CodeMemberField(typeof(object), "__o")
{
Attributes = MemberAttributes.Private | MemberAttributes.Static
});
_expressionHelperVariableWriten = true;
}
}
public IDisposable ChangeStatementCollector(Action<string, CodeLinePragma> collector)
{
Action<string, CodeLinePragma> oldCollector = StatementCollector;
StatementCollector = collector;
return new DisposableAction(() =>
{
StatementCollector = oldCollector;
});
}
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We explicitly want the lower-case string here")]
public void AddContextCall(Span contentSpan, string methodName, bool isLiteral)
{
AddStatement(BuildCodeString(cw =>
{
cw.WriteStartMethodInvoke(methodName);
if (!String.IsNullOrEmpty(TargetWriterName))
{
cw.WriteSnippet(TargetWriterName);
cw.WriteParameterSeparator();
}
cw.WriteStringLiteral(Host.InstrumentedSourceFilePath);
cw.WriteParameterSeparator();
cw.WriteSnippet(contentSpan.Start.AbsoluteIndex.ToString(CultureInfo.InvariantCulture));
cw.WriteParameterSeparator();
cw.WriteSnippet(contentSpan.Content.Length.ToString(CultureInfo.InvariantCulture));
cw.WriteParameterSeparator();
cw.WriteSnippet(isLiteral.ToString().ToLowerInvariant());
cw.WriteEndMethodInvoke();
cw.WriteEndStatement();
}));
}
internal CodeWriter CreateCodeWriter()
{
Debug.Assert(CodeWriterFactory != null);
if (CodeWriterFactory == null)
{
throw new InvalidOperationException(RazorResources.CreateCodeWriter_NoCodeWriter);
}
return CodeWriterFactory();
}
internal string BuildCodeString(Action<CodeWriter> action)
{
using (CodeWriter cw = CodeWriterFactory())
{
action(cw);
return cw.Content;
}
}
private class StatementBuffer
{
public StringBuilder Builder = new StringBuilder();
public int? GeneratedCodeStart;
public int? CodeLength;
public Span LinePragmaSpan;
public void Reset()
{
Builder.Clear();
GeneratedCodeStart = null;
CodeLength = null;
LinePragmaSpan = null;
}
public void MarkStart()
{
GeneratedCodeStart = Builder.Length;
}
public void MarkEnd()
{
CodeLength = Builder.Length - GeneratedCodeStart;
}
}
#endif
#endregion
public RazorEngineHost Host { get; private set; }
public string TargetWriterName { get; set; }
@ -312,49 +24,14 @@ namespace Microsoft.AspNet.Razor.Generator
public static CodeGeneratorContext Create(RazorEngineHost host, string className, string rootNamespace, string sourceFile, bool shouldGenerateLinePragmas)
{
return Create(host, null, className, rootNamespace, sourceFile, shouldGenerateLinePragmas);
}
internal static CodeGeneratorContext Create(RazorEngineHost host, Func<CodeWriter> writerFactory, string className, string rootNamespace, string sourceFile, bool shouldGenerateLinePragmas)
{
CodeGeneratorContext context = new CodeGeneratorContext()
return new CodeGeneratorContext()
{
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
CodeWriterFactory = writerFactory,
CompileUnit = new CodeCompileUnit(),
Namespace = new CodeNamespace(rootNamespace),
GeneratedClass = new CodeTypeDeclaration(className)
{
IsClass = true
},
TargetMethod = new CodeMemberMethod()
{
Name = host.GeneratedClassContext.ExecuteMethodName,
Attributes = MemberAttributes.Override | MemberAttributes.Public
},
CodeMappings = new Dictionary<int, GeneratedCodeMapping>()
#endif
ClassName = className
};
#if NET45
// No CodeDOM in CoreCLR.
context.CompileUnit.Namespaces.Add(context.Namespace);
context.Namespace.Types.Add(context.GeneratedClass);
context.GeneratedClass.Members.Add(context.TargetMethod);
context.Namespace.Imports.AddRange(host.NamespaceImports
.Select(s => new CodeNamespaceImport(s))
.ToArray());
#endif
return context;
}
}
}

View File

@ -1,205 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
#if NET45
// This section is #if'd because it is no longer needed for the CodeTree transition.
internal static class CodeGeneratorPaddingHelper
{
private static readonly char[] _newLineChars = { '\r', '\n' };
// there is some duplicity of code here, but its very simple and since this is a host path, I'd rather not create another class to encapsulate the data.
public static int PaddingCharCount(RazorEngineHost host, Span target, int generatedStart)
{
int padding = CalculatePadding(host, target, generatedStart);
if (host.DesignTimeMode && host.IsIndentingWithTabs)
{
int spaces;
int tabs = Math.DivRem(padding, host.TabSize, out spaces);
return tabs + spaces;
}
else
{
return padding;
}
}
// Special case for statement padding to account for brace positioning in the editor.
public static string PadStatement(RazorEngineHost host, string code, Span target, ref int startGeneratedCode, out int paddingCharCount)
{
if (host == null)
{
throw new ArgumentNullException("host");
}
if (target == null)
{
throw new ArgumentNullException("target");
}
// We are passing 0 rather than startgeneratedcode intentionally (keeping v2 behavior).
int padding = CalculatePadding(host, target, 0);
// We treat statement padding specially so for brace positioning, so that in the following example:
// @if (foo > 0)
// {
// }
//
// the braces shows up under the @ rather than under the if.
if (host.DesignTimeMode &&
padding > 0 &&
target.Previous.Kind == SpanKind.Transition && // target.Previous is guaranteed to be none null if you got any padding.
String.Equals(target.Previous.Content, SyntaxConstants.TransitionString))
{
padding--;
startGeneratedCode--;
}
string generatedCode = PadInternal(host, code, padding, out paddingCharCount);
return generatedCode;
}
public static string Pad(RazorEngineHost host, string code, Span target, out int paddingCharCount)
{
int padding = CalculatePadding(host, target, 0);
return PadInternal(host, code, padding, out paddingCharCount);
}
public static string Pad(RazorEngineHost host, string code, Span target, int generatedStart, out int paddingCharCount)
{
int padding = CalculatePadding(host, target, generatedStart);
return PadInternal(host, code, padding, out paddingCharCount);
}
// internal for unit testing only, not intended to be used directly in code
internal static int CalculatePadding(RazorEngineHost host, Span target, int generatedStart)
{
if (host == null)
{
throw new ArgumentNullException("host");
}
if (target == null)
{
throw new ArgumentNullException("target");
}
int padding;
padding = CollectSpacesAndTabs(target, host.TabSize) - generatedStart;
// if we add generated text that is longer than the padding we wanted to insert we have no recourse and we have to skip padding
// example:
// Razor code at column zero: @somecode()
// Generated code will be:
// In design time: __o = somecode();
// In Run time: Write(somecode());
//
// In both cases the padding would have been 1 space to remote the space the @ symbol takes, which will be smaller than the 6 chars the hidden generated code takes.
if (padding < 0)
{
padding = 0;
}
return padding;
}
private static string PadInternal(RazorEngineHost host, string code, int padding, out int paddingCharCount)
{
if (host.DesignTimeMode && host.IsIndentingWithTabs)
{
int spaces;
int tabs = Math.DivRem(padding, host.TabSize, out spaces);
paddingCharCount = tabs + spaces;
return new string('\t', tabs) + new string(' ', spaces) + code;
}
else
{
paddingCharCount = padding;
return code.PadLeft(padding + code.Length, ' ');
}
}
private static int CollectSpacesAndTabs(Span target, int tabSize)
{
Span firstSpanInLine = target;
string currentContent = null;
while (firstSpanInLine.Previous != null)
{
// When scanning previous spans we need to be break down the spans with spaces.
// Because the parser doesn't so for example a span looking like \n\n\t needs to be broken down, and we should just grab the \t.
String previousContent = firstSpanInLine.Previous.Content ?? String.Empty;
int lastNewLineIndex = previousContent.LastIndexOfAny(_newLineChars);
if (lastNewLineIndex < 0)
{
firstSpanInLine = firstSpanInLine.Previous;
}
else
{
if (lastNewLineIndex != previousContent.Length - 1)
{
firstSpanInLine = firstSpanInLine.Previous;
currentContent = previousContent.Substring(lastNewLineIndex + 1);
}
break;
}
}
// We need to walk from the beginning of the line, because space + tab(tabSize) = tabSize columns, but tab(tabSize) + space = tabSize+1 columns.
Span currentSpanInLine = firstSpanInLine;
if (currentContent == null)
{
currentContent = currentSpanInLine.Content;
}
int padding = 0;
while (currentSpanInLine != target)
{
if (currentContent != null)
{
for (int i = 0; i < currentContent.Length; i++)
{
if (currentContent[i] == '\t')
{
// Example:
// <space><space><tab><tab>:
// iter 1) 1
// iter 2) 2
// iter 3) 4 = 2 + (4 - 2)
// iter 4) 8 = 4 + (4 - 0)
padding = padding + (tabSize - (padding % tabSize));
}
else
{
padding++;
}
}
}
currentSpanInLine = currentSpanInLine.Next;
currentContent = currentSpanInLine.Content;
}
return padding;
}
}
#endif
}

View File

@ -1,218 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using System.Globalization;
using System.IO;
namespace Microsoft.AspNet.Razor.Generator
{
// Utility class which helps write code snippets
internal abstract class CodeWriter : IDisposable
{
private StringWriter _writer;
protected CodeWriter()
{
}
private enum WriterMode
{
Constructor,
MethodCall,
LambdaDelegate,
LambdaExpression
}
public string Content
{
get { return InnerWriter.ToString(); }
}
public StringWriter InnerWriter
{
get
{
if (_writer == null)
{
_writer = new StringWriter(CultureInfo.InvariantCulture);
}
return _writer;
}
}
public virtual bool SupportsMidStatementLinePragmas
{
get { return true; }
}
public abstract void WriteParameterSeparator();
public abstract void WriteReturn();
public abstract void WriteLinePragma(int? lineNumber, string fileName);
public abstract void WriteHelperHeaderPrefix(string templateTypeName, bool isStatic);
public abstract void WriteSnippet(string snippet);
public abstract void WriteStringLiteral(string literal);
public abstract int WriteVariableDeclaration(string type, string name, string value);
#if NET45
// No CodeDOM in CoreCLR
public virtual void WriteLinePragma()
{
WriteLinePragma(null);
}
public virtual void WriteLinePragma(CodeLinePragma pragma)
{
if (pragma == null)
{
WriteLinePragma(null, null);
}
else
{
WriteLinePragma(pragma.LineNumber, pragma.FileName);
}
}
public CodeSnippetStatement ToStatement()
{
return new CodeSnippetStatement(Content);
}
public CodeSnippetTypeMember ToTypeMember()
{
return new CodeSnippetTypeMember(Content);
}
#endif
public virtual void WriteHiddenLinePragma()
{
}
public virtual void WriteDisableUnusedFieldWarningPragma()
{
}
public virtual void WriteRestoreUnusedFieldWarningPragma()
{
}
public virtual void WriteIdentifier(string identifier)
{
InnerWriter.Write(identifier);
}
public virtual void WriteHelperHeaderSuffix(string templateTypeName)
{
}
public virtual void WriteHelperTrailer()
{
}
public void WriteStartMethodInvoke(string methodName)
{
EmitStartMethodInvoke(methodName);
}
public void WriteStartMethodInvoke(string methodName, params string[] genericArguments)
{
EmitStartMethodInvoke(methodName, genericArguments);
}
public void WriteEndMethodInvoke()
{
EmitEndMethodInvoke();
}
public virtual void WriteEndStatement()
{
}
public virtual void WriteStartAssignment(string variableName)
{
InnerWriter.Write(variableName);
InnerWriter.Write(" = ");
}
public void WriteStartLambdaExpression(params string[] parameterNames)
{
EmitStartLambdaExpression(parameterNames);
}
public void WriteStartConstructor(string typeName)
{
EmitStartConstructor(typeName);
}
public void WriteStartLambdaDelegate(params string[] parameterNames)
{
EmitStartLambdaDelegate(parameterNames);
}
public void WriteEndLambdaExpression()
{
EmitEndLambdaExpression();
}
public void WriteEndConstructor()
{
EmitEndConstructor();
}
public void WriteEndLambdaDelegate()
{
EmitEndLambdaDelegate();
}
public virtual void WriteLineContinuation()
{
}
public virtual void WriteBooleanLiteral(bool value)
{
#if NET45
// ToString does not take a parameter in CoreCLR
// #if'd the entire section because once we transition over to the CodeTree we will not need all this code.
WriteSnippet(value.ToString(CultureInfo.InvariantCulture));
#endif
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Clear()
{
if (InnerWriter != null)
{
InnerWriter.GetStringBuilder().Clear();
}
}
protected internal abstract void EmitStartLambdaDelegate(string[] parameterNames);
protected internal abstract void EmitStartLambdaExpression(string[] parameterNames);
protected internal abstract void EmitStartConstructor(string typeName);
protected internal abstract void EmitStartMethodInvoke(string methodName);
protected internal virtual void EmitStartMethodInvoke(string methodName, params string[] genericArguments)
{
EmitStartMethodInvoke(methodName);
}
protected internal abstract void EmitEndLambdaDelegate();
protected internal abstract void EmitEndLambdaExpression();
protected internal abstract void EmitEndConstructor();
protected internal abstract void EmitEndMethodInvoke();
protected virtual void Dispose(bool disposing)
{
if (disposing && _writer != null)
{
_writer.Dispose();
}
}
}
}

View File

@ -1,19 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Globalization;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator
{
internal static class CodeWriterExtensions
{
public static void WriteLocationTaggedString(this CodeWriter writer, LocationTagged<string> value)
{
writer.WriteStartMethodInvoke("Tuple.Create");
writer.WriteStringLiteral(value.Value);
writer.WriteParameterSeparator();
writer.WriteSnippet(value.Location.AbsoluteIndex.ToString(CultureInfo.CurrentCulture));
writer.WriteEndMethodInvoke();
}
}
}

View File

@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
WriteStartScope();
}
public event Action OnClose;
public Action OnClose;
public void Dispose()
{

View File

@ -51,45 +51,53 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
_generatedContentLength = _writer.ToString().Length - _generatedLocation.AbsoluteIndex;
}
public void Dispose()
protected virtual void Dispose(bool disposing)
{
// Verify that the generated length has not already been calculated
if (_generatedContentLength == 0)
if(disposing)
{
_generatedContentLength = _writer.ToString().Length - _generatedLocation.AbsoluteIndex;
}
var generatedLocation = new MappingLocation(_generatedLocation, _generatedContentLength);
if (_documentMapping.ContentLength == -1)
{
_documentMapping.ContentLength = generatedLocation.ContentLength;
}
_writer.LineMappingManager.AddMapping(
documentLocation: _documentMapping,
generatedLocation: new MappingLocation(_generatedLocation, _generatedContentLength));
if (_writePragmas)
{
// Need to add an additional line at the end IF there wasn't one already written.
// This is needed to work with the C# editor's handling of #line ...
bool endsWithNewline = _writer.ToString().EndsWith("\n");
// Always write at least 1 empty line to potentially separate code from pragmas.
_writer.WriteLine();
// Check if the previous empty line wasn't enough to separate code from pragmas.
if (!endsWithNewline)
// Verify that the generated length has not already been calculated
if (_generatedContentLength == 0)
{
_writer.WriteLine();
_generatedContentLength = _writer.ToString().Length - _generatedLocation.AbsoluteIndex;
}
_writer.WriteLineDefaultDirective()
.WriteLineHiddenDirective();
}
var generatedLocation = new MappingLocation(_generatedLocation, _generatedContentLength);
if (_documentMapping.ContentLength == -1)
{
_documentMapping.ContentLength = generatedLocation.ContentLength;
}
// Reset indent back to when it was started
_writer.SetIndent(_startIndent);
_writer.LineMappingManager.AddMapping(
documentLocation: _documentMapping,
generatedLocation: new MappingLocation(_generatedLocation, _generatedContentLength));
if (_writePragmas)
{
// Need to add an additional line at the end IF there wasn't one already written.
// This is needed to work with the C# editor's handling of #line ...
bool endsWithNewline = _writer.ToString().EndsWith("\n");
// Always write at least 1 empty line to potentially separate code from pragmas.
_writer.WriteLine();
// Check if the previous empty line wasn't enough to separate code from pragmas.
if (!endsWithNewline)
{
_writer.WriteLine();
}
_writer.WriteLineDefaultDirective()
.WriteLineHiddenDirective();
}
// Reset indent back to when it was started
_writer.SetIndent(_startIndent);
}
}
public void Dispose()
{
Dispose(disposing: true);
}
}
}

View File

@ -8,6 +8,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpCodeVisitor : CodeVisitor<CSharpCodeWriter>
{
private const string ItemParameterName = "item";
private const string ValueWriterName = "__razor_attribute_value_writer";
private const string TemplateWriterName = "__razor_template_writer";
@ -32,13 +33,13 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
protected override void Visit(TemplateChunk chunk)
{
Writer.Write(TemplateBlockCodeGenerator.ItemParameterName).Write(" => ")
Writer.Write(ItemParameterName).Write(" => ")
.WriteStartNewObject(Context.Host.GeneratedClassContext.TemplateTypeName);
string currentTargetWriterName = Context.TargetWriterName;
Context.TargetWriterName = TemplateWriterName;
using (Writer.BuildLambda(endLine: false, parameterNames: TemplateBlockCodeGenerator.TemplateWriterName))
using (Writer.BuildLambda(endLine: false, parameterNames: TemplateWriterName))
{
Accept(chunk.Children);
}

View File

@ -4,6 +4,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
public class CSharpDesignTimeHelpersVisitor : CodeVisitor<CSharpCodeWriter>
{
internal const string InheritsHelper = "__inheritsHelper";
internal const string DesignTimeHelperMethodName = "__RazorDesignTimeHelpers__";
public CSharpDesignTimeHelpersVisitor(CSharpCodeWriter writer, CodeGeneratorContext context)
: base(writer, context) { }
@ -12,7 +13,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
if (Context.Host.DesignTimeMode)
{
using (Writer.BuildMethodDeclaration("private", "void", "@" + CodeGeneratorContext.DesignTimeHelperMethodName))
using (Writer.BuildMethodDeclaration("private", "void", "@" + DesignTimeHelperMethodName))
{
using (Writer.BuildDisableWarningScope())
{

View File

@ -4,7 +4,7 @@ using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class CodeWriter
public class CodeWriter : IDisposable
{
protected StringWriter Writer;
@ -121,5 +121,18 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
lineIndex: (unescapedOutput.Length - unescapedOutput.Replace(Environment.NewLine, String.Empty).Length) / Environment.NewLine.Length,
characterIndex: unescapedOutput.Length - (unescapedOutput.LastIndexOf(Environment.NewLine) + Environment.NewLine.Length));
}
protected virtual void Dispose(bool disposing)
{
if(disposing)
{
Writer.Dispose();
}
}
public void Dispose()
{
Dispose(disposing: true);
}
}
}

View File

@ -6,7 +6,6 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public LocationTagged<string> Signature { get; set; }
public LocationTagged<string> Footer { get; set; }
// TODO: Can these properties be taken out?
public bool HeaderComplete { get; set; }
}
}

View File

@ -2,7 +2,6 @@
using System;
using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
@ -12,11 +11,6 @@ namespace Microsoft.AspNet.Razor.Generator
{
public class DynamicAttributeBlockCodeGenerator : BlockCodeGenerator
{
private const string ValueWriterName = "__razor_attribute_value_writer";
private string _oldTargetWriter;
private bool _isExpression;
private ExpressionRenderingMode _oldRenderingMode;
public DynamicAttributeBlockCodeGenerator(LocationTagged<string> prefix, int offset, int line, int col)
: this(prefix, new SourceLocation(offset, line, col))
{
@ -31,131 +25,16 @@ namespace Microsoft.AspNet.Razor.Generator
public LocationTagged<string> Prefix { get; private set; }
public SourceLocation ValueStart { get; private set; }
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
DynamicCodeAttributeChunk chunk = codeTreeBuilder.StartChunkBlock<DynamicCodeAttributeChunk>(target);
var chunk = context.CodeTreeBuilder.StartChunkBlock<DynamicCodeAttributeChunk>(target);
chunk.Start = ValueStart;
chunk.Prefix = Prefix;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// This code will not be needed once we transition to the CodeTree
if (context.Host.DesignTimeMode)
{
return; // Don't generate anything!
}
// What kind of block is nested within
string generatedCode;
#endif
Block child = target.Children.Where(n => n.IsBlock).Cast<Block>().FirstOrDefault();
if (child != null && child.Type == BlockType.Expression)
{
_isExpression = true;
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
generatedCode = context.BuildCodeString(cw =>
{
cw.WriteParameterSeparator();
cw.WriteStartMethodInvoke("Tuple.Create");
cw.WriteLocationTaggedString(Prefix);
cw.WriteParameterSeparator();
cw.WriteStartMethodInvoke("Tuple.Create", "System.Object", "System.Int32");
});
#endif
_oldRenderingMode = context.ExpressionRenderingMode;
context.ExpressionRenderingMode = ExpressionRenderingMode.InjectCode;
}
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
else
{
generatedCode = context.BuildCodeString(cw =>
{
cw.WriteParameterSeparator();
cw.WriteStartMethodInvoke("Tuple.Create");
cw.WriteLocationTaggedString(Prefix);
cw.WriteParameterSeparator();
cw.WriteStartMethodInvoke("Tuple.Create", "System.Object", "System.Int32");
cw.WriteStartConstructor(context.Host.GeneratedClassContext.TemplateTypeName);
cw.WriteStartLambdaDelegate(ValueWriterName);
});
}
context.MarkEndOfGeneratedCode();
context.BufferStatementFragment(generatedCode);
#endif
_oldTargetWriter = context.TargetWriterName;
context.TargetWriterName = ValueWriterName;
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
{
if (context.Host.DesignTimeMode)
{
return; // Don't generate anything!
}
string generatedCode;
if (_isExpression)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
generatedCode = context.BuildCodeString(cw =>
{
cw.WriteParameterSeparator();
cw.WriteSnippet(ValueStart.AbsoluteIndex.ToString(CultureInfo.CurrentCulture));
cw.WriteEndMethodInvoke();
cw.WriteParameterSeparator();
// literal: false - This attribute value is not a literal value, it is dynamically generated
cw.WriteBooleanLiteral(false);
cw.WriteEndMethodInvoke();
cw.WriteLineContinuation();
});
#endif
context.ExpressionRenderingMode = _oldRenderingMode;
}
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
else
{
generatedCode = context.BuildCodeString(cw =>
{
cw.WriteEndLambdaDelegate();
cw.WriteEndConstructor();
cw.WriteParameterSeparator();
cw.WriteSnippet(ValueStart.AbsoluteIndex.ToString(CultureInfo.CurrentCulture));
cw.WriteEndMethodInvoke();
cw.WriteParameterSeparator();
// literal: false - This attribute value is not a literal value, it is dynamically generated
cw.WriteBooleanLiteral(false);
cw.WriteEndMethodInvoke();
cw.WriteLineContinuation();
});
}
context.AddStatement(generatedCode);
#endif
context.TargetWriterName = _oldTargetWriter;
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.EndChunkBlock();
}
public override string ToString()

View File

@ -1,7 +1,5 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
@ -9,127 +7,19 @@ namespace Microsoft.AspNet.Razor.Generator
{
public class ExpressionCodeGenerator : HybridCodeGenerator
{
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
ExpressionBlockChunk chunk = codeTreeBuilder.StartChunkBlock<ExpressionBlockChunk>(target);
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
if (context.Host.EnableInstrumentation && context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
Span contentSpan = target.Children
.OfType<Span>()
.Where(s => s.Kind == SpanKind.Code || s.Kind == SpanKind.Markup)
.FirstOrDefault();
if (contentSpan != null)
{
context.AddContextCall(contentSpan, context.Host.GeneratedClassContext.BeginContextMethodName, false);
}
}
string writeInvocation = context.BuildCodeString(cw =>
{
if (context.Host.DesignTimeMode)
{
context.EnsureExpressionHelperVariable();
cw.WriteStartAssignment("__o");
}
else if (context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
if (!String.IsNullOrEmpty(context.TargetWriterName))
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.WriteToMethodName);
cw.WriteSnippet(context.TargetWriterName);
cw.WriteParameterSeparator();
}
else
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.WriteMethodName);
}
}
});
context.BufferStatementFragment(writeInvocation);
context.MarkStartOfGeneratedCode();
#endif
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
string endBlock = context.BuildCodeString(cw =>
{
if (context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
if (!context.Host.DesignTimeMode)
{
cw.WriteEndMethodInvoke();
}
cw.WriteEndStatement();
}
else
{
cw.WriteLineContinuation();
}
});
context.MarkEndOfGeneratedCode();
context.BufferStatementFragment(endBlock);
context.FlushBufferedStatement();
if (context.Host.EnableInstrumentation && context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
Span contentSpan = target.Children
.OfType<Span>()
.Where(s => s.Kind == SpanKind.Code || s.Kind == SpanKind.Markup)
.FirstOrDefault();
if (contentSpan != null)
{
context.AddContextCall(contentSpan, context.Host.GeneratedClassContext.EndContextMethodName, false);
}
}
#endif
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddExpressionChunk(target.Content, target);
context.CodeTreeBuilder.StartChunkBlock<ExpressionBlockChunk>(target);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
context.CodeTreeBuilder.AddExpressionChunk(target.Content, target);
}
Span sourceSpan = null;
if (context.CreateCodeWriter().SupportsMidStatementLinePragmas || context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
sourceSpan = target;
}
context.BufferStatementFragment(target.Content, sourceSpan);
#endif
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
{
context.CodeTreeBuilder.EndChunkBlock();
}
public override string ToString()

View File

@ -1,102 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Globalization;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator
{
public struct GeneratedCodeMapping
{
public GeneratedCodeMapping(int startLine, int startColumn, int startGeneratedColumn, int codeLength)
: this(null, startLine, startColumn, startGeneratedColumn, codeLength)
{
}
public GeneratedCodeMapping(int startOffset, int startLine, int startColumn, int startGeneratedColumn, int codeLength)
: this((int?)startOffset, startLine, startColumn, startGeneratedColumn, codeLength)
{
}
private GeneratedCodeMapping(int? startOffset, int startLine, int startColumn, int startGeneratedColumn, int codeLength)
: this()
{
if (startLine < 0)
{
throw new ArgumentOutOfRangeException("startLine", CommonResources.Argument_Must_Be_GreaterThanOrEqualTo(0));
}
if (startColumn < 0)
{
throw new ArgumentOutOfRangeException("startColumn", CommonResources.Argument_Must_Be_GreaterThanOrEqualTo(0));
}
if (startGeneratedColumn < 0)
{
throw new ArgumentOutOfRangeException("startGeneratedColumn", CommonResources.Argument_Must_Be_GreaterThanOrEqualTo(0));
}
if (codeLength < 0)
{
throw new ArgumentOutOfRangeException("codeLength", CommonResources.Argument_Must_Be_GreaterThanOrEqualTo(0));
}
StartOffset = startOffset;
StartLine = startLine;
StartColumn = startColumn;
StartGeneratedColumn = startGeneratedColumn;
CodeLength = codeLength;
}
public int? StartOffset { get; set; }
public int CodeLength { get; set; }
public int StartColumn { get; set; }
public int StartGeneratedColumn { get; set; }
public int StartLine { get; set; }
public override bool Equals(object obj)
{
if (!(obj is GeneratedCodeMapping))
{
return false;
}
GeneratedCodeMapping other = (GeneratedCodeMapping)obj;
return CodeLength == other.CodeLength &&
StartColumn == other.StartColumn &&
StartGeneratedColumn == other.StartGeneratedColumn &&
StartLine == other.StartLine &&
// Null means it matches the other no matter what.
(StartOffset == null || other.StartOffset == null || StartOffset.Equals(other.StartOffset));
}
public override string ToString()
{
return String.Format(
CultureInfo.CurrentCulture,
"({0}, {1}, {2}) -> (?, {3}) [{4}]",
StartOffset == null ? "?" : StartOffset.Value.ToString(CultureInfo.CurrentCulture),
StartLine,
StartColumn,
StartGeneratedColumn,
CodeLength);
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(CodeLength)
.Add(StartColumn)
.Add(StartGeneratedColumn)
.Add(StartLine)
.Add(StartOffset)
.CombinedHash;
}
public static bool operator ==(GeneratedCodeMapping left, GeneratedCodeMapping right)
{
return left.Equals(right);
}
public static bool operator !=(GeneratedCodeMapping left, GeneratedCodeMapping right)
{
return !left.Equals(right);
}
}
}

View File

@ -1,7 +1,5 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using System.Globalization;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
@ -12,12 +10,6 @@ namespace Microsoft.AspNet.Razor.Generator
{
public class HelperCodeGenerator : BlockCodeGenerator
{
private const string HelperWriterName = "__razor_helper_writer";
private CodeWriter _writer;
private string _oldWriter;
private IDisposable _statementCollectorToken;
public HelperCodeGenerator(LocationTagged<string> signature, bool headerComplete)
{
Signature = signature;
@ -28,83 +20,18 @@ namespace Microsoft.AspNet.Razor.Generator
public LocationTagged<string> Footer { get; set; }
public bool HeaderComplete { get; private set; }
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
HelperChunk chunk = codeTreeBuilder.StartChunkBlock<HelperChunk>(target, topLevel: true);
var chunk = context.CodeTreeBuilder.StartChunkBlock<HelperChunk>(target, topLevel: true);
chunk.Signature = Signature;
chunk.Footer = Footer;
chunk.HeaderComplete = HeaderComplete;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
_writer = context.CreateCodeWriter();
string prefix = context.BuildCodeString(
cw => cw.WriteHelperHeaderPrefix(context.Host.GeneratedClassContext.TemplateTypeName, context.Host.StaticHelpers));
_writer.WriteLinePragma(
context.GenerateLinePragma(Signature.Location, prefix.Length, Signature.Value.Length));
_writer.WriteSnippet(prefix);
_writer.WriteSnippet(Signature);
if (HeaderComplete)
{
_writer.WriteHelperHeaderSuffix(context.Host.GeneratedClassContext.TemplateTypeName);
}
_writer.WriteLinePragma(null);
if (HeaderComplete)
{
_writer.WriteReturn();
_writer.WriteStartConstructor(context.Host.GeneratedClassContext.TemplateTypeName);
_writer.WriteStartLambdaDelegate(HelperWriterName);
}
_statementCollectorToken = context.ChangeStatementCollector(AddStatementToHelper);
#endif
_oldWriter = context.TargetWriterName;
context.TargetWriterName = HelperWriterName;
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
_statementCollectorToken.Dispose();
if (HeaderComplete)
{
_writer.WriteEndLambdaDelegate();
_writer.WriteEndConstructor();
_writer.WriteEndStatement();
}
if (Footer != null && !String.IsNullOrEmpty(Footer.Value))
{
_writer.WriteLinePragma(
context.GenerateLinePragma(Footer.Location, 0, Footer.Value.Length));
_writer.WriteSnippet(Footer);
_writer.WriteLinePragma();
}
_writer.WriteHelperTrailer();
context.GeneratedClass.Members.Add(new CodeSnippetTypeMember(_writer.Content));
#endif
context.TargetWriterName = _oldWriter;
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.EndChunkBlock();
}
public override bool Equals(object obj)
@ -128,23 +55,5 @@ namespace Microsoft.AspNet.Razor.Generator
{
return "Helper:" + Signature.ToString("F", CultureInfo.CurrentCulture) + ";" + (HeaderComplete ? "C" : "I");
}
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
private void AddStatementToHelper(string statement, CodeLinePragma pragma)
{
if (pragma != null)
{
_writer.WriteLinePragma(pragma);
}
_writer.WriteSnippet(statement);
_writer.InnerWriter.WriteLine(); // CodeDOM normally inserts an extra line so we need to do so here.
if (pragma != null)
{
_writer.WriteLinePragma();
}
}
#endif
}
}

View File

@ -29,84 +29,17 @@ namespace Microsoft.AspNet.Razor.Generator
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
if (context.Host.DesignTimeMode)
{
return;
}
LiteralCodeAttributeChunk chunk = context.CodeTreeBuilder.StartChunkBlock<LiteralCodeAttributeChunk>(target);
var chunk = context.CodeTreeBuilder.StartChunkBlock<LiteralCodeAttributeChunk>(target);
chunk.Prefix = Prefix;
chunk.Value = Value;
if (ValueGenerator != null)
{
chunk.ValueLocation = ValueGenerator.Location;
}
ExpressionRenderingMode oldMode = context.ExpressionRenderingMode;
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
context.BufferStatementFragment(context.BuildCodeString(cw =>
{
cw.WriteParameterSeparator();
cw.WriteStartMethodInvoke("Tuple.Create");
cw.WriteLocationTaggedString(Prefix);
cw.WriteParameterSeparator();
#endif
if (ValueGenerator != null)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
cw.WriteStartMethodInvoke("Tuple.Create", "System.Object", "System.Int32");
#endif
context.ExpressionRenderingMode = ExpressionRenderingMode.InjectCode;
}
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
else
{
cw.WriteLocationTaggedString(Value);
cw.WriteParameterSeparator();
// literal: true - This attribute value is a literal value
cw.WriteBooleanLiteral(true);
cw.WriteEndMethodInvoke();
}
}));
#endif
if (ValueGenerator != null)
{
ValueGenerator.Value.GenerateCode(target, context);
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
context.FlushBufferedStatement();
#endif
context.ExpressionRenderingMode = oldMode;
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
context.AddStatement(context.BuildCodeString(cw =>
{
#endif
chunk.ValueLocation = ValueGenerator.Location;
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
cw.WriteParameterSeparator();
cw.WriteSnippet(ValueGenerator.Location.AbsoluteIndex.ToString(CultureInfo.CurrentCulture));
cw.WriteEndMethodInvoke();
cw.WriteParameterSeparator();
// literal: false - This attribute value is not a literal value, it is dynamically generated
cw.WriteBooleanLiteral(false);
cw.WriteEndMethodInvoke();
}));
}
else
{
context.FlushBufferedStatement();
#endif
}
context.CodeTreeBuilder.EndChunkBlock();

View File

@ -1,61 +1,14 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class MarkupCodeGenerator : SpanCodeGenerator
{
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddLiteralChunk(target.Content, target);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
if (!context.Host.DesignTimeMode && String.IsNullOrEmpty(target.Content))
{
return;
}
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
if (context.Host.EnableInstrumentation)
{
context.AddContextCall(target, context.Host.GeneratedClassContext.BeginContextMethodName, isLiteral: true);
}
if (!String.IsNullOrEmpty(target.Content) && !context.Host.DesignTimeMode)
{
string code = context.BuildCodeString(cw =>
{
if (!String.IsNullOrEmpty(context.TargetWriterName))
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.WriteLiteralToMethodName);
cw.WriteSnippet(context.TargetWriterName);
cw.WriteParameterSeparator();
}
else
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.WriteLiteralMethodName);
}
cw.WriteStringLiteral(target.Content);
cw.WriteEndMethodInvoke();
cw.WriteEndStatement();
});
context.AddStatement(code);
}
if (context.Host.EnableInstrumentation)
{
context.AddContextCall(target, context.Host.GeneratedClassContext.EndContextMethodName, isLiteral: true);
}
#endif
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.AddLiteralChunk(target.Content, target);
}
public override string ToString()

View File

@ -1,11 +1,8 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using System.Linq;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator
{
@ -54,11 +51,6 @@ namespace Microsoft.AspNet.Razor.Generator
}
}
internal virtual Func<CodeWriter> CodeWriterFactory
{
get { return null; }
}
public override void VisitStartBlock(Block block)
{
block.CodeGenerator.GenerateStartBlockCode(block, Context);
@ -74,37 +66,17 @@ namespace Microsoft.AspNet.Razor.Generator
span.CodeGenerator.GenerateCode(span, Context);
}
public override void OnComplete()
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
Context.FlushBufferedStatement();
#endif
}
private void EnsureContextInitialized()
{
if (_context == null)
{
_context = CodeGeneratorContext.Create(Host, CodeWriterFactory, ClassName, RootNamespaceName, SourceFileName, GenerateLinePragmas);
_context = CodeGeneratorContext.Create(Host, ClassName, RootNamespaceName, SourceFileName, GenerateLinePragmas);
Initialize(_context);
}
}
protected virtual void Initialize(CodeGeneratorContext context)
{
#if NET45
context.Namespace.Imports.AddRange(Host.NamespaceImports.Select(s => new CodeNamespaceImport(s)).ToArray());
if (!String.IsNullOrEmpty(Host.DefaultBaseClass))
{
context.GeneratedClass.BaseTypes.Add(new CodeTypeReference(Host.DefaultBaseClass));
}
// Dev10 Bug 937438: Generate explicit Parameter-less constructor on Razor generated class
context.GeneratedClass.Members.Add(new CodeConstructor() { Attributes = MemberAttributes.Public });
#endif
}
}
}

View File

@ -1,25 +1,9 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class RazorCommentCodeGenerator : BlockCodeGenerator
{
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
// Flush the buffered statement since we're interrupting it with a comment.
if (!String.IsNullOrEmpty(context.CurrentBufferedStatement))
{
context.MarkEndOfGeneratedCode();
context.BufferStatementFragment(context.BuildCodeString(cw => cw.WriteLineContinuation()));
}
context.FlushBufferedStatement();
#endif
}
}
}

View File

@ -1,11 +1,8 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator
{
@ -25,30 +22,14 @@ namespace Microsoft.AspNet.Razor.Generator
public string Value { get; private set; }
public void GenerateCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
if (Name == SyntaxConstants.CSharp.SessionStateKeyword)
{
codeTreeBuilder.AddSessionStateChunk(Value, target);
context.CodeTreeBuilder.AddSessionStateChunk(Value, target);
}
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
var attributeType = new CodeTypeReference(typeof(RazorDirectiveAttribute));
var attributeDeclaration = new CodeAttributeDeclaration(
attributeType,
new CodeAttributeArgument(new CodePrimitiveExpression(Name)),
new CodeAttributeArgument(new CodePrimitiveExpression(Value)));
context.GeneratedClass.CustomAttributes.Add(attributeDeclaration);
#endif
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()
{
return "Directive: " + Name + ", Value: " + Value;

View File

@ -1,18 +1,12 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class ResolveUrlCodeGenerator : SpanCodeGenerator
{
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddResolveUrlChunk(target.Content, target);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
// Check if the host supports it
@ -22,68 +16,8 @@ namespace Microsoft.AspNet.Razor.Generator
new MarkupCodeGenerator().GenerateCode(target, context);
return;
}
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
if (!context.Host.DesignTimeMode && String.IsNullOrEmpty(target.Content))
{
return;
}
if (context.Host.EnableInstrumentation && context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
// Add a non-literal context call (non-literal because the expanded URL will not match the source character-by-character)
context.AddContextCall(target, context.Host.GeneratedClassContext.BeginContextMethodName, isLiteral: false);
}
if (!String.IsNullOrEmpty(target.Content) && !context.Host.DesignTimeMode)
{
string code = context.BuildCodeString(cw =>
{
if (context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
if (!String.IsNullOrEmpty(context.TargetWriterName))
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.WriteLiteralToMethodName);
cw.WriteSnippet(context.TargetWriterName);
cw.WriteParameterSeparator();
}
else
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.WriteLiteralMethodName);
}
}
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.ResolveUrlMethodName);
cw.WriteStringLiteral(target.Content);
cw.WriteEndMethodInvoke();
if (context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
cw.WriteEndMethodInvoke();
cw.WriteEndStatement();
}
else
{
cw.WriteLineContinuation();
}
});
if (context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
context.AddStatement(code);
}
else
{
context.BufferStatementFragment(code);
}
}
if (context.Host.EnableInstrumentation && context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
{
context.AddContextCall(target, context.Host.GeneratedClassContext.EndContextMethodName, isLiteral: false);
}
#endif
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.AddResolveUrlChunk(target.Content, target);
}
public override string ToString()

View File

@ -16,53 +16,16 @@ namespace Microsoft.AspNet.Razor.Generator
public string SectionName { get; private set; }
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
SectionChunk chunk = codeTreeBuilder.StartChunkBlock<SectionChunk>(target);
var chunk = context.CodeTreeBuilder.StartChunkBlock<SectionChunk>(target);
chunk.Name = SectionName;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
string startBlock = context.BuildCodeString(cw =>
{
cw.WriteStartMethodInvoke(context.Host.GeneratedClassContext.DefineSectionMethodName);
cw.WriteStringLiteral(SectionName);
cw.WriteParameterSeparator();
cw.WriteStartLambdaDelegate();
});
context.AddStatement(startBlock);
#endif
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
string startBlock = context.BuildCodeString(cw =>
{
cw.WriteEndLambdaDelegate();
cw.WriteEndMethodInvoke();
cw.WriteEndStatement();
});
context.AddStatement(startBlock);
#endif
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.EndChunkBlock();
}
public override bool Equals(object obj)

View File

@ -1,8 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
@ -18,32 +16,6 @@ namespace Microsoft.AspNet.Razor.Generator
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
context.GeneratedClass.BaseTypes.Clear();
context.GeneratedClass.BaseTypes.Add(new CodeTypeReference(BaseType.Trim()));
if (context.Host.DesignTimeMode)
{
int generatedCodeStart = 0;
string code = context.BuildCodeString(cw =>
{
generatedCodeStart = cw.WriteVariableDeclaration(target.Content, "__inheritsHelper", null);
cw.WriteEndStatement();
});
int paddingCharCount;
CodeSnippetStatement stmt = new CodeSnippetStatement(
CodeGeneratorPaddingHelper.Pad(context.Host, code, target, generatedCodeStart, out paddingCharCount))
{
LinePragma = context.GenerateLinePragma(target, generatedCodeStart + paddingCharCount)
};
context.AddDesignTimeHelperStatement(stmt);
}
#endif
// TODO: Make this generate the primary generator
context.CodeTreeBuilder.AddSetBaseTypeChunk(BaseType, target);
}

View File

@ -1,8 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
@ -16,27 +14,9 @@ namespace Microsoft.AspNet.Razor.Generator
public string LayoutPath { get; set; }
public void GenerateCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddSetLayoutChunk(LayoutPath, target);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM
if (!context.Host.DesignTimeMode && !String.IsNullOrEmpty(context.Host.GeneratedClassContext.LayoutPropertyName))
{
context.TargetMethod.Statements.Add(
new CodeAssignStatement(
new CodePropertyReferenceExpression(null, context.Host.GeneratedClassContext.LayoutPropertyName),
new CodePrimitiveExpression(LayoutPath)));
}
#endif
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.AddSetLayoutChunk(LayoutPath, target);
}
public override string ToString()

View File

@ -1,40 +1,14 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class StatementCodeGenerator : SpanCodeGenerator
{
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddStatementChunk(target.Content, target);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
context.FlushBufferedStatement();
string generatedCode = context.BuildCodeString(cw =>
{
cw.WriteSnippet(target.Content);
});
int startGeneratedCode = target.Start.CharacterIndex;
int paddingCharCount;
generatedCode = CodeGeneratorPaddingHelper.PadStatement(context.Host, generatedCode, target, ref startGeneratedCode, out paddingCharCount);
context.AddStatement(
generatedCode,
context.GenerateLinePragma(target, paddingCharCount));
#endif
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.AddStatementChunk(target.Content, target);
}
public override string ToString()

View File

@ -7,63 +7,14 @@ namespace Microsoft.AspNet.Razor.Generator
{
public class TemplateBlockCodeGenerator : BlockCodeGenerator
{
internal const string TemplateWriterName = "__razor_template_writer";
internal const string ItemParameterName = "item";
private string _oldTargetWriter;
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.StartChunkBlock<TemplateChunk>(target);
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
string generatedCode = context.BuildCodeString(cw =>
{
cw.WriteStartLambdaExpression(ItemParameterName);
cw.WriteStartConstructor(context.Host.GeneratedClassContext.TemplateTypeName);
cw.WriteStartLambdaDelegate(TemplateWriterName);
});
context.MarkEndOfGeneratedCode();
context.BufferStatementFragment(generatedCode);
context.FlushBufferedStatement();
#endif
_oldTargetWriter = context.TargetWriterName;
context.TargetWriterName = TemplateWriterName;
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
context.CodeTreeBuilder.StartChunkBlock<TemplateChunk>(target);
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
string generatedCode = context.BuildCodeString(cw =>
{
cw.WriteEndLambdaDelegate();
cw.WriteEndConstructor();
cw.WriteEndLambdaExpression();
});
context.BufferStatementFragment(generatedCode);
#endif
context.TargetWriterName = _oldTargetWriter;
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.EndChunkBlock();
}
}
}

View File

@ -1,44 +1,14 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.CodeDom;
#if NET45
using System.Diagnostics.Contracts;
#endif
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class TypeMemberCodeGenerator : SpanCodeGenerator
{
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddTypeMemberChunk(target.Content, target);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
string generatedCode = context.BuildCodeString(cw =>
{
cw.WriteSnippet(target.Content);
});
int paddingCharCount;
string paddedCode = CodeGeneratorPaddingHelper.Pad(context.Host, generatedCode, target, out paddingCharCount);
Contract.Assert(paddingCharCount > 0);
context.GeneratedClass.Members.Add(
new CodeSnippetTypeMember(paddedCode)
{
LinePragma = context.GenerateLinePragma(target, paddingCharCount)
});
#endif
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
context.CodeTreeBuilder.AddTypeMemberChunk(target.Content, target);
}
public override string ToString()

View File

@ -1,6 +1,4 @@
using System.CodeDom;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
@ -8,8 +6,8 @@ namespace Microsoft.AspNet.Razor
{
public class GeneratorResults : ParserResults
{
public GeneratorResults(ParserResults parserResults,
CodeBuilderResult codeBuilderResult)
public GeneratorResults(ParserResults parserResults,
CodeBuilderResult codeBuilderResult)
: this(parserResults.Document, parserResults.ParserErrors, codeBuilderResult)
{
}
@ -33,13 +31,5 @@ namespace Microsoft.AspNet.Razor
public string GeneratedCode { get; private set; }
public IList<LineMapping> DesignTimeLineMappings { get; private set; }
#if NET45
// No CodeDOM + This code will not be needed once we transition to the CodeTree
public CodeCompileUnit CCU { get; set; }
public IDictionary<int, GeneratedCodeMapping> OLDDesignTimeLineMappings { get; set; }
#endif
internal CodeTree CT { get; set; }
}
}

View File

@ -30,14 +30,6 @@ namespace Microsoft.AspNet.Razor
/// The name of the language (for use in System.Web.Compilation.BuildProvider.GetDefaultCompilerTypeForLanguage)
/// </summary>
public abstract string LanguageName { get; }
#if NET45
// No CodeDOM in CoreCLR
/// <summary>
/// The type of the CodeDOM provider for this language
/// </summary>
public abstract Type CodeDomProviderType { get; }
#endif
/// <summary>
/// Gets the RazorCodeLanguage registered for the specified file extension
@ -61,6 +53,6 @@ namespace Microsoft.AspNet.Razor
/// </summary>
public abstract RazorCodeGenerator CreateCodeGenerator(string className, string rootNamespaceName, string sourceFileName, RazorEngineHost host);
public abstract CodeBuilder CreateBuilder(CodeGeneratorContext codeGeneratorContext);
public abstract CodeBuilder CreateCodeBuilder(CodeGeneratorContext codeGeneratorContext);
}
}

View File

@ -3,8 +3,6 @@
#if DEBUG
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
@ -39,39 +37,7 @@ namespace Microsoft.AspNet.Razor
{
get { return _outputDebuggingEnabled; }
}
#if NET45
// No CodeDOM in CoreCLR
[SuppressMessage("Microsoft.Security", "CA2141:TransparentMethodsMustNotSatisfyLinkDemandsFxCopRule", Justification = "This is debug only")]
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "This is debug only")]
[SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.IO.StringWriter.#ctor", Justification = "This is debug only")]
internal static void WriteGeneratedCode(string sourceFile, CodeCompileUnit codeCompileUnit)
{
if (!OutputDebuggingEnabled)
{
return;
}
RunTask(() =>
{
string extension = Path.GetExtension(sourceFile);
RazorCodeLanguage language = RazorCodeLanguage.GetLanguageByExtension(extension);
CodeDomProvider provider = CodeDomProvider.CreateProvider(language.LanguageName);
using (var writer = new StringWriter())
{
// Trim the html part of cshtml or vbhtml
string outputExtension = extension.Substring(0, 3);
string outputFileName = Normalize(sourceFile) + "_generated" + outputExtension;
string outputPath = Path.Combine(Path.GetDirectoryName(sourceFile), outputFileName);
// REVIEW: Do these options need to be tweaked?
provider.GenerateCodeFromCompileUnit(codeCompileUnit, writer, new CodeGeneratorOptions());
File.WriteAllText(outputPath, writer.ToString());
}
});
}
#endif
internal static void WriteDebugTree(string sourceFile, Block document, PartialParseResult result, TextChange change, RazorEditorParser parser, bool treeStructureChanged)
{
if (!OutputDebuggingEnabled)

View File

@ -1,10 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor
@ -199,44 +200,5 @@ namespace Microsoft.AspNet.Razor
}
return incomingCodeGenerator;
}
#if NET45
// No CodeDOM in CoreCLR
/// <summary>
/// Gets the important CodeDOM nodes generated by the code generator and has a chance to add to them.
/// </summary>
/// <remarks>
/// All the other parameter values can be located by traversing tree in the codeCompileUnit node, they
/// are simply provided for convenience
/// </remarks>
/// <param name="context">The current <see cref="CodeGeneratorContext"/>.</param>
public virtual void PostProcessGeneratedCode(CodeGeneratorContext context)
{
#pragma warning disable 0618
PostProcessGeneratedCode(context.CompileUnit, context.Namespace, context.GeneratedClass, context.TargetMethod);
#pragma warning restore 0618
}
[Obsolete("This method is obsolete, use the override which takes a CodeGeneratorContext instead")]
public virtual void PostProcessGeneratedCode(CodeCompileUnit codeCompileUnit, CodeNamespace generatedNamespace, CodeTypeDeclaration generatedClass, CodeMemberMethod executeMethod)
{
if (codeCompileUnit == null)
{
throw new ArgumentNullException("codeCompileUnit");
}
if (generatedNamespace == null)
{
throw new ArgumentNullException("generatedNamespace");
}
if (generatedClass == null)
{
throw new ArgumentNullException("generatedClass");
}
if (executeMethod == null)
{
throw new ArgumentNullException("executeMethod");
}
}
#endif
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
@ -104,7 +103,7 @@ namespace Microsoft.AspNet.Razor
}
/// <summary>
/// Parses the template specified by the TextBuffer, generates code for it, and returns the constructed CodeDOM tree
/// Parses the template specified by the TextBuffer, generates code for it, and returns the constructed code.
/// </summary>
/// <remarks>
/// The cancel token provided can be used to cancel the parse. However, please note
@ -123,7 +122,7 @@ namespace Microsoft.AspNet.Razor
/// <param name="className">The name of the generated class, overriding whatever is specified in the Host. The default value (defined in the Host) can be used by providing null for this argument</param>
/// <param name="rootNamespace">The namespace in which the generated class will reside, overriding whatever is specified in the Host. The default value (defined in the Host) can be used by providing null for this argument</param>
/// <param name="sourceFileName">The file name to use in line pragmas, usually the original Razor file, overriding whatever is specified in the Host. The default value (defined in the Host) can be used by providing null for this argument</param>
/// <returns>The resulting parse tree AND generated Code DOM tree</returns>
/// <returns>The resulting parse tree AND generated code.</returns>
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Input object would be disposed if we dispose the wrapper. We don't own the input so we don't want to dispose it")]
public GeneratorResults GenerateCode(ITextBuffer input, string className, string rootNamespace, string sourceFileName, CancellationToken? cancelToken)
{
@ -166,39 +165,12 @@ namespace Microsoft.AspNet.Razor
RazorCodeGenerator generator = CreateCodeGenerator(className, rootNamespace, sourceFileName);
generator.DesignTimeMode = Host.DesignTimeMode;
generator.Visit(results);
#if NET45
// No CodeDOM in CoreCLR, this calls into CodeDOM dependent code.
// Post process code
Host.PostProcessGeneratedCode(generator.Context);
#endif
// Extract design-time mappings
IDictionary<int, GeneratedCodeMapping> designTimeLineMappings = null;
if (Host.DesignTimeMode)
{
#if NET45
// No CodeDOM in CoreCLR, this calls into CodeDOM dependent code.
designTimeLineMappings = generator.Context.CodeMappings;
#endif
}
var builder = new CSharpCodeBuilder(generator.Context);
CodeBuilderResult builderResult = builder.Build();
var builder = Host.CodeLanguage.CreateCodeBuilder(generator.Context);
var builderResult = builder.Build();
// Collect results and return
return new GeneratorResults(results, builderResult)
{
#if NET45
// No CodeDOM in CoreCLR, this calls into CodeDOM dependent code.
// Also this code will be removed once we transition into the CodeTree
CCU = generator.Context.CompileUnit,
OLDDesignTimeLineMappings = designTimeLineMappings,
#endif
CT = generator.Context.CodeTreeBuilder.CodeTree
};
return new GeneratorResults(results, builderResult);
}
protected internal virtual RazorCodeGenerator CreateCodeGenerator(string className, string rootNamespace, string sourceFileName)

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator.CodeTree
var context = CodeGeneratorContext.Create(host, "TestClass", "TestNamespace", "Foo.cs", shouldGenerateLinePragmas: false);
context.CodeTreeBuilder.AddUsingChunk("FakeNamespace1", syntaxTreeNode.Object);
context.CodeTreeBuilder.AddUsingChunk("FakeNamespace2.SubNamespace", syntaxTreeNode.Object);
CodeBuilder codeBuilder = language.CreateBuilder(context);
CodeBuilder codeBuilder = language.CreateCodeBuilder(context);
// Act
CodeBuilderResult result = codeBuilder.Build();

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Text;
using Microsoft.CSharp;
@ -16,17 +15,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
{
RunTest("CodeTree", onResults: (results) =>
{
CodeDomProvider codeProvider = (CodeDomProvider)Activator.CreateInstance(typeof(CSharpCodeProvider));
CodeGeneratorOptions options = new CodeGeneratorOptions();
var output = new StringBuilder();
using (var writer = new StringWriter(output))
{
codeProvider.GenerateCodeFromCompileUnit(results.CCU, writer, options);
}
string codeDOMOutput = output.ToString();
CodeTreeOutputValidator.ValidateResults(results.GeneratedCode, codeDOMOutput, results.DesignTimeLineMappings, results.OLDDesignTimeLineMappings);
Console.WriteLine(results.GeneratedCode);
}, designTimeMode: true);
}
}

View File

@ -1,140 +0,0 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public class CodeTreeOutputValidator
{
public static void ValidateResults(string codeTreeCode, string codeDOMCode, IList<LineMapping> codeTreeMappings, IDictionary<int, GeneratedCodeMapping> codeDOMMappings)
{
if (codeDOMMappings != null)
{
Assert.Equal(codeTreeMappings.Count, codeDOMMappings.Values.Count);
}
ValidateNamespace(codeTreeCode, codeDOMCode);
ValidateClass(codeTreeCode, codeDOMCode);
ValidateUsings(codeTreeCode, codeDOMCode);
ValidateNewObjects(codeTreeCode, codeDOMCode);
ValidateBraces(codeTreeCode, codeDOMCode);
ValidateLambdas(codeTreeCode, codeDOMCode);
ValidateMembers(codeTreeCode, codeDOMCode);
ValidateReturns(codeTreeCode, codeDOMCode);
ValidateBaseTypes(codeTreeCode, codeDOMCode);
}
private static void ValidateNamespace(string codeTreeCode, string codeDOMCode)
{
ValidateCodeTreeContains(codeTreeCode, codeDOMCode, @"namespace [^\s{]+");
}
private static void ValidateClass(string codeTreeCode, string codeDOMCode)
{
ValidateCodeTreeContains(codeTreeCode, codeDOMCode, @"class [^\s{]+");
}
private static void ValidateUsings(string codeTreeCode, string codeDOMCode)
{
ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"using [^\s{;]+");
}
private static void ValidateNewObjects(string codeTreeCode, string codeDOMCode)
{
ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"new [^\(<\s]+");
}
private static void ValidateBraces(string codeTreeCode, string codeDOMCode)
{
var codeDOMMatches = Regex.Matches(codeDOMCode, "{");
var codeTreeMatches = Regex.Matches(codeTreeCode, "{");
Assert.NotEmpty(codeDOMMatches);
Assert.NotEmpty(codeTreeMatches);
if (codeDOMMatches.Count != codeTreeMatches.Count)
{
// 1 leniency for the design time helpers
Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count - 1);
}
else
{
Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count);
}
codeDOMMatches = Regex.Matches(codeDOMCode, "}");
codeTreeMatches = Regex.Matches(codeTreeCode, "}");
Assert.NotEmpty(codeDOMMatches);
Assert.NotEmpty(codeTreeMatches);
if (codeDOMMatches.Count != codeTreeMatches.Count)
{
// 1 leniency for the design time helpers
Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count - 1);
}
else
{
Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count);
}
}
private static void ValidateLambdas(string codeTreeCode, string codeDOMCode)
{
ValidateCount(codeTreeCode, codeDOMCode, " => ");
}
private static void ValidateMembers(string codeTreeCode, string codeDOMCode)
{
ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"(public|private) [^\s\(]+ [^\s\(]+");
}
private static void ValidateReturns(string codeTreeCode, string codeDOMCode)
{
ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"return [^\s\(;]+");
}
private static void ValidateBaseTypes(string codeTreeCode, string codeDOMCode)
{
ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"class [^\s]+ : [^\s{]+");
}
private static void ValidateKeywords(string codeTreeCode, string codeDOMCode)
{
ValidateCount(codeTreeCode, codeDOMCode, "Execute");
ValidateCount(codeTreeCode, codeDOMCode, CSharpDesignTimeHelpersVisitor.InheritsHelper);
}
private static void ValidateCodeTreeContains(string codeTreeCode, string codeDOMCode, string regex)
{
var match = Regex.Match(codeDOMCode, regex);
Assert.NotEmpty(match.Groups);
Assert.True(codeTreeCode.IndexOf(match.Groups[0].Value) >= 0);
}
private static void ValidateCodeTreeContainsAll(string codeTreeCode, string codeDOMCode, string regex)
{
var matches = Regex.Matches(codeDOMCode, regex);
for (int i = 0; i < matches.Count; i++)
{
var match = matches[i];
for (int j = 0; j < match.Groups.Count; j++)
{
Assert.True(codeTreeCode.IndexOf(match.Groups[j].Value) >= 0);
}
}
}
private static void ValidateCount(string codeTreeCode, string codeDOMCode, string regex)
{
var codeDOMMatches = Regex.Matches(codeDOMCode, regex);
var codeTreeMatches = Regex.Matches(codeTreeCode, regex);
Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count);
}
}
}

View File

@ -68,7 +68,6 @@
<Compile Include="Framework\RawTextSymbol.cs" />
<Compile Include="Framework\TestSpanBuilder.cs" />
<Compile Include="Generator\CodeTree\CodeTreeGenerationTest.cs" />
<Compile Include="Generator\CodeTree\CodeTreeOutputValidator.cs" />
<Compile Include="Generator\CodeTree\CSharpCodeBuilderTests.cs" />
<Compile Include="Generator\CodeTree\CSharpPaddingBuilderTests.cs" />
<Compile Include="Generator\CSharpRazorCodeGeneratorTest.cs" />