|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
namespace Microsoft.CSharp
{
internal sealed partial class CSharpCodeGenerator : ICodeCompiler, ICodeGenerator
{
private static readonly char[] s_periodArray = new char[] { '.' };
private ExposedTabStringIndentedTextWriter _output;
private CodeGeneratorOptions _options;
private CodeTypeDeclaration _currentClass;
private CodeTypeMember _currentMember;
private bool _inNestedBinary;
private readonly IDictionary<string, string> _provOptions;
private const int ParameterMultilineThreshold = 15;
private const int MaxLineLength = 80;
private const GeneratorSupport LanguageSupport = GeneratorSupport.ArraysOfArrays |
GeneratorSupport.EntryPointMethod |
GeneratorSupport.GotoStatements |
GeneratorSupport.MultidimensionalArrays |
GeneratorSupport.StaticConstructors |
GeneratorSupport.TryCatchStatements |
GeneratorSupport.ReturnTypeAttributes |
GeneratorSupport.AssemblyAttributes |
GeneratorSupport.DeclareValueTypes |
GeneratorSupport.DeclareEnums |
GeneratorSupport.DeclareEvents |
GeneratorSupport.DeclareDelegates |
GeneratorSupport.DeclareInterfaces |
GeneratorSupport.ParameterAttributes |
GeneratorSupport.ReferenceParameters |
GeneratorSupport.ChainedConstructorArguments |
GeneratorSupport.NestedTypes |
GeneratorSupport.MultipleInterfaceMembers |
GeneratorSupport.PublicStaticMembers |
GeneratorSupport.ComplexExpressions |
GeneratorSupport.Win32Resources |
GeneratorSupport.Resources |
GeneratorSupport.PartialTypes |
GeneratorSupport.GenericTypeReference |
GeneratorSupport.GenericTypeDeclaration |
GeneratorSupport.DeclareIndexerProperties;
internal CSharpCodeGenerator() { }
internal CSharpCodeGenerator(IDictionary<string, string> providerOptions)
{
_provOptions = providerOptions;
}
private bool _generatingForLoop;
private static string FileExtension => ".cs";
private static string CompilerName => "csc.exe";
private string CurrentTypeName => _currentClass != null ? _currentClass.Name : "<% unknown %>";
private int Indent
{
get => _output.Indent;
set => _output.Indent = value;
}
private bool IsCurrentInterface => _currentClass != null && !(_currentClass is CodeTypeDelegate) ? _currentClass.IsInterface : false;
private bool IsCurrentClass => _currentClass != null && !(_currentClass is CodeTypeDelegate) ? _currentClass.IsClass : false;
private bool IsCurrentStruct => _currentClass != null && !(_currentClass is CodeTypeDelegate) ? _currentClass.IsStruct : false;
private bool IsCurrentEnum => _currentClass != null && !(_currentClass is CodeTypeDelegate) ? _currentClass.IsEnum : false;
private bool IsCurrentDelegate => _currentClass != null && _currentClass is CodeTypeDelegate;
private static string NullToken => "null";
private ExposedTabStringIndentedTextWriter Output => _output;
private string QuoteSnippetStringCStyle(string value)
{
var b = new StringBuilder(value.Length + 5);
var indentObj = new Indentation(_output, Indent + 1);
b.Append('\"');
bool isStringMultiline = false;
int i = 0;
while (i < value.Length)
{
switch (value[i])
{
case '\r':
b.Append("\\r");
break;
case '\t':
b.Append("\\t");
break;
case '\"':
b.Append("\\\"");
break;
case '\'':
b.Append("\\\'");
break;
case '\\':
b.Append("\\\\");
break;
case '\0':
b.Append("\\0");
break;
case '\n':
b.Append("\\n");
break;
case '\u2028':
case '\u2029':
case '\u0085':
AppendEscapedChar(b, value[i]);
break;
default:
b.Append(value[i]);
break;
}
if (i > 0 && i % MaxLineLength == 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(value[i]) && (i < value.Length - 1) && char.IsLowSurrogate(value[i + 1]))
{
b.Append(value[++i]);
}
if (i != value.Length - 1)
{
b.Append("\" +");
b.Append(Environment.NewLine);
b.Append(indentObj.IndentationString);
b.Append('\"');
isStringMultiline = true;
}
}
++i;
}
b.Append('\"');
if (isStringMultiline)
{
b.Insert(0, '(');
b.Append(')');
}
return b.ToString();
}
private static string QuoteSnippetStringVerbatimStyle(string value)
{
var b = new StringBuilder(value.Length + 5);
b.Append("@\"");
for (int i = 0; i < value.Length; i++)
{
if (value[i] == '\"')
b.Append("\"\"");
else
b.Append(value[i]);
}
b.Append('\"');
return b.ToString();
}
private string QuoteSnippetString(string value)
{
// 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.
#pragma warning disable CA2249 // Consider using 'string.Contains' instead of 'string.IndexOf'
if (value.Length < 256 || value.Length > 1500 || (value.IndexOf('\0') != -1)) // string.Contains(char) is .NetCore2.1+ specific
return QuoteSnippetStringCStyle(value);
#pragma warning restore CA2249
// Otherwise, use 'verbatim' style quoting (e.g. @"foo")
return QuoteSnippetStringVerbatimStyle(value);
}
private void ContinueOnNewLine(string st) => Output.WriteLine(st);
private void OutputIdentifier(string ident) => Output.Write(CreateEscapedIdentifier(ident));
private void OutputType(CodeTypeReference typeRef) => Output.Write(GetTypeOutput(typeRef));
private void GenerateArrayCreateExpression(CodeArrayCreateExpression e)
{
Output.Write("new ");
CodeExpressionCollection init = e.Initializers;
if (init.Count > 0)
{
OutputType(e.CreateType);
if (e.CreateType.ArrayRank == 0)
{
// Unfortunately, many clients are already calling this without array
// types. This will allow new clients to correctly use the array type and
// not break existing clients. For VNext, stop doing this.
Output.Write("[]");
}
Output.WriteLine(" {");
Indent++;
OutputExpressionList(init, newlineBetweenItems: true);
Indent--;
Output.Write('}');
}
else
{
Output.Write(GetBaseTypeOutput(e.CreateType));
Output.Write('[');
if (e.SizeExpression != null)
{
GenerateExpression(e.SizeExpression);
}
else
{
Output.Write(e.Size);
}
Output.Write(']');
int nestedArrayDepth = e.CreateType.NestedArrayDepth;
for (int i = 0; i < nestedArrayDepth - 1; i++)
{
Output.Write("[]");
}
}
}
private void GenerateBaseReferenceExpression() => Output.Write("base");
private void GenerateBinaryOperatorExpression(CodeBinaryOperatorExpression e)
{
bool indentedExpression = false;
Output.Write('(');
GenerateExpression(e.Left);
Output.Write(' ');
if (e.Left is CodeBinaryOperatorExpression || e.Right is CodeBinaryOperatorExpression)
{
// In case the line gets too long with nested binary operators, we need to output them on
// different lines. However we want to indent them to maintain readability, but this needs
// to be done only once;
if (!_inNestedBinary)
{
indentedExpression = true;
_inNestedBinary = true;
Indent += 3;
}
ContinueOnNewLine("");
}
OutputOperator(e.Operator);
Output.Write(' ');
GenerateExpression(e.Right);
Output.Write(')');
if (indentedExpression)
{
Indent -= 3;
_inNestedBinary = false;
}
}
private void GenerateCastExpression(CodeCastExpression e)
{
Output.Write("((");
OutputType(e.TargetType);
Output.Write(")(");
GenerateExpression(e.Expression);
Output.Write("))");
}
public void GenerateCodeFromMember(CodeTypeMember member, TextWriter writer, CodeGeneratorOptions options)
{
if (_output != null)
{
throw new InvalidOperationException(SR.CodeGenReentrance);
}
_options = options ?? new CodeGeneratorOptions();
_output = new ExposedTabStringIndentedTextWriter(writer, _options.IndentString);
try
{
CodeTypeDeclaration dummyClass = new CodeTypeDeclaration();
_currentClass = dummyClass;
GenerateTypeMember(member, dummyClass);
}
finally
{
_currentClass = null;
_output = null;
_options = null;
}
}
private void GenerateDefaultValueExpression(CodeDefaultValueExpression e)
{
Output.Write("default(");
OutputType(e.Type);
Output.Write(')');
}
private void GenerateDelegateCreateExpression(CodeDelegateCreateExpression e)
{
Output.Write("new ");
OutputType(e.DelegateType);
Output.Write('(');
GenerateExpression(e.TargetObject);
Output.Write('.');
OutputIdentifier(e.MethodName);
Output.Write(')');
}
private void GenerateEvents(CodeTypeDeclaration e)
{
foreach (CodeTypeMember current in e.Members)
{
if (current is CodeMemberEvent)
{
_currentMember = current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeMemberEvent imp = (CodeMemberEvent)current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateEvent(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd();
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
private void GenerateFields(CodeTypeDeclaration e)
{
foreach (CodeTypeMember current in e.Members)
{
if (current is CodeMemberField)
{
_currentMember = current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeMemberField imp = (CodeMemberField)current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateField(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd();
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
private void GenerateFieldReferenceExpression(CodeFieldReferenceExpression e)
{
if (e.TargetObject != null)
{
GenerateExpression(e.TargetObject);
Output.Write('.');
}
OutputIdentifier(e.FieldName);
}
private void GenerateArgumentReferenceExpression(CodeArgumentReferenceExpression e) =>
OutputIdentifier(e.ParameterName);
private void GenerateVariableReferenceExpression(CodeVariableReferenceExpression e) =>
OutputIdentifier(e.VariableName);
private void GenerateIndexerExpression(CodeIndexerExpression e)
{
GenerateExpression(e.TargetObject);
Output.Write('[');
bool first = true;
foreach (CodeExpression exp in e.Indices)
{
if (first)
{
first = false;
}
else
{
Output.Write(", ");
}
GenerateExpression(exp);
}
Output.Write(']');
}
private void GenerateArrayIndexerExpression(CodeArrayIndexerExpression e)
{
GenerateExpression(e.TargetObject);
Output.Write('[');
bool first = true;
foreach (CodeExpression exp in e.Indices)
{
if (first)
{
first = false;
}
else
{
Output.Write(", ");
}
GenerateExpression(exp);
}
Output.Write(']');
}
private void GenerateSnippetCompileUnit(CodeSnippetCompileUnit e)
{
GenerateDirectives(e.StartDirectives);
if (e.LinePragma != null) GenerateLinePragmaStart(e.LinePragma);
Output.WriteLine(e.Value);
if (e.LinePragma != null) GenerateLinePragmaEnd();
if (e.EndDirectives.Count > 0)
{
GenerateDirectives(e.EndDirectives);
}
}
private void GenerateSnippetExpression(CodeSnippetExpression e)
{
Output.Write(e.Value);
}
private void GenerateMethodInvokeExpression(CodeMethodInvokeExpression e)
{
GenerateMethodReferenceExpression(e.Method);
Output.Write('(');
OutputExpressionList(e.Parameters);
Output.Write(')');
}
private void GenerateMethodReferenceExpression(CodeMethodReferenceExpression e)
{
if (e.TargetObject != null)
{
if (e.TargetObject is CodeBinaryOperatorExpression)
{
Output.Write('(');
GenerateExpression(e.TargetObject);
Output.Write(')');
}
else
{
GenerateExpression(e.TargetObject);
}
Output.Write('.');
}
OutputIdentifier(e.MethodName);
if (e.TypeArguments.Count > 0)
{
Output.Write(GetTypeArgumentsOutput(e.TypeArguments));
}
}
private static bool GetUserData(CodeObject e, string property, bool defaultValue)
{
object o = e.UserData[property];
if (o != null && o is bool)
{
return (bool)o;
}
return defaultValue;
}
private void GenerateNamespace(CodeNamespace e)
{
GenerateCommentStatements(e.Comments);
GenerateNamespaceStart(e);
if (GetUserData(e, "GenerateImports", true))
{
GenerateNamespaceImports(e);
}
Output.WriteLine();
GenerateTypes(e);
GenerateNamespaceEnd(e);
}
private void GenerateStatement(CodeStatement e)
{
if (e is null)
{
throw new ArgumentNullException(nameof(e));
}
if (e.StartDirectives.Count > 0)
{
GenerateDirectives(e.StartDirectives);
}
if (e.LinePragma != null)
{
GenerateLinePragmaStart(e.LinePragma);
}
if (e is CodeCommentStatement)
{
GenerateCommentStatement((CodeCommentStatement)e);
}
else if (e is CodeMethodReturnStatement)
{
GenerateMethodReturnStatement((CodeMethodReturnStatement)e);
}
else if (e is CodeConditionStatement)
{
GenerateConditionStatement((CodeConditionStatement)e);
}
else if (e is CodeTryCatchFinallyStatement)
{
GenerateTryCatchFinallyStatement((CodeTryCatchFinallyStatement)e);
}
else if (e is CodeAssignStatement)
{
GenerateAssignStatement((CodeAssignStatement)e);
}
else if (e is CodeExpressionStatement)
{
GenerateExpressionStatement((CodeExpressionStatement)e);
}
else if (e is CodeIterationStatement)
{
GenerateIterationStatement((CodeIterationStatement)e);
}
else if (e is CodeThrowExceptionStatement)
{
GenerateThrowExceptionStatement((CodeThrowExceptionStatement)e);
}
else if (e is CodeSnippetStatement)
{
// Don't indent snippet statements, in order to preserve the column
// information from the original code. This improves the debugging
// experience.
int savedIndent = Indent;
Indent = 0;
GenerateSnippetStatement((CodeSnippetStatement)e);
// Restore the indent
Indent = savedIndent;
}
else if (e is CodeVariableDeclarationStatement)
{
GenerateVariableDeclarationStatement((CodeVariableDeclarationStatement)e);
}
else if (e is CodeAttachEventStatement)
{
GenerateAttachEventStatement((CodeAttachEventStatement)e);
}
else if (e is CodeRemoveEventStatement)
{
GenerateRemoveEventStatement((CodeRemoveEventStatement)e);
}
else if (e is CodeGotoStatement)
{
GenerateGotoStatement((CodeGotoStatement)e);
}
else if (e is CodeLabeledStatement)
{
GenerateLabeledStatement((CodeLabeledStatement)e);
}
else
{
throw new ArgumentException(SR.Format(SR.InvalidElementType, e.GetType().FullName), nameof(e));
}
if (e.LinePragma != null)
{
GenerateLinePragmaEnd();
}
if (e.EndDirectives.Count > 0)
{
GenerateDirectives(e.EndDirectives);
}
}
private void GenerateStatements(CodeStatementCollection stmts)
{
foreach (CodeStatement stmt in stmts)
{
((ICodeGenerator)this).GenerateCodeFromStatement(stmt, _output.InnerWriter, _options);
}
}
private void GenerateNamespaceImports(CodeNamespace e)
{
foreach (CodeNamespaceImport imp in e.Imports)
{
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateNamespaceImport(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd();
}
}
private void GenerateEventReferenceExpression(CodeEventReferenceExpression e)
{
if (e.TargetObject != null)
{
GenerateExpression(e.TargetObject);
Output.Write('.');
}
OutputIdentifier(e.EventName);
}
private void GenerateDelegateInvokeExpression(CodeDelegateInvokeExpression e)
{
if (e.TargetObject != null)
{
GenerateExpression(e.TargetObject);
}
Output.Write('(');
OutputExpressionList(e.Parameters);
Output.Write(')');
}
private void GenerateObjectCreateExpression(CodeObjectCreateExpression e)
{
Output.Write("new ");
OutputType(e.CreateType);
Output.Write('(');
OutputExpressionList(e.Parameters);
Output.Write(')');
}
private void GeneratePrimitiveExpression(CodePrimitiveExpression e)
{
if (e.Value is char)
{
GeneratePrimitiveChar((char)e.Value);
}
else if (e.Value is sbyte)
{
// C# has no literal marker for types smaller than Int32
Output.Write(((sbyte)e.Value).ToString(CultureInfo.InvariantCulture));
}
else if (e.Value is ushort)
{
// C# has no literal marker for types smaller than Int32, and you will
// get a conversion error if you use "u" here.
Output.Write(((ushort)e.Value).ToString(CultureInfo.InvariantCulture));
}
else if (e.Value is uint)
{
Output.Write(((uint)e.Value).ToString(CultureInfo.InvariantCulture));
Output.Write('u');
}
else if (e.Value is ulong)
{
Output.Write(((ulong)e.Value).ToString(CultureInfo.InvariantCulture));
Output.Write("ul");
}
else if (e.Value == null)
{
Output.Write(NullToken);
}
else if (e.Value is string)
{
Output.Write(QuoteSnippetString((string)e.Value));
}
else if (e.Value is byte)
{
Output.Write(((byte)e.Value).ToString(CultureInfo.InvariantCulture));
}
else if (e.Value is short)
{
Output.Write(((short)e.Value).ToString(CultureInfo.InvariantCulture));
}
else if (e.Value is int)
{
Output.Write(((int)e.Value).ToString(CultureInfo.InvariantCulture));
}
else if (e.Value is long)
{
Output.Write(((long)e.Value).ToString(CultureInfo.InvariantCulture));
}
else if (e.Value is float)
{
GenerateSingleFloatValue((float)e.Value);
}
else if (e.Value is double)
{
GenerateDoubleValue((double)e.Value);
}
else if (e.Value is decimal)
{
GenerateDecimalValue((decimal)e.Value);
}
else if (e.Value is bool)
{
if ((bool)e.Value)
{
Output.Write("true");
}
else
{
Output.Write("false");
}
}
else
{
throw new ArgumentException(SR.Format(SR.InvalidPrimitiveType, e.Value.GetType()), nameof(e));
}
}
private void GeneratePrimitiveChar(char c)
{
Output.Write('\'');
switch (c)
{
case '\r':
Output.Write("\\r");
break;
case '\t':
Output.Write("\\t");
break;
case '\"':
Output.Write("\\\"");
break;
case '\'':
Output.Write("\\\'");
break;
case '\\':
Output.Write("\\\\");
break;
case '\0':
Output.Write("\\0");
break;
case '\n':
Output.Write("\\n");
break;
case '\u2028':
case '\u2029':
case '\u0084':
case '\u0085':
AppendEscapedChar(null, c);
break;
default:
if (char.IsSurrogate(c))
{
AppendEscapedChar(null, c);
}
else
{
Output.Write(c);
}
break;
}
Output.Write('\'');
}
private void AppendEscapedChar(StringBuilder b, char value)
{
if (b == null)
{
Output.Write("\\u");
Output.Write(((int)value).ToString("X4"));
}
else
{
b.Append("\\u");
b.Append(((int)value).ToString("X4"));
}
}
private void GeneratePropertySetValueReferenceExpression() =>
Output.Write("value");
private void GenerateThisReferenceExpression() =>
Output.Write("this");
private void GenerateExpressionStatement(CodeExpressionStatement e)
{
GenerateExpression(e.Expression);
if (!_generatingForLoop)
{
Output.WriteLine(';');
}
}
private void GenerateIterationStatement(CodeIterationStatement e)
{
_generatingForLoop = true;
Output.Write("for (");
GenerateStatement(e.InitStatement);
Output.Write("; ");
GenerateExpression(e.TestExpression);
Output.Write("; ");
GenerateStatement(e.IncrementStatement);
Output.Write(')');
OutputStartingBrace();
_generatingForLoop = false;
Indent++;
GenerateStatements(e.Statements);
Indent--;
Output.WriteLine('}');
}
private void GenerateThrowExceptionStatement(CodeThrowExceptionStatement e)
{
Output.Write("throw");
if (e.ToThrow != null)
{
Output.Write(' ');
GenerateExpression(e.ToThrow);
}
Output.WriteLine(';');
}
private void GenerateComment(CodeComment e)
{
string commentLineStart = e.DocComment ? "///" : "//";
Output.Write(commentLineStart);
Output.Write(' ');
bool isAfterCommentLineStart = false;
string value = e.Text;
for (int i = 0; i < value.Length; i++)
{
if (isAfterCommentLineStart)
{
if (value[i] == '/' && (e.DocComment || !value.HasCharAt(i + 1, '/')))
{
Output.Write(' ');
}
isAfterCommentLineStart = false;
}
if (value[i] == '\u0000')
{
continue;
}
Output.Write(value[i]);
if (value[i] == '\r')
{
if (value.HasCharAt(i + 1, '\n'))
{ // if next char is '\n', skip it
Output.Write('\n');
i++;
}
_output.InternalOutputTabs();
Output.Write(commentLineStart);
isAfterCommentLineStart = true;
}
else if (value[i] == '\n')
{
_output.InternalOutputTabs();
Output.Write(commentLineStart);
isAfterCommentLineStart = true;
}
else if (value[i] == '\u2028' || value[i] == '\u2029' || value[i] == '\u0085')
{
Output.Write(commentLineStart);
isAfterCommentLineStart = true;
}
}
Output.WriteLine();
}
private void GenerateCommentStatement(CodeCommentStatement e)
{
if (e.Comment == null)
{
throw new ArgumentException(SR.Format(SR.Argument_NullComment, nameof(e)), nameof(e));
}
GenerateComment(e.Comment);
}
private void GenerateCommentStatements(CodeCommentStatementCollection e)
{
foreach (CodeCommentStatement comment in e)
{
GenerateCommentStatement(comment);
}
}
private void GenerateMethodReturnStatement(CodeMethodReturnStatement e)
{
Output.Write("return");
if (e.Expression != null)
{
Output.Write(' ');
GenerateExpression(e.Expression);
}
Output.WriteLine(';');
}
private void GenerateConditionStatement(CodeConditionStatement e)
{
Output.Write("if (");
GenerateExpression(e.Condition);
Output.Write(')');
OutputStartingBrace();
Indent++;
GenerateStatements(e.TrueStatements);
Indent--;
CodeStatementCollection falseStatements = e.FalseStatements;
if (falseStatements.Count > 0)
{
Output.Write('}');
if (_options.ElseOnClosing)
{
Output.Write(' ');
}
else
{
Output.WriteLine();
}
Output.Write("else");
OutputStartingBrace();
Indent++;
GenerateStatements(e.FalseStatements);
Indent--;
}
Output.WriteLine('}');
}
private void GenerateTryCatchFinallyStatement(CodeTryCatchFinallyStatement e)
{
Output.Write("try");
OutputStartingBrace();
Indent++;
GenerateStatements(e.TryStatements);
Indent--;
CodeCatchClauseCollection catches = e.CatchClauses;
if (catches.Count > 0)
{
foreach (CodeCatchClause current in catches)
{
Output.Write('}');
if (_options.ElseOnClosing)
{
Output.Write(' ');
}
else
{
Output.WriteLine();
}
Output.Write("catch (");
OutputType(current.CatchExceptionType);
Output.Write(' ');
OutputIdentifier(current.LocalName);
Output.Write(')');
OutputStartingBrace();
Indent++;
GenerateStatements(current.Statements);
Indent--;
}
}
CodeStatementCollection finallyStatements = e.FinallyStatements;
if (finallyStatements.Count > 0)
{
Output.Write('}');
if (_options.ElseOnClosing)
{
Output.Write(' ');
}
else
{
Output.WriteLine();
}
Output.Write("finally");
OutputStartingBrace();
Indent++;
GenerateStatements(finallyStatements);
Indent--;
}
Output.WriteLine('}');
}
private void GenerateAssignStatement(CodeAssignStatement e)
{
GenerateExpression(e.Left);
Output.Write(" = ");
GenerateExpression(e.Right);
if (!_generatingForLoop)
{
Output.WriteLine(';');
}
}
private void GenerateAttachEventStatement(CodeAttachEventStatement e)
{
GenerateEventReferenceExpression(e.Event);
Output.Write(" += ");
GenerateExpression(e.Listener);
Output.WriteLine(';');
}
private void GenerateRemoveEventStatement(CodeRemoveEventStatement e)
{
GenerateEventReferenceExpression(e.Event);
Output.Write(" -= ");
GenerateExpression(e.Listener);
Output.WriteLine(';');
}
private void GenerateSnippetStatement(CodeSnippetStatement e)
{
Output.WriteLine(e.Value);
}
private void GenerateGotoStatement(CodeGotoStatement e)
{
Output.Write("goto ");
Output.Write(e.Label);
Output.WriteLine(';');
}
private void GenerateLabeledStatement(CodeLabeledStatement e)
{
Indent--;
Output.Write(e.Label);
Output.WriteLine(':');
Indent++;
if (e.Statement != null)
{
GenerateStatement(e.Statement);
}
}
private void GenerateVariableDeclarationStatement(CodeVariableDeclarationStatement e)
{
OutputTypeNamePair(e.Type, e.Name);
if (e.InitExpression != null)
{
Output.Write(" = ");
GenerateExpression(e.InitExpression);
}
if (!_generatingForLoop)
{
Output.WriteLine(';');
}
}
private void GenerateLinePragmaStart(CodeLinePragma e)
{
Output.WriteLine();
Output.Write("#line ");
Output.Write(e.LineNumber);
Output.Write(" \"");
Output.Write(e.FileName);
Output.Write('\"');
Output.WriteLine();
}
private void GenerateLinePragmaEnd()
{
Output.WriteLine();
Output.WriteLine("#line default");
Output.WriteLine("#line hidden");
}
private void GenerateEvent(CodeMemberEvent e)
{
if (IsCurrentDelegate || IsCurrentEnum) return;
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
if (e.PrivateImplementationType == null)
{
OutputMemberAccessModifier(e.Attributes);
}
Output.Write("event ");
string name = e.Name;
if (e.PrivateImplementationType != null)
{
name = GetBaseTypeOutput(e.PrivateImplementationType, preferBuiltInTypes: false) + "." + name;
}
OutputTypeNamePair(e.Type, name);
Output.WriteLine(';');
}
private void GenerateExpression(CodeExpression e)
{
if (e is CodeArrayCreateExpression)
{
GenerateArrayCreateExpression((CodeArrayCreateExpression)e);
}
else if (e is CodeBaseReferenceExpression)
{
GenerateBaseReferenceExpression();
}
else if (e is CodeBinaryOperatorExpression)
{
GenerateBinaryOperatorExpression((CodeBinaryOperatorExpression)e);
}
else if (e is CodeCastExpression)
{
GenerateCastExpression((CodeCastExpression)e);
}
else if (e is CodeDelegateCreateExpression)
{
GenerateDelegateCreateExpression((CodeDelegateCreateExpression)e);
}
else if (e is CodeFieldReferenceExpression)
{
GenerateFieldReferenceExpression((CodeFieldReferenceExpression)e);
}
else if (e is CodeArgumentReferenceExpression)
{
GenerateArgumentReferenceExpression((CodeArgumentReferenceExpression)e);
}
else if (e is CodeVariableReferenceExpression)
{
GenerateVariableReferenceExpression((CodeVariableReferenceExpression)e);
}
else if (e is CodeIndexerExpression)
{
GenerateIndexerExpression((CodeIndexerExpression)e);
}
else if (e is CodeArrayIndexerExpression)
{
GenerateArrayIndexerExpression((CodeArrayIndexerExpression)e);
}
else if (e is CodeSnippetExpression)
{
GenerateSnippetExpression((CodeSnippetExpression)e);
}
else if (e is CodeMethodInvokeExpression)
{
GenerateMethodInvokeExpression((CodeMethodInvokeExpression)e);
}
else if (e is CodeMethodReferenceExpression)
{
GenerateMethodReferenceExpression((CodeMethodReferenceExpression)e);
}
else if (e is CodeEventReferenceExpression)
{
GenerateEventReferenceExpression((CodeEventReferenceExpression)e);
}
else if (e is CodeDelegateInvokeExpression)
{
GenerateDelegateInvokeExpression((CodeDelegateInvokeExpression)e);
}
else if (e is CodeObjectCreateExpression)
{
GenerateObjectCreateExpression((CodeObjectCreateExpression)e);
}
else if (e is CodeParameterDeclarationExpression)
{
GenerateParameterDeclarationExpression((CodeParameterDeclarationExpression)e);
}
else if (e is CodeDirectionExpression)
{
GenerateDirectionExpression((CodeDirectionExpression)e);
}
else if (e is CodePrimitiveExpression)
{
GeneratePrimitiveExpression((CodePrimitiveExpression)e);
}
else if (e is CodePropertyReferenceExpression)
{
GeneratePropertyReferenceExpression((CodePropertyReferenceExpression)e);
}
else if (e is CodePropertySetValueReferenceExpression)
{
GeneratePropertySetValueReferenceExpression();
}
else if (e is CodeThisReferenceExpression)
{
GenerateThisReferenceExpression();
}
else if (e is CodeTypeReferenceExpression)
{
GenerateTypeReferenceExpression((CodeTypeReferenceExpression)e);
}
else if (e is CodeTypeOfExpression)
{
GenerateTypeOfExpression((CodeTypeOfExpression)e);
}
else if (e is CodeDefaultValueExpression)
{
GenerateDefaultValueExpression((CodeDefaultValueExpression)e);
}
else
{
if (e == null)
{
throw new ArgumentNullException(nameof(e));
}
else
{
throw new ArgumentException(SR.Format(SR.InvalidElementType, e.GetType().FullName), nameof(e));
}
}
}
private void GenerateField(CodeMemberField e)
{
if (IsCurrentDelegate || IsCurrentInterface) return;
if (IsCurrentEnum)
{
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
OutputIdentifier(e.Name);
if (e.InitExpression != null)
{
Output.Write(" = ");
GenerateExpression(e.InitExpression);
}
Output.WriteLine(',');
}
else
{
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
OutputMemberAccessModifier(e.Attributes);
OutputVTableModifier(e.Attributes);
OutputFieldScopeModifier(e.Attributes);
OutputTypeNamePair(e.Type, e.Name);
if (e.InitExpression != null)
{
Output.Write(" = ");
GenerateExpression(e.InitExpression);
}
Output.WriteLine(';');
}
}
private void GenerateSnippetMember(CodeSnippetTypeMember e) =>
Output.Write(e.Text);
private void GenerateParameterDeclarationExpression(CodeParameterDeclarationExpression e)
{
if (e.CustomAttributes.Count > 0)
{
// Parameter attributes should be in-line for readability
GenerateAttributes(e.CustomAttributes, null, true);
}
OutputDirection(e.Direction);
OutputTypeNamePair(e.Type, e.Name);
}
private void GenerateEntryPointMethod(CodeEntryPointMethod e)
{
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
Output.Write("public static ");
OutputType(e.ReturnType);
Output.Write(" Main()");
OutputStartingBrace();
Indent++;
GenerateStatements(e.Statements);
Indent--;
Output.WriteLine('}');
}
private void GenerateMethods(CodeTypeDeclaration e)
{
foreach (CodeTypeMember current in e.Members)
{
if (current is CodeMemberMethod && !(current is CodeTypeConstructor) && !(current is CodeConstructor))
{
_currentMember = current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeMemberMethod imp = (CodeMemberMethod)current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
if (current is CodeEntryPointMethod)
{
GenerateEntryPointMethod((CodeEntryPointMethod)current);
}
else
{
GenerateMethod(imp);
}
if (imp.LinePragma != null) GenerateLinePragmaEnd();
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
private void GenerateMethod(CodeMemberMethod e)
{
if (!(IsCurrentClass || IsCurrentStruct || IsCurrentInterface)) return;
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
if (e.ReturnTypeCustomAttributes.Count > 0)
{
GenerateAttributes(e.ReturnTypeCustomAttributes, "return: ");
}
if (!IsCurrentInterface)
{
if (e.PrivateImplementationType == null)
{
OutputMemberAccessModifier(e.Attributes);
OutputVTableModifier(e.Attributes);
OutputMemberScopeModifier(e.Attributes);
}
}
else
{
// interfaces still need "new"
OutputVTableModifier(e.Attributes);
}
OutputType(e.ReturnType);
Output.Write(' ');
if (e.PrivateImplementationType != null)
{
Output.Write(GetBaseTypeOutput(e.PrivateImplementationType, preferBuiltInTypes: false));
Output.Write('.');
}
OutputIdentifier(e.Name);
OutputTypeParameters(e.TypeParameters);
Output.Write('(');
OutputParameters(e.Parameters);
Output.Write(')');
OutputTypeParameterConstraints(e.TypeParameters);
if (!IsCurrentInterface
&& (e.Attributes & MemberAttributes.ScopeMask) != MemberAttributes.Abstract)
{
OutputStartingBrace();
Indent++;
GenerateStatements(e.Statements);
Indent--;
Output.WriteLine('}');
}
else
{
Output.WriteLine(';');
}
}
private void GenerateProperties(CodeTypeDeclaration e)
{
foreach (CodeTypeMember current in e.Members)
{
if (current is CodeMemberProperty)
{
_currentMember = current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeMemberProperty imp = (CodeMemberProperty)current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateProperty(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd();
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
private void GenerateProperty(CodeMemberProperty e)
{
if (!(IsCurrentClass || IsCurrentStruct || IsCurrentInterface)) return;
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
if (!IsCurrentInterface)
{
if (e.PrivateImplementationType == null)
{
OutputMemberAccessModifier(e.Attributes);
OutputVTableModifier(e.Attributes);
OutputMemberScopeModifier(e.Attributes);
}
}
else
{
OutputVTableModifier(e.Attributes);
}
OutputType(e.Type);
Output.Write(' ');
if (e.PrivateImplementationType != null && !IsCurrentInterface)
{
Output.Write(GetBaseTypeOutput(e.PrivateImplementationType, preferBuiltInTypes: false));
Output.Write('.');
}
if (e.Parameters.Count > 0 && string.Equals(e.Name, "Item", StringComparison.OrdinalIgnoreCase))
{
Output.Write("this[");
OutputParameters(e.Parameters);
Output.Write(']');
}
else
{
OutputIdentifier(e.Name);
}
OutputStartingBrace();
Indent++;
if (e.HasGet)
{
if (IsCurrentInterface || (e.Attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract)
{
Output.WriteLine("get;");
}
else
{
Output.Write("get");
OutputStartingBrace();
Indent++;
GenerateStatements(e.GetStatements);
Indent--;
Output.WriteLine('}');
}
}
if (e.HasSet)
{
if (IsCurrentInterface || (e.Attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract)
{
Output.WriteLine("set;");
}
else
{
Output.Write("set");
OutputStartingBrace();
Indent++;
GenerateStatements(e.SetStatements);
Indent--;
Output.WriteLine('}');
}
}
Indent--;
Output.WriteLine('}');
}
private void GenerateSingleFloatValue(float s)
{
if (float.IsNaN(s))
{
Output.Write("float.NaN");
}
else if (float.IsNegativeInfinity(s))
{
Output.Write("float.NegativeInfinity");
}
else if (float.IsPositiveInfinity(s))
{
Output.Write("float.PositiveInfinity");
}
else
{
Output.Write(s.ToString(CultureInfo.InvariantCulture));
Output.Write('F');
}
}
private void GenerateDoubleValue(double d)
{
if (double.IsNaN(d))
{
Output.Write("double.NaN");
}
else if (double.IsNegativeInfinity(d))
{
Output.Write("double.NegativeInfinity");
}
else if (double.IsPositiveInfinity(d))
{
Output.Write("double.PositiveInfinity");
}
else
{
Output.Write(d.ToString("R", CultureInfo.InvariantCulture));
// always mark a double as being a double in case we have no decimal portion (e.g write 1D instead of 1 which is an int)
Output.Write('D');
}
}
private void GenerateDecimalValue(decimal d)
{
Output.Write(d.ToString(CultureInfo.InvariantCulture));
Output.Write('m');
}
private void OutputVTableModifier(MemberAttributes attributes)
{
switch (attributes & MemberAttributes.VTableMask)
{
case MemberAttributes.New:
Output.Write("new ");
break;
}
}
private void OutputMemberAccessModifier(MemberAttributes attributes)
{
switch (attributes & MemberAttributes.AccessMask)
{
case MemberAttributes.Assembly:
Output.Write("internal ");
break;
case MemberAttributes.FamilyAndAssembly:
Output.Write("internal "); /*FamANDAssem*/
break;
case MemberAttributes.Family:
Output.Write("protected ");
break;
case MemberAttributes.FamilyOrAssembly:
Output.Write("protected internal ");
break;
case MemberAttributes.Private:
Output.Write("private ");
break;
case MemberAttributes.Public:
Output.Write("public ");
break;
}
}
private void OutputMemberScopeModifier(MemberAttributes attributes)
{
switch (attributes & MemberAttributes.ScopeMask)
{
case MemberAttributes.Abstract:
Output.Write("abstract ");
break;
case MemberAttributes.Final:
Output.Write("");
break;
case MemberAttributes.Static:
Output.Write("static ");
break;
case MemberAttributes.Override:
Output.Write("override ");
break;
default:
switch (attributes & MemberAttributes.AccessMask)
{
case MemberAttributes.Family:
case MemberAttributes.Public:
case MemberAttributes.Assembly:
Output.Write("virtual ");
break;
default:
// nothing;
break;
}
break;
}
}
private void OutputOperator(CodeBinaryOperatorType op)
{
switch (op)
{
case CodeBinaryOperatorType.Add:
Output.Write('+');
break;
case CodeBinaryOperatorType.Subtract:
Output.Write('-');
break;
case CodeBinaryOperatorType.Multiply:
Output.Write('*');
break;
case CodeBinaryOperatorType.Divide:
Output.Write('/');
break;
case CodeBinaryOperatorType.Modulus:
Output.Write('%');
break;
case CodeBinaryOperatorType.Assign:
Output.Write('=');
break;
case CodeBinaryOperatorType.IdentityInequality:
Output.Write("!=");
break;
case CodeBinaryOperatorType.IdentityEquality:
Output.Write("==");
break;
case CodeBinaryOperatorType.ValueEquality:
Output.Write("==");
break;
case CodeBinaryOperatorType.BitwiseOr:
Output.Write('|');
break;
case CodeBinaryOperatorType.BitwiseAnd:
Output.Write('&');
break;
case CodeBinaryOperatorType.BooleanOr:
Output.Write("||");
break;
case CodeBinaryOperatorType.BooleanAnd:
Output.Write("&&");
break;
case CodeBinaryOperatorType.LessThan:
Output.Write('<');
break;
case CodeBinaryOperatorType.LessThanOrEqual:
Output.Write("<=");
break;
case CodeBinaryOperatorType.GreaterThan:
Output.Write('>');
break;
case CodeBinaryOperatorType.GreaterThanOrEqual:
Output.Write(">=");
break;
}
}
private void OutputFieldScopeModifier(MemberAttributes attributes)
{
switch (attributes & MemberAttributes.ScopeMask)
{
case MemberAttributes.Final:
break;
case MemberAttributes.Static:
Output.Write("static ");
break;
case MemberAttributes.Const:
Output.Write("const ");
break;
default:
break;
}
}
private void GeneratePropertyReferenceExpression(CodePropertyReferenceExpression e)
{
if (e.TargetObject != null)
{
GenerateExpression(e.TargetObject);
Output.Write('.');
}
OutputIdentifier(e.PropertyName);
}
private void GenerateConstructors(CodeTypeDeclaration e)
{
foreach (CodeTypeMember current in e.Members)
{
if (current is CodeConstructor)
{
_currentMember = current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeConstructor imp = (CodeConstructor)current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateConstructor(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd();
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
private void GenerateConstructor(CodeConstructor e)
{
if (!(IsCurrentClass || IsCurrentStruct)) return;
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
OutputMemberAccessModifier(e.Attributes);
OutputIdentifier(CurrentTypeName);
Output.Write('(');
OutputParameters(e.Parameters);
Output.Write(')');
CodeExpressionCollection baseArgs = e.BaseConstructorArgs;
CodeExpressionCollection thisArgs = e.ChainedConstructorArgs;
if (baseArgs.Count > 0)
{
Output.WriteLine(" : ");
Indent++;
Indent++;
Output.Write("base(");
OutputExpressionList(baseArgs);
Output.Write(')');
Indent--;
Indent--;
}
if (thisArgs.Count > 0)
{
Output.WriteLine(" : ");
Indent++;
Indent++;
Output.Write("this(");
OutputExpressionList(thisArgs);
Output.Write(')');
Indent--;
Indent--;
}
OutputStartingBrace();
Indent++;
GenerateStatements(e.Statements);
Indent--;
Output.WriteLine('}');
}
private void GenerateTypeConstructor(CodeTypeConstructor e)
{
if (!(IsCurrentClass || IsCurrentStruct)) return;
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
Output.Write("static ");
Output.Write(CurrentTypeName);
Output.Write("()");
OutputStartingBrace();
Indent++;
GenerateStatements(e.Statements);
Indent--;
Output.WriteLine('}');
}
private void GenerateTypeReferenceExpression(CodeTypeReferenceExpression e) =>
OutputType(e.Type);
private void GenerateTypeOfExpression(CodeTypeOfExpression e)
{
Output.Write("typeof(");
OutputType(e.Type);
Output.Write(')');
}
private void GenerateType(CodeTypeDeclaration e)
{
_currentClass = e;
if (e.StartDirectives.Count > 0)
{
GenerateDirectives(e.StartDirectives);
}
GenerateCommentStatements(e.Comments);
if (e.LinePragma != null) GenerateLinePragmaStart(e.LinePragma);
GenerateTypeStart(e);
if (_options.VerbatimOrder)
{
foreach (CodeTypeMember member in e.Members)
{
GenerateTypeMember(member, e);
}
}
else
{
GenerateFields(e);
GenerateSnippetMembers(e);
GenerateTypeConstructors(e);
GenerateConstructors(e);
GenerateProperties(e);
GenerateEvents(e);
GenerateMethods(e);
GenerateNestedTypes(e);
}
// Nested types clobber the current class, so reset it.
_currentClass = e;
GenerateTypeEnd();
if (e.LinePragma != null) GenerateLinePragmaEnd();
if (e.EndDirectives.Count > 0)
{
GenerateDirectives(e.EndDirectives);
}
}
private void GenerateTypes(CodeNamespace e)
{
foreach (CodeTypeDeclaration c in e.Types)
{
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
((ICodeGenerator)this).GenerateCodeFromType(c, _output.InnerWriter, _options);
}
}
private void GenerateTypeStart(CodeTypeDeclaration e)
{
if (e.CustomAttributes.Count > 0)
{
GenerateAttributes(e.CustomAttributes);
}
if (IsCurrentDelegate)
{
switch (e.TypeAttributes & TypeAttributes.VisibilityMask)
{
case TypeAttributes.Public:
Output.Write("public ");
break;
case TypeAttributes.NotPublic:
default:
break;
}
CodeTypeDelegate del = (CodeTypeDelegate)e;
Output.Write("delegate ");
OutputType(del.ReturnType);
Output.Write(' ');
OutputIdentifier(e.Name);
Output.Write('(');
OutputParameters(del.Parameters);
Output.WriteLine(");");
}
else
{
OutputTypeAttributes(e);
OutputIdentifier(e.Name);
OutputTypeParameters(e.TypeParameters);
bool first = true;
foreach (CodeTypeReference typeRef in e.BaseTypes)
{
if (first)
{
Output.Write(" : ");
first = false;
}
else
{
Output.Write(", ");
}
OutputType(typeRef);
}
OutputTypeParameterConstraints(e.TypeParameters);
OutputStartingBrace();
Indent++;
}
}
private void GenerateTypeMember(CodeTypeMember member, CodeTypeDeclaration declaredType)
{
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (member is CodeTypeDeclaration)
{
((ICodeGenerator)this).GenerateCodeFromType((CodeTypeDeclaration)member, _output.InnerWriter, _options);
// Nested types clobber the current class, so reset it.
_currentClass = declaredType;
// For nested types, comments and line pragmas are handled separately, so return here
return;
}
if (member.StartDirectives.Count > 0)
{
GenerateDirectives(member.StartDirectives);
}
GenerateCommentStatements(member.Comments);
if (member.LinePragma != null)
{
GenerateLinePragmaStart(member.LinePragma);
}
if (member is CodeMemberField)
{
GenerateField((CodeMemberField)member);
}
else if (member is CodeMemberProperty)
{
GenerateProperty((CodeMemberProperty)member);
}
else if (member is CodeMemberMethod)
{
if (member is CodeConstructor)
{
GenerateConstructor((CodeConstructor)member);
}
else if (member is CodeTypeConstructor)
{
GenerateTypeConstructor((CodeTypeConstructor)member);
}
else if (member is CodeEntryPointMethod)
{
GenerateEntryPointMethod((CodeEntryPointMethod)member);
}
else
{
GenerateMethod((CodeMemberMethod)member);
}
}
else if (member is CodeMemberEvent)
{
GenerateEvent((CodeMemberEvent)member);
}
else if (member is CodeSnippetTypeMember)
{
// Don't indent snippets, in order to preserve the column
// information from the original code. This improves the debugging
// experience.
int savedIndent = Indent;
Indent = 0;
GenerateSnippetMember((CodeSnippetTypeMember)member);
// Restore the indent
Indent = savedIndent;
// Generate an extra new line at the end of the snippet.
// If the snippet is comment and this type only contains comments.
// The generated code will not compile.
Output.WriteLine();
}
if (member.LinePragma != null)
{
GenerateLinePragmaEnd();
}
if (member.EndDirectives.Count > 0)
{
GenerateDirectives(member.EndDirectives);
}
}
private void GenerateTypeConstructors(CodeTypeDeclaration e)
{
foreach (CodeTypeMember current in e.Members)
{
if (current is CodeTypeConstructor)
{
_currentMember = current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeTypeConstructor imp = (CodeTypeConstructor)current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateTypeConstructor(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd();
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
private void GenerateSnippetMembers(CodeTypeDeclaration e)
{
bool hasSnippet = false;
foreach (CodeTypeMember current in e.Members)
{
if (current is CodeSnippetTypeMember)
{
hasSnippet = true;
_currentMember = current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeSnippetTypeMember imp = (CodeSnippetTypeMember)current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
// Don't indent snippets, in order to preserve the column
// information from the original code. This improves the debugging
// experience.
int savedIndent = Indent;
Indent = 0;
GenerateSnippetMember(imp);
// Restore the indent
Indent = savedIndent;
if (imp.LinePragma != null) GenerateLinePragmaEnd();
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
// Generate an extra new line at the end of the snippet.
// If the snippet is comment and this type only contains comments.
// The generated code will not compile.
if (hasSnippet)
{
Output.WriteLine();
}
}
private void GenerateNestedTypes(CodeTypeDeclaration e)
{
foreach (CodeTypeMember current in e.Members)
{
if (current is CodeTypeDeclaration)
{
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
CodeTypeDeclaration currentClass = (CodeTypeDeclaration)current;
((ICodeGenerator)this).GenerateCodeFromType(currentClass, _output.InnerWriter, _options);
}
}
}
private void GenerateNamespaces(CodeCompileUnit e)
{
foreach (CodeNamespace n in e.Namespaces)
{
((ICodeGenerator)this).GenerateCodeFromNamespace(n, _output.InnerWriter, _options);
}
}
private void OutputAttributeArgument(CodeAttributeArgument arg)
{
if (!string.IsNullOrEmpty(arg.Name))
{
OutputIdentifier(arg.Name);
Output.Write('=');
}
((ICodeGenerator)this).GenerateCodeFromExpression(arg.Value, _output.InnerWriter, _options);
}
private void OutputDirection(FieldDirection dir)
{
switch (dir)
{
case FieldDirection.In:
break;
case FieldDirection.Out:
Output.Write("out ");
break;
case FieldDirection.Ref:
Output.Write("ref ");
break;
}
}
private void OutputExpressionList(CodeExpressionCollection expressions)
{
OutputExpressionList(expressions, false /*newlineBetweenItems*/);
}
private void OutputExpressionList(CodeExpressionCollection expressions, bool newlineBetweenItems)
{
bool first = true;
Indent++;
foreach (CodeExpression current in expressions)
{
if (first)
{
first = false;
}
else
{
if (newlineBetweenItems)
ContinueOnNewLine(",");
else
Output.Write(", ");
}
((ICodeGenerator)this).GenerateCodeFromExpression(current, _output.InnerWriter, _options);
}
Indent--;
}
private void OutputParameters(CodeParameterDeclarationExpressionCollection parameters)
{
bool first = true;
bool multiline = parameters.Count > ParameterMultilineThreshold;
if (multiline)
{
Indent += 3;
}
foreach (CodeParameterDeclarationExpression current in parameters)
{
if (first)
{
first = false;
}
else
{
Output.Write(", ");
}
if (multiline)
{
ContinueOnNewLine("");
}
GenerateExpression(current);
}
if (multiline)
{
Indent -= 3;
}
}
private void OutputTypeNamePair(CodeTypeReference typeRef, string name)
{
OutputType(typeRef);
Output.Write(' ');
OutputIdentifier(name);
}
private void OutputTypeParameters(CodeTypeParameterCollection typeParameters)
{
if (typeParameters.Count == 0)
{
return;
}
Output.Write('<');
bool first = true;
for (int i = 0; i < typeParameters.Count; i++)
{
if (first)
{
first = false;
}
else
{
Output.Write(", ");
}
if (typeParameters[i].CustomAttributes.Count > 0)
{
GenerateAttributes(typeParameters[i].CustomAttributes, null, true);
Output.Write(' ');
}
Output.Write(typeParameters[i].Name);
}
Output.Write('>');
}
private void OutputTypeParameterConstraints(CodeTypeParameterCollection typeParameters)
{
if (typeParameters.Count == 0)
{
return;
}
for (int i = 0; i < typeParameters.Count; i++)
{
// generating something like: "where KeyType: IComparable, IEnumerable"
Indent++;
bool first = true;
if (typeParameters[i].Constraints.Count > 0)
{
foreach (CodeTypeReference typeRef in typeParameters[i].Constraints)
{
if (first)
{
Output.WriteLine();
Output.Write("where ");
Output.Write(typeParameters[i].Name);
Output.Write(" : ");
first = false;
}
else
{
Output.Write(", ");
}
OutputType(typeRef);
}
}
if (typeParameters[i].HasConstructorConstraint)
{
if (first)
{
Output.WriteLine();
Output.Write("where ");
Output.Write(typeParameters[i].Name);
Output.Write(" : new()");
}
else
{
Output.Write(", new ()");
}
}
Indent--;
}
}
private void OutputTypeAttributes(CodeTypeDeclaration e)
{
if ((e.Attributes & MemberAttributes.New) != 0)
{
Output.Write("new ");
}
TypeAttributes attributes = e.TypeAttributes;
switch (attributes & TypeAttributes.VisibilityMask)
{
case TypeAttributes.Public:
case TypeAttributes.NestedPublic:
Output.Write("public ");
break;
case TypeAttributes.NestedPrivate:
Output.Write("private ");
break;
case TypeAttributes.NestedFamily:
Output.Write("protected ");
break;
case TypeAttributes.NotPublic:
case TypeAttributes.NestedAssembly:
case TypeAttributes.NestedFamANDAssem:
Output.Write("internal ");
break;
case TypeAttributes.NestedFamORAssem:
Output.Write("protected internal ");
break;
}
if (e.IsStruct)
{
if (e.IsPartial)
{
Output.Write("partial ");
}
Output.Write("struct ");
}
else if (e.IsEnum)
{
Output.Write("enum ");
}
else
{
switch (attributes & TypeAttributes.ClassSemanticsMask)
{
case TypeAttributes.Class:
if ((attributes & TypeAttributes.Sealed) == TypeAttributes.Sealed)
{
Output.Write("sealed ");
}
if ((attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract)
{
Output.Write("abstract ");
}
if (e.IsPartial)
{
Output.Write("partial ");
}
Output.Write("class ");
break;
case TypeAttributes.Interface:
if (e.IsPartial)
{
Output.Write("partial ");
}
Output.Write("interface ");
break;
}
}
}
private void GenerateTypeEnd()
{
if (!IsCurrentDelegate)
{
Indent--;
Output.WriteLine('}');
}
}
private void GenerateNamespaceStart(CodeNamespace e)
{
if (!string.IsNullOrEmpty(e.Name))
{
Output.Write("namespace ");
string[] names = e.Name.Split(s_periodArray);
Debug.Assert(names.Length > 0);
OutputIdentifier(names[0]);
for (int i = 1; i < names.Length; i++)
{
Output.Write('.');
OutputIdentifier(names[i]);
}
OutputStartingBrace();
Indent++;
}
}
private void GenerateCompileUnit(CodeCompileUnit e)
{
GenerateCompileUnitStart(e);
GenerateNamespaces(e);
GenerateCompileUnitEnd(e);
}
private void GenerateCompileUnitStart(CodeCompileUnit e)
{
if (e.StartDirectives.Count > 0)
{
GenerateDirectives(e.StartDirectives);
}
Output.WriteLine("//------------------------------------------------------------------------------");
Output.Write("// <");
Output.WriteLine(SR.AutoGen_Comment_Line1);
Output.Write("// ");
Output.WriteLine(SR.AutoGen_Comment_Line2);
Output.WriteLine("//");
Output.Write("// ");
Output.WriteLine(SR.AutoGen_Comment_Line4);
Output.Write("// ");
Output.WriteLine(SR.AutoGen_Comment_Line5);
Output.Write("// </");
Output.WriteLine(SR.AutoGen_Comment_Line1);
Output.WriteLine("//------------------------------------------------------------------------------");
Output.WriteLine();
// CSharp needs to put assembly attributes after using statements.
// Since we need to create an empty namespace even if we don't need it,
// using will generated after assembly attributes.
var importList = new SortedSet<string>(StringComparer.Ordinal);
foreach (CodeNamespace nspace in e.Namespaces)
{
if (string.IsNullOrEmpty(nspace.Name))
{
// mark the namespace to stop it generating its own import list
nspace.UserData["GenerateImports"] = false;
// Collect the unique list of imports
foreach (CodeNamespaceImport import in nspace.Imports)
{
importList.Add(import.Namespace);
}
}
}
// now output the imports
foreach (string import in importList)
{
Output.Write("using ");
OutputIdentifier(import);
Output.WriteLine(';');
}
if (importList.Count > 0)
{
Output.WriteLine();
}
// in C# the best place to put these is at the top level.
if (e.AssemblyCustomAttributes.Count > 0)
{
GenerateAttributes(e.AssemblyCustomAttributes, "assembly: ");
Output.WriteLine();
}
}
private void GenerateCompileUnitEnd(CodeCompileUnit e)
{
if (e.EndDirectives.Count > 0)
{
GenerateDirectives(e.EndDirectives);
}
}
private void GenerateDirectionExpression(CodeDirectionExpression e)
{
OutputDirection(e.Direction);
GenerateExpression(e.Expression);
}
private void GenerateDirectives(CodeDirectiveCollection directives)
{
for (int i = 0; i < directives.Count; i++)
{
CodeDirective directive = directives[i];
if (directive is CodeChecksumPragma)
{
GenerateChecksumPragma((CodeChecksumPragma)directive);
}
else if (directive is CodeRegionDirective)
{
GenerateCodeRegionDirective((CodeRegionDirective)directive);
}
}
}
private void GenerateChecksumPragma(CodeChecksumPragma checksumPragma)
{
Output.Write("#pragma checksum \"");
Output.Write(checksumPragma.FileName);
Output.Write("\" \"");
Output.Write(checksumPragma.ChecksumAlgorithmId.ToString("B", CultureInfo.InvariantCulture));
Output.Write("\" \"");
if (checksumPragma.ChecksumData != null)
{
foreach (byte b in checksumPragma.ChecksumData)
{
Output.Write(b.ToString("X2"));
}
}
Output.WriteLine("\"");
}
private void GenerateCodeRegionDirective(CodeRegionDirective regionDirective)
{
if (regionDirective.RegionMode == CodeRegionMode.Start)
{
Output.Write("#region ");
Output.WriteLine(regionDirective.RegionText);
}
else if (regionDirective.RegionMode == CodeRegionMode.End)
{
Output.WriteLine("#endregion");
}
}
private void GenerateNamespaceEnd(CodeNamespace e)
{
if (!string.IsNullOrEmpty(e.Name))
{
Indent--;
Output.WriteLine('}');
}
}
private void GenerateNamespaceImport(CodeNamespaceImport e)
{
Output.Write("using ");
OutputIdentifier(e.Namespace);
Output.WriteLine(';');
}
private void GenerateAttributeDeclarationsStart() =>
Output.Write('[');
private void GenerateAttributeDeclarationsEnd() =>
Output.Write(']');
private void GenerateAttributes(CodeAttributeDeclarationCollection attributes) =>
GenerateAttributes(attributes, null, inLine: false);
private void GenerateAttributes(CodeAttributeDeclarationCollection attributes, string prefix) =>
GenerateAttributes(attributes, prefix, inLine: false);
private void GenerateAttributes(CodeAttributeDeclarationCollection attributes, string prefix, bool inLine)
{
if (attributes.Count == 0)
{
return;
}
bool paramArray = false;
foreach (CodeAttributeDeclaration current in attributes)
{
// we need to convert paramArrayAttribute to params keyword to
// make csharp compiler happy. In addition, params keyword needs to be after
// other attributes.
if (current.Name.Equals("system.paramarrayattribute", StringComparison.OrdinalIgnoreCase))
{
paramArray = true;
continue;
}
GenerateAttributeDeclarationsStart();
if (prefix != null)
{
Output.Write(prefix);
}
if (current.AttributeType != null)
{
Output.Write(GetTypeOutput(current.AttributeType));
}
Output.Write('(');
bool firstArg = true;
foreach (CodeAttributeArgument arg in current.Arguments)
{
if (firstArg)
{
firstArg = false;
}
else
{
Output.Write(", ");
}
OutputAttributeArgument(arg);
}
Output.Write(')');
GenerateAttributeDeclarationsEnd();
if (inLine)
{
Output.Write(' ');
}
else
{
Output.WriteLine();
}
}
if (paramArray)
{
if (prefix != null)
{
Output.Write(prefix);
}
Output.Write("params");
if (inLine)
{
Output.Write(' ');
}
else
{
Output.WriteLine();
}
}
}
public bool Supports(GeneratorSupport support) => (support & LanguageSupport) == support;
public bool IsValidIdentifier(string value)
{
// identifiers must be 1 char or longer
//
if (string.IsNullOrEmpty(value))
{
return false;
}
if (value.Length > 512)
{
return false;
}
// identifiers cannot be a keyword, unless they are escaped with an '@'
//
if (value[0] != '@')
{
if (CSharpHelpers.IsKeyword(value))
{
return false;
}
}
else
{
value = value.Substring(1);
}
return CodeGenerator.IsValidLanguageIndependentIdentifier(value);
}
public void ValidateIdentifier(string value)
{
if (!IsValidIdentifier(value))
{
throw new ArgumentException(SR.Format(SR.InvalidIdentifier, value), nameof(value));
}
}
public string CreateValidIdentifier(string name)
{
if (name is null)
{
throw new ArgumentNullException(nameof(name));
}
if (CSharpHelpers.IsPrefixTwoUnderscore(name))
{
name = "_" + name;
}
while (CSharpHelpers.IsKeyword(name))
{
name = "_" + name;
}
return name;
}
public string CreateEscapedIdentifier(string name)
{
if (name is null)
{
throw new ArgumentNullException(nameof(name));
}
return CSharpHelpers.CreateEscapedIdentifier(name);
}
// returns the type name without any array declaration.
private string GetBaseTypeOutput(CodeTypeReference typeRef, bool preferBuiltInTypes = true)
{
string s = typeRef.BaseType;
if (preferBuiltInTypes)
{
if (s.Length == 0)
{
return "void";
}
string lowerCaseString = s.ToLowerInvariant().Trim();
switch (lowerCaseString)
{
case "system.int16":
return "short";
case "system.int32":
return "int";
case "system.int64":
return "long";
case "system.string":
return "string";
case "system.object":
return "object";
case "system.boolean":
return "bool";
case "system.void":
return "void";
case "system.char":
return "char";
case "system.byte":
return "byte";
case "system.uint16":
return "ushort";
case "system.uint32":
return "uint";
case "system.uint64":
return "ulong";
case "system.sbyte":
return "sbyte";
case "system.single":
return "float";
case "system.double":
return "double";
case "system.decimal":
return "decimal";
}
}
// replace + with . for nested classes.
//
var sb = new StringBuilder(s.Length + 10);
if ((typeRef.Options & CodeTypeReferenceOptions.GlobalReference) != 0)
{
sb.Append("global::");
}
string baseType = typeRef.BaseType;
int lastIndex = 0;
int currentTypeArgStart = 0;
for (int i = 0; i < baseType.Length; i++)
{
switch (baseType[i])
{
case '+':
case '.':
sb.Append(CreateEscapedIdentifier(baseType.Substring(lastIndex, i - lastIndex)));
sb.Append('.');
i++;
lastIndex = i;
break;
case '`':
sb.Append(CreateEscapedIdentifier(baseType.Substring(lastIndex, i - lastIndex)));
i++; // skip the '
int numTypeArgs = 0;
while (i < baseType.Length && baseType[i] >= '0' && baseType[i] <= '9')
{
numTypeArgs = numTypeArgs * 10 + (baseType[i] - '0');
i++;
}
GetTypeArgumentsOutput(typeRef.TypeArguments, currentTypeArgStart, numTypeArgs, sb);
currentTypeArgStart += numTypeArgs;
// Arity can be in the middle of a nested type name, so we might have a . or + after it.
// Skip it if so.
if (i < baseType.Length && (baseType[i] == '+' || baseType[i] == '.'))
{
sb.Append('.');
i++;
}
lastIndex = i;
break;
}
}
if (lastIndex < baseType.Length)
sb.Append(CreateEscapedIdentifier(baseType.Substring(lastIndex)));
return sb.ToString();
}
private string GetTypeArgumentsOutput(CodeTypeReferenceCollection typeArguments)
{
var sb = new StringBuilder(128);
GetTypeArgumentsOutput(typeArguments, 0, typeArguments.Count, sb);
return sb.ToString();
}
private void GetTypeArgumentsOutput(CodeTypeReferenceCollection typeArguments, int start, int length, StringBuilder sb)
{
sb.Append('<');
bool first = true;
for (int i = start; i < start + length; i++)
{
if (first)
{
first = false;
}
else
{
sb.Append(", ");
}
// it's possible that we call GetTypeArgumentsOutput with an empty typeArguments collection. This is the case
// for open types, so we want to just output the brackets and commas.
if (i < typeArguments.Count)
sb.Append(GetTypeOutput(typeArguments[i]));
}
sb.Append('>');
}
public string GetTypeOutput(CodeTypeReference typeRef)
{
string s = string.Empty;
CodeTypeReference baseTypeRef = typeRef;
while (baseTypeRef.ArrayElementType != null)
{
baseTypeRef = baseTypeRef.ArrayElementType;
}
s += GetBaseTypeOutput(baseTypeRef);
while (typeRef != null && typeRef.ArrayRank > 0)
{
char[] results = new char[typeRef.ArrayRank + 1];
results[0] = '[';
results[typeRef.ArrayRank] = ']';
for (int i = 1; i < typeRef.ArrayRank; i++)
{
results[i] = ',';
}
s += new string(results);
typeRef = typeRef.ArrayElementType;
}
return s;
}
private void OutputStartingBrace()
{
if (_options.BracingStyle == "C")
{
Output.WriteLine();
Output.WriteLine('{');
}
else
{
Output.WriteLine(" {");
}
}
CompilerResults ICodeCompiler.CompileAssemblyFromDom(CompilerParameters options, CodeCompileUnit e)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
try
{
return FromDom(options, e);
}
finally
{
options.TempFiles.SafeDelete();
}
}
CompilerResults ICodeCompiler.CompileAssemblyFromFile(CompilerParameters options, string fileName)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
try
{
return FromFile(options, fileName);
}
finally
{
options.TempFiles.SafeDelete();
}
}
CompilerResults ICodeCompiler.CompileAssemblyFromSource(CompilerParameters options, string source)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
try
{
return FromSource(options, source);
}
finally
{
options.TempFiles.SafeDelete();
}
}
CompilerResults ICodeCompiler.CompileAssemblyFromSourceBatch(CompilerParameters options, string[] sources)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
try
{
return FromSourceBatch(options, sources);
}
finally
{
options.TempFiles.SafeDelete();
}
}
CompilerResults ICodeCompiler.CompileAssemblyFromFileBatch(CompilerParameters options, string[] fileNames)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
if (fileNames is null)
{
throw new ArgumentNullException(nameof(fileNames));
}
try
{
// Try opening the files to make sure they exists. This will throw an exception
// if it doesn't
foreach (string fileName in fileNames)
{
File.OpenRead(fileName).Dispose();
}
return FromFileBatch(options, fileNames);
}
finally
{
options.TempFiles.SafeDelete();
}
}
CompilerResults ICodeCompiler.CompileAssemblyFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
try
{
return FromDomBatch(options, ea);
}
finally
{
options.TempFiles.SafeDelete();
}
}
private CompilerResults FromDom(CompilerParameters options, CodeCompileUnit e)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
return FromDomBatch(options, new CodeCompileUnit[1] { e });
}
private static CompilerResults FromFile(CompilerParameters options, string fileName)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
if (fileName is null)
{
throw new ArgumentNullException(nameof(fileName));
}
// Try opening the file to make sure it exists. This will throw an exception
// if it doesn't
File.OpenRead(fileName).Dispose();
return FromFileBatch(options, new string[1] { fileName });
}
private static CompilerResults FromSource(CompilerParameters options, string source)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
return FromSourceBatch(options, new string[1] { source });
}
private CompilerResults FromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
if (ea is null)
{
throw new ArgumentNullException(nameof(ea));
}
string[] filenames = new string[ea.Length];
for (int i = 0; i < ea.Length; i++)
{
if (ea[i] == null)
{
continue; // the other two batch methods just work if one element is null, so we'll match that.
}
ResolveReferencedAssemblies(options, ea[i]);
filenames[i] = options.TempFiles.AddExtension(i + FileExtension);
using (var fs = new FileStream(filenames[i], FileMode.Create, FileAccess.Write, FileShare.Read))
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
{
((ICodeGenerator)this).GenerateCodeFromCompileUnit(ea[i], sw, _options);
sw.Flush();
}
}
return FromFileBatch(options, filenames);
}
private static void ResolveReferencedAssemblies(CompilerParameters options, CodeCompileUnit e)
{
if (e.ReferencedAssemblies.Count > 0)
{
foreach (string assemblyName in e.ReferencedAssemblies)
{
if (!options.ReferencedAssemblies.Contains(assemblyName))
{
options.ReferencedAssemblies.Add(assemblyName);
}
}
}
}
private static CompilerResults FromSourceBatch(CompilerParameters options, string[] sources)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
if (sources is null)
{
throw new ArgumentNullException(nameof(sources));
}
string[] filenames = new string[sources.Length];
for (int i = 0; i < sources.Length; i++)
{
string name = options.TempFiles.AddExtension(i + FileExtension);
using (var fs = new FileStream(name, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var sw = new StreamWriter(fs, Encoding.UTF8))
{
sw.Write(sources[i]);
sw.Flush();
}
filenames[i] = name;
}
return FromFileBatch(options, filenames);
}
private static string JoinStringArray(string[] sa, string separator)
{
if (sa == null || sa.Length == 0)
{
return string.Empty;
}
if (sa.Length == 1)
{
return "\"" + sa[0] + "\"";
}
var sb = new StringBuilder();
for (int i = 0; i < sa.Length - 1; i++)
{
sb.Append('\"');
sb.Append(sa[i]);
sb.Append('\"');
sb.Append(separator);
}
sb.Append('\"');
sb.Append(sa[sa.Length - 1]);
sb.Append('\"');
return sb.ToString();
}
void ICodeGenerator.GenerateCodeFromType(CodeTypeDeclaration e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SR.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = o ?? new CodeGeneratorOptions();
_output = new ExposedTabStringIndentedTextWriter(w, _options.IndentString);
}
try
{
GenerateType(e);
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
void ICodeGenerator.GenerateCodeFromExpression(CodeExpression e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SR.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = o ?? new CodeGeneratorOptions();
_output = new ExposedTabStringIndentedTextWriter(w, _options.IndentString);
}
try
{
GenerateExpression(e);
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
void ICodeGenerator.GenerateCodeFromCompileUnit(CodeCompileUnit e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SR.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = o ?? new CodeGeneratorOptions();
_output = new ExposedTabStringIndentedTextWriter(w, _options.IndentString);
}
try
{
if (e is CodeSnippetCompileUnit)
{
GenerateSnippetCompileUnit((CodeSnippetCompileUnit)e);
}
else
{
GenerateCompileUnit(e);
}
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
void ICodeGenerator.GenerateCodeFromNamespace(CodeNamespace e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SR.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = o ?? new CodeGeneratorOptions();
_output = new ExposedTabStringIndentedTextWriter(w, _options.IndentString);
}
try
{
GenerateNamespace(e);
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
void ICodeGenerator.GenerateCodeFromStatement(CodeStatement e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SR.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = o ?? new CodeGeneratorOptions();
_output = new ExposedTabStringIndentedTextWriter(w, _options.IndentString);
}
try
{
GenerateStatement(e);
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
}
}
|