|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using Microsoft.CodeDom;
using Microsoft.CodeDom.Compiler;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Collections.Generic;
using System.Runtime.Versioning;
namespace Microsoft.CSharp
{
#region class CSharpCodeProvider
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public class CSharpCodeProvider : CodeDomProvider
{
private CSharpCodeGenerator _generator;
public CSharpCodeProvider()
{
_generator = new CSharpCodeGenerator();
}
public CSharpCodeProvider(IDictionary<string, string> providerOptions)
{
if (providerOptions == null)
{
throw new ArgumentNullException("providerOptions");
}
_generator = new CSharpCodeGenerator(providerOptions);
}
/// <devdoc>
/// <para>Retrieves the default extension to use when saving files using this code dom provider.</para>
/// </devdoc>
public override string FileExtension
{
get
{
return "cs";
}
}
[Obsolete("Callers should not use the ICodeGenerator interface and should instead use the methods directly on the CodeDomProvider class.")]
public override ICodeGenerator CreateGenerator()
{
return (ICodeGenerator)_generator;
}
[Obsolete("Callers should not use the ICodeCompiler interface and should instead use the methods directly on the CodeDomProvider class.")]
public override ICodeCompiler CreateCompiler()
{
return (ICodeCompiler)_generator;
}
/// <devdoc>
/// This method allows a code dom provider implementation to provide a different type converter
/// for a given data type. At design time, a designer may pass data types through this
/// method to see if the code dom provider wants to provide an additional converter.
/// A typical way this would be used is if the language this code dom provider implements
/// does not support all of the values of the MemberAttributes enumeration, or if the language
/// uses different names (Protected instead of Family, for example). The default
/// implementation just calls TypeDescriptor.GetConverter for the given type.
/// </devdoc>
public override TypeConverter GetConverter(Type type)
{
if (type == typeof(MemberAttributes))
{
return CSharpMemberAttributeConverter.Default;
}
else if (type == typeof(TypeAttributes))
{
return CSharpTypeAttributeConverter.Default;
}
return base.GetConverter(type);
}
public override void GenerateCodeFromMember(CodeTypeMember member, TextWriter writer, CodeGeneratorOptions options)
{
_generator.GenerateCodeFromMember(member, writer, options);
}
} // CSharpCodeProvider
#endregion class CSharpCodeProvider
#region class CSharpCodeGenerator
/// <devdoc>
/// <para>
/// C# (C Sharp) Code Generator.
/// </para>
/// </devdoc>
internal class CSharpCodeGenerator : ICodeCompiler, ICodeGenerator
{
private IndentedTextWriter _output;
private CodeGeneratorOptions _options;
private CodeTypeDeclaration _currentClass;
private CodeTypeMember _currentMember;
private bool _inNestedBinary = false;
private 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 |
#if !FEATURE_PAL
GeneratorSupport.Win32Resources |
#endif // !FEATURE_PAL
GeneratorSupport.Resources |
GeneratorSupport.PartialTypes |
GeneratorSupport.GenericTypeReference |
GeneratorSupport.GenericTypeDeclaration |
GeneratorSupport.DeclareIndexerProperties;
private static volatile Regex s_outputRegWithFileAndLine;
private static volatile Regex s_outputRegSimple;
private static readonly string[][] s_keywords = new string[][] {
null, // 1 character
new string[] { // 2 characters
"as",
"do",
"if",
"in",
"is",
},
new string[] { // 3 characters
"for",
"int",
"new",
"out",
"ref",
"try",
},
new string[] { // 4 characters
"base",
"bool",
"byte",
"case",
"char",
"else",
"enum",
"goto",
"lock",
"long",
"null",
"this",
"true",
"uint",
"void",
},
new string[] { // 5 characters
"break",
"catch",
"class",
"const",
"event",
"false",
"fixed",
"float",
"sbyte",
"short",
"throw",
"ulong",
"using",
"while",
},
new string[] { // 6 characters
"double",
"extern",
"object",
"params",
"public",
"return",
"sealed",
"sizeof",
"static",
"string",
"struct",
"switch",
"typeof",
"unsafe",
"ushort",
},
new string[] { // 7 characters
"checked",
"decimal",
"default",
"finally",
"foreach",
"private",
"virtual",
},
new string[] { // 8 characters
"abstract",
"continue",
"delegate",
"explicit",
"implicit",
"internal",
"operator",
"override",
"readonly",
"volatile",
},
new string[] { // 9 characters
"__arglist",
"__makeref",
"__reftype",
"interface",
"namespace",
"protected",
"unchecked",
},
new string[] { // 10 characters
"__refvalue",
"stackalloc",
},
};
internal CSharpCodeGenerator()
{
}
internal CSharpCodeGenerator(IDictionary<string, string> providerOptions)
{
_provOptions = providerOptions;
}
private bool _generatingForLoop = false;
/// <devdoc>
/// <para>
/// Gets
/// or sets the file extension to use for source files.
/// </para>
/// </devdoc>
private string FileExtension { get { return ".cs"; } }
/// <devdoc>
/// <para>
/// Gets or
/// sets the name of the compiler executable.
/// </para>
/// </devdoc>
#if !PLATFORM_UNIX
private string CompilerName { get { return "csc.exe"; } }
#else // !PLATFORM_UNIX
private string CompilerName { get { return "csc"; } }
#endif // !PLATFORM_UNIX
/// <devdoc>
/// <para>
/// Gets or sets the current class name.
/// </para>
/// </devdoc>
private string CurrentTypeName
{
get
{
if (_currentClass != null)
{
return _currentClass.Name;
}
return "<% unknown %>";
}
}
private int Indent
{
get
{
return _output.Indent;
}
set
{
_output.Indent = value;
}
}
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the current object being
/// generated is an interface.
/// </para>
/// </devdoc>
private bool IsCurrentInterface
{
get
{
if (_currentClass != null && !(_currentClass is CodeTypeDelegate))
{
return _currentClass.IsInterface;
}
return false;
}
}
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the current object being generated
/// is a class.
/// </para>
/// </devdoc>
private bool IsCurrentClass
{
get
{
if (_currentClass != null && !(_currentClass is CodeTypeDelegate))
{
return _currentClass.IsClass;
}
return false;
}
}
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the current object being generated
/// is a struct.
/// </para>
/// </devdoc>
private bool IsCurrentStruct
{
get
{
if (_currentClass != null && !(_currentClass is CodeTypeDelegate))
{
return _currentClass.IsStruct;
}
return false;
}
}
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the current object being generated
/// is an enumeration.
/// </para>
/// </devdoc>
private bool IsCurrentEnum
{
get
{
if (_currentClass != null && !(_currentClass is CodeTypeDelegate))
{
return _currentClass.IsEnum;
}
return false;
}
}
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the current object being generated
/// is a delegate.
/// </para>
/// </devdoc>
private bool IsCurrentDelegate
{
get
{
if (_currentClass != null && _currentClass is CodeTypeDelegate)
{
return true;
}
return false;
}
}
/// <devdoc>
/// <para>
/// Gets the token used to represent <see langword='null'/>.
/// </para>
/// </devdoc>
private string NullToken
{
get
{
return "null";
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
private CodeGeneratorOptions Options
{
get
{
return _options;
}
}
private TextWriter Output
{
get
{
return _output;
}
}
/// <devdoc>
/// <para>
/// Provides conversion to C-style formatting with escape codes.
/// </para>
/// </devdoc>
private string QuoteSnippetStringCStyle(string value)
{
StringBuilder b = new StringBuilder(value.Length + 5);
Indentation indentObj = new Indentation((IndentedTextWriter)Output, Indent + 1);
b.Append("\"");
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':
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]);
}
b.Append("\" +");
b.Append(Environment.NewLine);
b.Append(indentObj.IndentationString);
b.Append('\"');
}
++i;
}
b.Append("\"");
return b.ToString();
}
private string QuoteSnippetStringVerbatimStyle(string value)
{
StringBuilder 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();
}
/// <devdoc>
/// <para>
/// Provides conversion to formatting with escape codes.
/// </para>
/// </devdoc>
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.
if (value.Length < 256 || value.Length > 1500 || (value.IndexOf('\0') != -1))
return QuoteSnippetStringCStyle(value);
// Otherwise, use 'verbatim' style quoting (e.g. @"foo")
return QuoteSnippetStringVerbatimStyle(value);
}
/// <devdoc>
/// <para>
/// Processes the <see cref='Microsoft.CodeDom.Compiler.CompilerResults'/> returned from compilation.
/// </para>
/// </devdoc>
private void ProcessCompilerOutputLine(CompilerResults results, string line)
{
if (s_outputRegSimple == null)
{
s_outputRegWithFileAndLine =
new Regex(@"(^(.*)(\(([0-9]+),([0-9]+)\)): )(error|warning) ([A-Z]+[0-9]+) ?: (.*)");
s_outputRegSimple =
new Regex(@"(error|warning) ([A-Z]+[0-9]+) ?: (.*)");
}
//First look for full file info
Match m = s_outputRegWithFileAndLine.Match(line);
bool full;
if (m.Success)
{
full = true;
}
else
{
m = s_outputRegSimple.Match(line);
full = false;
}
if (m.Success)
{
CompilerError ce = new CompilerError();
if (full)
{
ce.FileName = m.Groups[2].Value;
ce.Line = int.Parse(m.Groups[4].Value, CultureInfo.InvariantCulture);
ce.Column = int.Parse(m.Groups[5].Value, CultureInfo.InvariantCulture);
}
if (string.Compare(m.Groups[full ? 6 : 1].Value, "warning", StringComparison.OrdinalIgnoreCase) == 0)
{
ce.IsWarning = true;
}
ce.ErrorNumber = m.Groups[full ? 7 : 2].Value;
ce.ErrorText = m.Groups[full ? 8 : 3].Value;
results.Errors.Add(ce);
}
}
/// <devdoc>
/// <para>
/// Gets the command arguments from the specified <see cref='Microsoft.CodeDom.Compiler.CompilerParameters'/>.
/// </para>
/// </devdoc>
private string CmdArgsFromParameters(CompilerParameters options)
{
StringBuilder sb = new StringBuilder(128);
if (options.GenerateExecutable)
{
sb.Append("/t:exe ");
if (options.MainClass != null && options.MainClass.Length > 0)
{
sb.Append("/main:");
sb.Append(options.MainClass);
sb.Append(" ");
}
}
else
{
sb.Append("/t:library ");
}
// Get UTF8 output from the compiler
sb.Append("/utf8output ");
string coreAssemblyFileName = options.CoreAssemblyFileName;
if (!String.IsNullOrWhiteSpace(coreAssemblyFileName))
{
sb.Append("/nostdlib+ ");
sb.Append("/R:\"").Append(coreAssemblyFileName.Trim()).Append("\" ");
}
foreach (string s in options.ReferencedAssemblies)
{
sb.Append("/R:");
sb.Append("\"");
sb.Append(s);
sb.Append("\"");
sb.Append(" ");
}
sb.Append("/out:");
sb.Append("\"");
sb.Append(options.OutputAssembly);
sb.Append("\"");
sb.Append(" ");
if (options.IncludeDebugInformation)
{
sb.Append("/D:DEBUG ");
sb.Append("/debug+ ");
sb.Append("/optimize- ");
}
else
{
sb.Append("/debug- ");
sb.Append("/optimize+ ");
}
#if !FEATURE_PAL
if (options.Win32Resource != null)
{
sb.Append("/win32res:\"" + options.Win32Resource + "\" ");
}
#endif // !FEATURE_PAL
foreach (string s in options.EmbeddedResources)
{
sb.Append("/res:\"");
sb.Append(s);
sb.Append("\" ");
}
foreach (string s in options.LinkedResources)
{
sb.Append("/linkres:\"");
sb.Append(s);
sb.Append("\" ");
}
if (options.TreatWarningsAsErrors)
{
sb.Append("/warnaserror ");
}
if (options.WarningLevel >= 0)
{
sb.Append("/w:" + options.WarningLevel + " ");
}
if (options.CompilerOptions != null)
{
sb.Append(options.CompilerOptions + " ");
}
return sb.ToString();
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
private void ContinueOnNewLine(string st)
{
Output.WriteLine(st);
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
private string GetResponseFileCmdArgs(CompilerParameters options, string cmdArgs)
{
string responseFileName = options.TempFiles.AddExtension("cmdline");
Stream temp = new FileStream(responseFileName, FileMode.Create, FileAccess.Write, FileShare.Read);
try
{
using (StreamWriter sw = new StreamWriter(temp, Encoding.UTF8))
{
sw.Write(cmdArgs);
sw.Flush();
}
}
finally
{
temp.Dispose();
}
// Always specify the /noconfig flag (outside of the response file)
return "/noconfig /fullpaths @\"" + responseFileName + "\"";
}
private void OutputIdentifier(string ident)
{
Output.Write(CreateEscapedIdentifier(ident));
}
/// <devdoc>
/// <para>
/// Sets the output type.
/// </para>
/// </devdoc>
private void OutputType(CodeTypeReference typeRef)
{
Output.Write(GetTypeOutput(typeRef));
}
/// <devdoc>
/// <para>
/// Generates code for
/// the specified CodeDom based array creation expression representation.
/// </para>
/// </devdoc>
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, true /*newlineBetweenItems*/);
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("[]");
}
}
}
/// <devdoc>
/// <para>
/// Generates
/// code for the specified CodeDom based base reference expression
/// representation.
/// </para>
/// </devdoc>
private void GenerateBaseReferenceExpression(CodeBaseReferenceExpression e)
{
Output.Write("base");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based binary operator
/// expression representation.
/// </para>
/// </devdoc>
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;
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based cast expression
/// representation.
/// </para>
/// </devdoc>
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(SRCodeDom.CodeGenReentrance);
}
_options = (options == null) ? new CodeGeneratorOptions() : options;
_output = new IndentedTextWriter(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(")");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based delegate creation
/// expression representation.
/// </para>
/// </devdoc>
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)
{
IEnumerator en = e.Members.GetEnumerator();
while (en.MoveNext())
{
if (en.Current is CodeMemberEvent)
{
_currentMember = (CodeTypeMember)en.Current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeMemberEvent imp = (CodeMemberEvent)en.Current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateEvent(imp, e);
if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
private void GenerateFields(CodeTypeDeclaration e)
{
IEnumerator en = e.Members.GetEnumerator();
while (en.MoveNext())
{
if (en.Current is CodeMemberField)
{
_currentMember = (CodeTypeMember)en.Current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeMemberField imp = (CodeMemberField)en.Current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateField(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based field reference expression
/// representation.
/// </para>
/// </devdoc>
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);
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based indexer expression
/// representation.
/// </para>
/// </devdoc>
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("]");
}
/// <devdoc>
/// <para> Generates code for the specified snippet code block
/// </para>
/// </devdoc>
private void GenerateSnippetCompileUnit(CodeSnippetCompileUnit e)
{
GenerateDirectives(e.StartDirectives);
if (e.LinePragma != null) GenerateLinePragmaStart(e.LinePragma);
Output.WriteLine(e.Value);
if (e.LinePragma != null) GenerateLinePragmaEnd(e.LinePragma);
if (e.EndDirectives.Count > 0)
{
GenerateDirectives(e.EndDirectives);
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based snippet expression
/// representation.
/// </para>
/// </devdoc>
private void GenerateSnippetExpression(CodeSnippetExpression e)
{
Output.Write(e.Value);
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based method invoke expression
/// representation.
/// </para>
/// </devdoc>
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 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);
}
/// <devdoc>
/// <para>
/// Generates code for
/// the specified CodeDom based statement representation.
/// </para>
/// </devdoc>
private void GenerateStatement(CodeStatement 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(string.Format(SRCodeDom.InvalidElementType, e.GetType().FullName), "e");
}
if (e.LinePragma != null)
{
GenerateLinePragmaEnd(e.LinePragma);
}
if (e.EndDirectives.Count > 0)
{
GenerateDirectives(e.EndDirectives);
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based statement representations.
/// </para>
/// </devdoc>
private void GenerateStatements(CodeStatementCollection stms)
{
IEnumerator en = stms.GetEnumerator();
while (en.MoveNext())
{
((ICodeGenerator)this).GenerateCodeFromStatement((CodeStatement)en.Current, _output.InnerWriter, _options);
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based namespace import
/// representation.
/// </para>
/// </devdoc>
private void GenerateNamespaceImports(CodeNamespace e)
{
IEnumerator en = e.Imports.GetEnumerator();
while (en.MoveNext())
{
CodeNamespaceImport imp = (CodeNamespaceImport)en.Current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateNamespaceImport(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
}
}
private void GenerateEventReferenceExpression(CodeEventReferenceExpression e)
{
if (e.TargetObject != null)
{
GenerateExpression(e.TargetObject);
Output.Write(".");
}
OutputIdentifier(e.EventName);
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based delegate invoke
/// expression representation.
/// </para>
/// </devdoc>
private void GenerateDelegateInvokeExpression(CodeDelegateInvokeExpression e)
{
if (e.TargetObject != null)
{
GenerateExpression(e.TargetObject);
}
Output.Write("(");
OutputExpressionList(e.Parameters);
Output.Write(")");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based object creation expression
/// representation.
/// </para>
/// </devdoc>
private void GenerateObjectCreateExpression(CodeObjectCreateExpression e)
{
Output.Write("new ");
OutputType(e.CreateType);
Output.Write("(");
OutputExpressionList(e.Parameters);
Output.Write(")");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based primitive expression
/// representation.
/// </para>
/// </devdoc>
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());
}
else if (e.Value is UInt16)
{
// C# has no literal marker for types smaller than Int32, and you will
// get a conversion error if you use "u" here.
Output.Write(((UInt16)e.Value).ToString());
}
else if (e.Value is UInt32)
{
Output.Write(((UInt32)e.Value).ToString());
Output.Write("u");
}
else if (e.Value is UInt64)
{
Output.Write(((UInt64)e.Value).ToString());
Output.Write("ul");
}
else
{
GeneratePrimitiveExpressionBase(e);
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based primitive expression
/// representation.
/// </para>
/// </devdoc>
private void GeneratePrimitiveExpressionBase(CodePrimitiveExpression e)
{
if (e.Value == null)
{
Output.Write(NullToken);
}
else if (e.Value is string)
{
Output.Write(QuoteSnippetString((string)e.Value));
}
else if (e.Value is char)
{
Output.Write("'" + e.Value.ToString() + "'");
}
else if (e.Value is byte)
{
Output.Write(((byte)e.Value).ToString());
}
else if (e.Value is Int16)
{
Output.Write(((Int16)e.Value).ToString());
}
else if (e.Value is Int32)
{
Output.Write(((Int32)e.Value).ToString());
}
else if (e.Value is Int64)
{
Output.Write(((Int64)e.Value).ToString());
}
else if (e.Value is Single)
{
GenerateSingleFloatValue((Single)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(string.Format(SRCodeDom.InvalidPrimitiveType, e.Value.GetType().ToString()));
}
}
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", CultureInfo.InvariantCulture));
}
else
{
b.Append("\\u");
b.Append(((int)value).ToString("X4", CultureInfo.InvariantCulture));
}
}
private void GeneratePropertySetValueReferenceExpression(CodePropertySetValueReferenceExpression e)
{
Output.Write("value");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based this reference expression
/// representation.
/// </para>
/// </devdoc>
private void GenerateThisReferenceExpression(CodeThisReferenceExpression e)
{
Output.Write("this");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based method invoke statement
/// representation.
/// </para>
/// </devdoc>
private void GenerateExpressionStatement(CodeExpressionStatement e)
{
GenerateExpression(e.Expression);
if (!_generatingForLoop)
{
Output.WriteLine(";");
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based for loop statement
/// representation.
/// </para>
/// </devdoc>
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("}");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based throw exception statement
/// representation.
/// </para>
/// </devdoc>
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(" ");
string value = e.Text;
for (int i = 0; i < value.Length; i++)
{
if (value[i] == '\u0000')
{
continue;
}
Output.Write(value[i]);
if (value[i] == '\r')
{
if (i < value.Length - 1 && value[i + 1] == '\n')
{ // if next char is '\n', skip it
Output.Write('\n');
i++;
}
((IndentedTextWriter)Output).InternalOutputTabs();
Output.Write(commentLineStart);
}
else if (value[i] == '\n')
{
((IndentedTextWriter)Output).InternalOutputTabs();
Output.Write(commentLineStart);
}
else if (value[i] == '\u2028' || value[i] == '\u2029' || value[i] == '\u0085')
{
Output.Write(commentLineStart);
}
}
Output.WriteLine();
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based comment statement
/// representation.
/// </para>
/// </devdoc>
private void GenerateCommentStatement(CodeCommentStatement e)
{
if (e.Comment == null)
throw new ArgumentException(string.Format(SRCodeDom.Argument_NullComment, "e"), "e");
GenerateComment(e.Comment);
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
private void GenerateCommentStatements(CodeCommentStatementCollection e)
{
foreach (CodeCommentStatement comment in e)
{
GenerateCommentStatement(comment);
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based method return statement
/// representation.
/// </para>
/// </devdoc>
private void GenerateMethodReturnStatement(CodeMethodReturnStatement e)
{
Output.Write("return");
if (e.Expression != null)
{
Output.Write(" ");
GenerateExpression(e.Expression);
}
Output.WriteLine(";");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based if statement
/// representation.
/// </para>
/// </devdoc>
private void GenerateConditionStatement(CodeConditionStatement e)
{
Output.Write("if (");
GenerateExpression(e.Condition);
Output.Write(")");
OutputStartingBrace();
Indent++;
GenerateStatements(e.TrueStatements);
Indent--;
CodeStatementCollection falseStatemetns = e.FalseStatements;
if (falseStatemetns.Count > 0)
{
Output.Write("}");
if (Options.ElseOnClosing)
{
Output.Write(" ");
}
else
{
Output.WriteLine("");
}
Output.Write("else");
OutputStartingBrace();
Indent++;
GenerateStatements(e.FalseStatements);
Indent--;
}
Output.WriteLine("}");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based try catch finally
/// statement representation.
/// </para>
/// </devdoc>
private void GenerateTryCatchFinallyStatement(CodeTryCatchFinallyStatement e)
{
Output.Write("try");
OutputStartingBrace();
Indent++;
GenerateStatements(e.TryStatements);
Indent--;
CodeCatchClauseCollection catches = e.CatchClauses;
if (catches.Count > 0)
{
IEnumerator en = catches.GetEnumerator();
while (en.MoveNext())
{
Output.Write("}");
if (Options.ElseOnClosing)
{
Output.Write(" ");
}
else
{
Output.WriteLine("");
}
CodeCatchClause current = (CodeCatchClause)en.Current;
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("}");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based assignment statement
/// representation.
/// </para>
/// </devdoc>
private void GenerateAssignStatement(CodeAssignStatement e)
{
GenerateExpression(e.Left);
Output.Write(" = ");
GenerateExpression(e.Right);
if (!_generatingForLoop)
{
Output.WriteLine(";");
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based attach event statement
/// representation.
/// </para>
/// </devdoc>
private void GenerateAttachEventStatement(CodeAttachEventStatement e)
{
GenerateEventReferenceExpression(e.Event);
Output.Write(" += ");
GenerateExpression(e.Listener);
Output.WriteLine(";");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based detach event statement
/// representation.
/// </para>
/// </devdoc>
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);
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based variable declaration
/// statement representation.
/// </para>
/// </devdoc>
private void GenerateVariableDeclarationStatement(CodeVariableDeclarationStatement e)
{
OutputTypeNamePair(e.Type, e.Name);
if (e.InitExpression != null)
{
Output.Write(" = ");
GenerateExpression(e.InitExpression);
}
if (!_generatingForLoop)
{
Output.WriteLine(";");
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based line pragma start
/// representation.
/// </para>
/// </devdoc>
private void GenerateLinePragmaStart(CodeLinePragma e)
{
Output.WriteLine("");
Output.Write("#line ");
Output.Write(e.LineNumber);
Output.Write(" \"");
Output.Write(e.FileName);
Output.Write("\"");
Output.WriteLine("");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based line pragma end
/// representation.
/// </para>
/// </devdoc>
private void GenerateLinePragmaEnd(CodeLinePragma e)
{
Output.WriteLine();
Output.WriteLine("#line default");
Output.WriteLine("#line hidden");
}
private void GenerateEvent(CodeMemberEvent e, CodeTypeDeclaration c)
{
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) + "." + name;
}
OutputTypeNamePair(e.Type, name);
Output.WriteLine(";");
}
/// <devdoc>
/// <para>Generates code for the specified CodeDom code expression representation.</para>
/// </devdoc>
private void GenerateExpression(CodeExpression e)
{
if (e is CodeArrayCreateExpression)
{
GenerateArrayCreateExpression((CodeArrayCreateExpression)e);
}
else if (e is CodeBaseReferenceExpression)
{
GenerateBaseReferenceExpression((CodeBaseReferenceExpression)e);
}
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((CodePropertySetValueReferenceExpression)e);
}
else if (e is CodeThisReferenceExpression)
{
GenerateThisReferenceExpression((CodeThisReferenceExpression)e);
}
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("e");
}
else
{
throw new ArgumentException(string.Format(SRCodeDom.InvalidElementType, e.GetType().FullName), "e");
}
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom
/// based field representation.
/// </para>
/// </devdoc>
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(";");
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based snippet class member
/// representation.
/// </para>
/// </devdoc>
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, CodeTypeDeclaration c)
{
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)
{
IEnumerator en = e.Members.GetEnumerator();
while (en.MoveNext())
{
if (en.Current is CodeMemberMethod
&& !(en.Current is CodeTypeConstructor)
&& !(en.Current is CodeConstructor))
{
_currentMember = (CodeTypeMember)en.Current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeMemberMethod imp = (CodeMemberMethod)en.Current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
if (en.Current is CodeEntryPointMethod)
{
GenerateEntryPointMethod((CodeEntryPointMethod)en.Current, e);
}
else
{
GenerateMethod(imp, e);
}
if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based member method
/// representation.
/// </para>
/// </devdoc>
private void GenerateMethod(CodeMemberMethod e, CodeTypeDeclaration c)
{
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));
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)
{
IEnumerator en = e.Members.GetEnumerator();
while (en.MoveNext())
{
if (en.Current is CodeMemberProperty)
{
_currentMember = (CodeTypeMember)en.Current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeMemberProperty imp = (CodeMemberProperty)en.Current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateProperty(imp, e);
if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based property representation.
/// </para>
/// </devdoc>
private void GenerateProperty(CodeMemberProperty e, CodeTypeDeclaration c)
{
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));
Output.Write(".");
}
if (e.Parameters.Count > 0 && String.Compare(e.Name, "Item", StringComparison.OrdinalIgnoreCase) == 0)
{
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(Single 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("R", 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("F" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalDigits, CultureInfo.InvariantCulture));
Output.Write('m');
}
private void OutputVTableModifier(MemberAttributes attributes)
{
switch (attributes & MemberAttributes.VTableMask)
{
case MemberAttributes.New:
Output.Write("new ");
break;
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified member access modifier.
/// </para>
/// </devdoc>
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;
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified operator.
/// </para>
/// </devdoc>
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;
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based property reference
/// expression representation.
/// </para>
/// </devdoc>
private void GeneratePropertyReferenceExpression(CodePropertyReferenceExpression e)
{
if (e.TargetObject != null)
{
GenerateExpression(e.TargetObject);
Output.Write(".");
}
OutputIdentifier(e.PropertyName);
}
private void GenerateConstructors(CodeTypeDeclaration e)
{
IEnumerator en = e.Members.GetEnumerator();
while (en.MoveNext())
{
if (en.Current is CodeConstructor)
{
_currentMember = (CodeTypeMember)en.Current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeConstructor imp = (CodeConstructor)en.Current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateConstructor(imp, e);
if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based constructor
/// representation.
/// </para>
/// </devdoc>
private void GenerateConstructor(CodeConstructor e, CodeTypeDeclaration c)
{
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("}");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based class constructor
/// representation.
/// </para>
/// </devdoc>
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("}");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based type reference expression
/// representation.
/// </para>
/// </devdoc>
private void GenerateTypeReferenceExpression(CodeTypeReferenceExpression e)
{
OutputType(e.Type);
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based type of expression
/// representation.
/// </para>
/// </devdoc>
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(e);
if (e.LinePragma != null) GenerateLinePragmaEnd(e.LinePragma);
if (e.EndDirectives.Count > 0)
{
GenerateDirectives(e.EndDirectives);
}
}
/// <devdoc>
/// <para> Generates code for the specified CodeDom namespace representation and the classes it
/// contains.</para>
/// </devdoc>
private void GenerateTypes(CodeNamespace e)
{
foreach (CodeTypeDeclaration c in e.Types)
{
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
((ICodeGenerator)this).GenerateCodeFromType(c, _output.InnerWriter, _options);
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based class start
/// representation.
/// </para>
/// </devdoc>
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, declaredType);
}
else if (member is CodeMemberMethod)
{
if (member is CodeConstructor)
{
GenerateConstructor((CodeConstructor)member, declaredType);
}
else if (member is CodeTypeConstructor)
{
GenerateTypeConstructor((CodeTypeConstructor)member);
}
else if (member is CodeEntryPointMethod)
{
GenerateEntryPointMethod((CodeEntryPointMethod)member, declaredType);
}
else
{
GenerateMethod((CodeMemberMethod)member, declaredType);
}
}
else if (member is CodeMemberEvent)
{
GenerateEvent((CodeMemberEvent)member, declaredType);
}
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(member.LinePragma);
}
if (member.EndDirectives.Count > 0)
{
GenerateDirectives(member.EndDirectives);
}
}
private void GenerateTypeConstructors(CodeTypeDeclaration e)
{
IEnumerator en = e.Members.GetEnumerator();
while (en.MoveNext())
{
if (en.Current is CodeTypeConstructor)
{
_currentMember = (CodeTypeMember)en.Current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeTypeConstructor imp = (CodeTypeConstructor)en.Current;
if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
GenerateTypeConstructor(imp);
if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
if (_currentMember.EndDirectives.Count > 0)
{
GenerateDirectives(_currentMember.EndDirectives);
}
}
}
}
private void GenerateSnippetMembers(CodeTypeDeclaration e)
{
IEnumerator en = e.Members.GetEnumerator();
bool hasSnippet = false;
while (en.MoveNext())
{
if (en.Current is CodeSnippetTypeMember)
{
hasSnippet = true;
_currentMember = (CodeTypeMember)en.Current;
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
if (_currentMember.StartDirectives.Count > 0)
{
GenerateDirectives(_currentMember.StartDirectives);
}
GenerateCommentStatements(_currentMember.Comments);
CodeSnippetTypeMember imp = (CodeSnippetTypeMember)en.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(imp.LinePragma);
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)
{
IEnumerator en = e.Members.GetEnumerator();
while (en.MoveNext())
{
if (en.Current is CodeTypeDeclaration)
{
if (_options.BlankLinesBetweenMembers)
{
Output.WriteLine();
}
CodeTypeDeclaration currentClass = (CodeTypeDeclaration)en.Current;
((ICodeGenerator)this).GenerateCodeFromType(currentClass, _output.InnerWriter, _options);
}
}
}
/// <devdoc>
/// <para> Generates code for the namepsaces in the specifield CodeDom compile unit.
/// </para>
/// </devdoc>
private void GenerateNamespaces(CodeCompileUnit e)
{
foreach (CodeNamespace n in e.Namespaces)
{
((ICodeGenerator)this).GenerateCodeFromNamespace(n, _output.InnerWriter, _options);
}
}
/// <devdoc>
/// <para>
/// Outputs an argument in a attribute block.
/// </para>
/// </devdoc>
private void OutputAttributeArgument(CodeAttributeArgument arg)
{
if (arg.Name != null && arg.Name.Length > 0)
{
OutputIdentifier(arg.Name);
Output.Write("=");
}
((ICodeGenerator)this).GenerateCodeFromExpression(arg.Value, _output.InnerWriter, _options);
}
/// <devdoc>
/// <para>
/// Generates code for the specified Microsoft.CodeDom.FieldDirection.
/// </para>
/// </devdoc>
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;
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified expression list.
/// </para>
/// </devdoc>
private void OutputExpressionList(CodeExpressionCollection expressions)
{
OutputExpressionList(expressions, false /*newlineBetweenItems*/);
}
/// <devdoc>
/// <para>
/// Generates code for the specified expression list.
/// </para>
/// </devdoc>
private void OutputExpressionList(CodeExpressionCollection expressions, bool newlineBetweenItems)
{
bool first = true;
IEnumerator en = expressions.GetEnumerator();
Indent++;
while (en.MoveNext())
{
if (first)
{
first = false;
}
else
{
if (newlineBetweenItems)
ContinueOnNewLine(",");
else
Output.Write(", ");
}
((ICodeGenerator)this).GenerateCodeFromExpression((CodeExpression)en.Current, _output.InnerWriter, _options);
}
Indent--;
}
/// <devdoc>
/// <para>
/// Generates code for the specified parameters.
/// </para>
/// </devdoc>
private void OutputParameters(CodeParameterDeclarationExpressionCollection parameters)
{
bool first = true;
bool multiline = parameters.Count > ParameterMultilineThreshold;
if (multiline)
{
Indent += 3;
}
IEnumerator en = parameters.GetEnumerator();
while (en.MoveNext())
{
CodeParameterDeclarationExpression current = (CodeParameterDeclarationExpression)en.Current;
if (first)
{
first = false;
}
else
{
Output.Write(", ");
}
if (multiline)
{
ContinueOnNewLine("");
}
GenerateExpression(current);
}
if (multiline)
{
Indent -= 3;
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified object type and name pair.
/// </para>
/// </devdoc>
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"
Output.WriteLine();
Indent++;
bool first = true;
if (typeParameters[i].Constraints.Count > 0)
{
foreach (CodeTypeReference typeRef in typeParameters[i].Constraints)
{
if (first)
{
Output.Write("where ");
Output.Write(typeParameters[i].Name);
Output.Write(" : ");
first = false;
}
else
{
Output.Write(", ");
}
OutputType(typeRef);
}
}
if (typeParameters[i].HasConstructorConstraint)
{
if (first)
{
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;
}
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based class end representation.
/// </para>
/// </devdoc>
private void GenerateTypeEnd(CodeTypeDeclaration e)
{
if (!IsCurrentDelegate)
{
Indent--;
Output.WriteLine("}");
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based namespace start
/// representation.
/// </para>
/// </devdoc>
private void GenerateNamespaceStart(CodeNamespace e)
{
if (e.Name != null && e.Name.Length > 0)
{
Output.Write("namespace ");
string[] names = e.Name.Split('.');
Debug.Assert(names.Length > 0);
OutputIdentifier(names[0]);
for (int i = 1; i < names.Length; i++)
{
Output.Write(".");
OutputIdentifier(names[i]);
}
OutputStartingBrace();
Indent++;
}
}
/// <devdoc>
/// <para> Generates code for the specified CodeDom
/// compile unit representation.</para>
/// </devdoc>
private void GenerateCompileUnit(CodeCompileUnit e)
{
GenerateCompileUnitStart(e);
GenerateNamespaces(e);
GenerateCompileUnitEnd(e);
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based compile unit start
/// representation.
/// </para>
/// </devdoc>
private void GenerateCompileUnitStart(CodeCompileUnit e)
{
if (e.StartDirectives.Count > 0)
{
GenerateDirectives(e.StartDirectives);
}
Output.WriteLine("//------------------------------------------------------------------------------");
Output.WriteLine("// <auto-generated>");
Output.Write("// ");
Output.WriteLine(SRCodeDom.AutoGen_Comment_Line2);
Output.WriteLine("//");
Output.Write("// ");
Output.WriteLine(SRCodeDom.AutoGen_Comment_Line4);
Output.Write("// ");
Output.WriteLine(SRCodeDom.AutoGen_Comment_Line5);
Output.WriteLine("// </auto-generated>");
Output.WriteLine("//------------------------------------------------------------------------------");
Output.WriteLine("");
SortedList importList;
// CSharp needs to put assembly attributes after using statements.
// Since we need to create a empty namespace even if we don't need it,
// using will generated after assembly attributes.
importList = new SortedList(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)
{
if (!importList.Contains(import.Namespace))
{
importList.Add(import.Namespace, import.Namespace);
}
}
}
}
// now output the imports
foreach (string import in importList.Keys)
{
Output.Write("using ");
OutputIdentifier(import);
Output.WriteLine(";");
}
if (importList.Keys.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("");
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based compile unit end
/// representation.
/// </para>
/// </devdoc>
private void GenerateCompileUnitEnd(CodeCompileUnit e)
{
if (e.EndDirectives.Count > 0)
{
GenerateDirectives(e.EndDirectives);
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
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);
}
else if (directive is CodeIfDirective)
{
GenerateCodeIfDirective((CodeIfDirective)directive);
}
}
}
private void GenerateChecksumPragma(CodeChecksumPragma checksumPragma)
{
Output.Write("#pragma checksum \"");
Output.Write(checksumPragma.FileName);
Output.Write("\" \"");
Output.Write(checksumPragma.ChecksumAlgorithmId.ToString("B"));
Output.Write("\" \"");
if (checksumPragma.ChecksumData != null)
{
foreach (Byte b in checksumPragma.ChecksumData)
{
Output.Write(b.ToString("X2", CultureInfo.InvariantCulture));
}
}
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 GenerateCodeIfDirective(CodeIfDirective ifDirective)
{
if (ifDirective.IfMode == CodeIfMode.Start)
{
Output.Write("#if ");
Output.WriteLine(ifDirective.IfText);
}
else if (ifDirective.IfMode == CodeIfMode.End)
{
Output.WriteLine("#endif");
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based namespace end
/// representation.
/// </para>
/// </devdoc>
private void GenerateNamespaceEnd(CodeNamespace e)
{
if (e.Name != null && e.Name.Length > 0)
{
Indent--;
Output.WriteLine("}");
}
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based namespace import
/// representation.
/// </para>
/// </devdoc>
private void GenerateNamespaceImport(CodeNamespaceImport e)
{
Output.Write("using ");
OutputIdentifier(e.Namespace);
Output.WriteLine(";");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based attribute block start
/// representation.
/// </para>
/// </devdoc>
private void GenerateAttributeDeclarationsStart(CodeAttributeDeclarationCollection attributes)
{
Output.Write("[");
}
/// <devdoc>
/// <para>
/// Generates code for the specified CodeDom based attribute block end
/// representation.
/// </para>
/// </devdoc>
private void GenerateAttributeDeclarationsEnd(CodeAttributeDeclarationCollection attributes)
{
Output.Write("]");
}
private void GenerateAttributes(CodeAttributeDeclarationCollection attributes)
{
GenerateAttributes(attributes, null, false);
}
private void GenerateAttributes(CodeAttributeDeclarationCollection attributes, string prefix)
{
GenerateAttributes(attributes, prefix, false);
}
private void GenerateAttributes(CodeAttributeDeclarationCollection attributes, string prefix, bool inLine)
{
if (attributes.Count == 0) return;
IEnumerator en = attributes.GetEnumerator();
bool paramArray = false;
while (en.MoveNext())
{
// we need to convert paramArrayAttribute to params keyword to
// make csharp compiler happy. In addition, params keyword needs to be after
// other attributes.
CodeAttributeDeclaration current = (CodeAttributeDeclaration)en.Current;
if (current.Name.Equals("system.paramarrayattribute", StringComparison.OrdinalIgnoreCase))
{
paramArray = true;
continue;
}
GenerateAttributeDeclarationsStart(attributes);
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(attributes);
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();
}
}
}
private static bool IsKeyword(string value)
{
return FixedStringLookup.Contains(s_keywords, value, false);
}
private static bool IsPrefixTwoUnderscore(string value)
{
if (value.Length < 3)
{
return false;
}
else
{
return ((value[0] == '_') && (value[1] == '_') && (value[2] != '_'));
}
}
public bool Supports(GeneratorSupport support)
{
return ((support & LanguageSupport) == support);
}
/// <devdoc>
/// <para>
/// Gets whether the specified value is a valid identifier.
/// </para>
/// </devdoc>
public bool IsValidIdentifier(string value)
{
// identifiers must be 1 char or longer
//
if (value == null || value.Length == 0)
{
return false;
}
if (value.Length > 512)
return false;
// identifiers cannot be a keyword, unless they are escaped with an '@'
//
if (value[0] != '@')
{
if (IsKeyword(value))
return false;
}
else
{
value = value.Substring(1);
}
return CodeGenerator.IsValidLanguageIndependentIdentifier(value);
}
public void ValidateIdentifier(string value)
{
if (!IsValidIdentifier(value))
{
throw new ArgumentException(string.Format(SRCodeDom.InvalidIdentifier, value));
}
}
public string CreateValidIdentifier(string name)
{
if (IsPrefixTwoUnderscore(name))
{
name = "_" + name;
}
while (IsKeyword(name))
{
name = "_" + name;
}
return name;
}
public string CreateEscapedIdentifier(string name)
{
// Any identifier started with two consecutive underscores are
// reserved by CSharp.
if (IsKeyword(name) || IsPrefixTwoUnderscore(name))
{
return "@" + name;
}
return name;
}
// returns the type name without any array declaration.
private string GetBaseTypeOutput(CodeTypeReference typeRef)
{
string s = typeRef.BaseType;
if (s.Length == 0)
{
s = "void";
return s;
}
string lowerCaseString = s.ToLowerInvariant().Trim();
switch (lowerCaseString)
{
case "system.int16":
s = "short";
break;
case "system.int32":
s = "int";
break;
case "system.int64":
s = "long";
break;
case "system.string":
s = "string";
break;
case "system.object":
s = "object";
break;
case "system.boolean":
s = "bool";
break;
case "system.void":
s = "void";
break;
case "system.char":
s = "char";
break;
case "system.byte":
s = "byte";
break;
case "system.uint16":
s = "ushort";
break;
case "system.uint32":
s = "uint";
break;
case "system.uint64":
s = "ulong";
break;
case "system.sbyte":
s = "sbyte";
break;
case "system.single":
s = "float";
break;
case "system.double":
s = "double";
break;
case "system.decimal":
s = "decimal";
break;
default:
// replace + with . for nested classes.
//
StringBuilder 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();
}
return s;
}
private String GetTypeArgumentsOutput(CodeTypeReferenceCollection typeArguments)
{
StringBuilder 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(" {");
}
}
private CompilerResults FromFileBatch(CompilerParameters options, string[] fileNames)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
if (fileNames == null)
throw new ArgumentNullException("fileNames");
string outputFile = null;
int retValue = 0;
CompilerResults results = new CompilerResults(options.TempFiles);
bool createdEmptyAssembly = false;
if (options.OutputAssembly == null || options.OutputAssembly.Length == 0)
{
string extension = (options.GenerateExecutable) ? "exe" : "dll";
options.OutputAssembly = results.TempFiles.AddExtension(extension, !options.GenerateInMemory);
// Create an empty assembly. This is so that the file will have permissions that
// we can later access with our current credential. If we don't do this, the compiler
// could end up creating an assembly that we cannot open.
new FileStream(options.OutputAssembly, FileMode.Create, FileAccess.ReadWrite).Dispose();
createdEmptyAssembly = true;
}
#if FEATURE_PAL
string pdbname = "ildb";
#else
string pdbname = "pdb";
#endif
// Don't delete pdbs when debug=false but they have specified pdbonly.
if (options.CompilerOptions != null
&& -1 != CultureInfo.InvariantCulture.CompareInfo.IndexOf(options.CompilerOptions, "/debug:pdbonly", CompareOptions.IgnoreCase))
results.TempFiles.AddExtension(pdbname, true);
else
results.TempFiles.AddExtension(pdbname);
string args = CmdArgsFromParameters(options) + " " + JoinStringArray(fileNames, " ");
// Use a response file if the compiler supports it
string responseFileArgs = GetResponseFileCmdArgs(options, args);
string trueArgs = null;
if (responseFileArgs != null)
{
trueArgs = args;
args = responseFileArgs;
}
Compile(options,
RedistVersionInfo.GetCompilerPath(_provOptions, CompilerName),
CompilerName,
args,
ref outputFile,
ref retValue,
trueArgs);
results.NativeCompilerReturnValue = retValue;
// only look for errors/warnings if the compile failed or the caller set the warning level
if (retValue != 0 || options.WarningLevel > 0)
{
// The output of the compiler is in UTF8
string[] lines = ReadAllLines(outputFile, Encoding.UTF8, FileShare.ReadWrite);
foreach (string line in lines)
{
results.Output.Add(line);
ProcessCompilerOutputLine(results, line);
}
// Delete the empty assembly if we created one
if (retValue != 0 && createdEmptyAssembly)
File.Delete(options.OutputAssembly);
}
if (results.Errors.HasErrors || !options.GenerateInMemory)
{
results.PathToAssembly = options.OutputAssembly;
return results;
}
results.CompiledAssembly = Assembly.Load(new AssemblyName(options.OutputAssembly));
return results;
}
private static string[] ReadAllLines(String file, Encoding encoding, FileShare share)
{
using (FileStream stream = File.Open(file, FileMode.Open, FileAccess.Read, share))
{
String line;
List<String> lines = new List<String>();
using (StreamReader sr = new StreamReader(stream, encoding))
while ((line = sr.ReadLine()) != null)
lines.Add(line);
return lines.ToArray();
}
}
/// <internalonly/>
CompilerResults ICodeCompiler.CompileAssemblyFromDom(CompilerParameters options, CodeCompileUnit e)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
try
{
return FromDom(options, e);
}
finally
{
options.TempFiles.SafeDelete();
}
}
/// <internalonly/>
CompilerResults ICodeCompiler.CompileAssemblyFromFile(CompilerParameters options, string fileName)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
try
{
return FromFile(options, fileName);
}
finally
{
options.TempFiles.SafeDelete();
}
}
/// <internalonly/>
CompilerResults ICodeCompiler.CompileAssemblyFromSource(CompilerParameters options, string source)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
try
{
return FromSource(options, source);
}
finally
{
options.TempFiles.SafeDelete();
}
}
/// <internalonly/>
CompilerResults ICodeCompiler.CompileAssemblyFromSourceBatch(CompilerParameters options, string[] sources)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
try
{
return FromSourceBatch(options, sources);
}
finally
{
options.TempFiles.SafeDelete();
}
}
/// <internalonly/>
CompilerResults ICodeCompiler.CompileAssemblyFromFileBatch(CompilerParameters options, string[] fileNames)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
if (fileNames == null)
throw new ArgumentNullException("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)
{
using (Stream str = File.OpenRead(fileName)) { }
}
return FromFileBatch(options, fileNames);
}
finally
{
options.TempFiles.SafeDelete();
}
}
/// <internalonly/>
CompilerResults ICodeCompiler.CompileAssemblyFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
try
{
return FromDomBatch(options, ea);
}
finally
{
options.TempFiles.SafeDelete();
}
}
internal void Compile(CompilerParameters options, string compilerDirectory, string compilerExe, string arguments,
ref string outputFile, ref int nativeReturnValue, string trueArgs)
{
throw new NotImplementedException();
}
/// <devdoc>
/// <para>
/// Compiles the specified compile unit and options, and returns the results
/// from the compilation.
/// </para>
/// </devdoc>
private CompilerResults FromDom(CompilerParameters options, CodeCompileUnit e)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
CodeCompileUnit[] units = new CodeCompileUnit[1];
units[0] = e;
return FromDomBatch(options, units);
}
/// <devdoc>
/// <para>
/// Compiles the specified file using the specified options, and returns the
/// results from the compilation.
/// </para>
/// </devdoc>
private CompilerResults FromFile(CompilerParameters options, string fileName)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
if (fileName == null)
throw new ArgumentNullException("fileName");
// Try opening the file to make sure it exists. This will throw an exception
// if it doesn't
using (Stream str = File.OpenRead(fileName)) { }
string[] filenames = new string[1];
filenames[0] = fileName;
return FromFileBatch(options, filenames);
}
/// <devdoc>
/// <para>
/// Compiles the specified source code using the specified options, and
/// returns the results from the compilation.
/// </para>
/// </devdoc>
private CompilerResults FromSource(CompilerParameters options, string source)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
string[] sources = new string[1];
sources[0] = source;
return FromSourceBatch(options, sources);
}
/// <devdoc>
/// <para>
/// Compiles the specified compile units and
/// options, and returns the results from the compilation.
/// </para>
/// </devdoc>
private CompilerResults FromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
if (ea == null)
throw new ArgumentNullException("ea");
string[] filenames = new string[ea.Length];
CompilerResults results = null;
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);
Stream temp = new FileStream(filenames[i], FileMode.Create, FileAccess.Write, FileShare.Read);
try
{
using (StreamWriter sw = new StreamWriter(temp, Encoding.UTF8))
{
((ICodeGenerator)this).GenerateCodeFromCompileUnit(ea[i], sw, Options);
sw.Flush();
}
}
finally
{
temp.Dispose();
}
}
results = FromFileBatch(options, filenames);
return results;
}
/// <devdoc>
/// <para>
/// Because CodeCompileUnit and CompilerParameters both have a referenced assemblies
/// property, they must be reconciled. However, because you can compile multiple
/// compile units with one set of options, it will simply merge them.
/// </para>
/// </devdoc>
private 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);
}
}
}
}
/// <devdoc>
/// <para>
/// Compiles the specified source code strings using the specified options, and
/// returns the results from the compilation.
/// </para>
/// </devdoc>
private CompilerResults FromSourceBatch(CompilerParameters options, string[] sources)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
if (sources == null)
throw new ArgumentNullException("sources");
string[] filenames = new string[sources.Length];
CompilerResults results = null;
for (int i = 0; i < sources.Length; i++)
{
string name = options.TempFiles.AddExtension(i + FileExtension);
Stream temp = new FileStream(name, FileMode.Create, FileAccess.Write, FileShare.Read);
try
{
using (StreamWriter sw = new StreamWriter(temp, Encoding.UTF8))
{
sw.Write(sources[i]);
sw.Flush();
}
}
finally
{
temp.Dispose();
}
filenames[i] = name;
}
results = FromFileBatch(options, filenames);
return results;
}
/// <devdoc>
/// <para>Joins the specified string arrays.</para>
/// </devdoc>
private static string JoinStringArray(string[] sa, string separator)
{
if (sa == null || sa.Length == 0)
return String.Empty;
if (sa.Length == 1)
{
return "\"" + sa[0] + "\"";
}
StringBuilder 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();
}
/// <internalonly/>
void ICodeGenerator.GenerateCodeFromType(CodeTypeDeclaration e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SRCodeDom.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = (o == null) ? new CodeGeneratorOptions() : o;
_output = new IndentedTextWriter(w, _options.IndentString);
}
try
{
GenerateType(e);
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
/// <internalonly/>
void ICodeGenerator.GenerateCodeFromExpression(CodeExpression e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SRCodeDom.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = (o == null) ? new CodeGeneratorOptions() : o;
_output = new IndentedTextWriter(w, _options.IndentString);
}
try
{
GenerateExpression(e);
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
/// <internalonly/>
void ICodeGenerator.GenerateCodeFromCompileUnit(CodeCompileUnit e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SRCodeDom.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = (o == null) ? new CodeGeneratorOptions() : o;
_output = new IndentedTextWriter(w, _options.IndentString);
}
try
{
if (e is CodeSnippetCompileUnit)
{
GenerateSnippetCompileUnit((CodeSnippetCompileUnit)e);
}
else
{
GenerateCompileUnit(e);
}
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
/// <internalonly/>
void ICodeGenerator.GenerateCodeFromNamespace(CodeNamespace e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SRCodeDom.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = (o == null) ? new CodeGeneratorOptions() : o;
_output = new IndentedTextWriter(w, _options.IndentString);
}
try
{
GenerateNamespace(e);
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
/// <internalonly/>
void ICodeGenerator.GenerateCodeFromStatement(CodeStatement e, TextWriter w, CodeGeneratorOptions o)
{
bool setLocal = false;
if (_output != null && w != _output.InnerWriter)
{
throw new InvalidOperationException(SRCodeDom.CodeGenOutputWriter);
}
if (_output == null)
{
setLocal = true;
_options = (o == null) ? new CodeGeneratorOptions() : o;
_output = new IndentedTextWriter(w, _options.IndentString);
}
try
{
GenerateStatement(e);
}
finally
{
if (setLocal)
{
_output = null;
_options = null;
}
}
}
} // CSharpCodeGenerator
#endregion class CSharpCodeGenerator
#region class CSharpTypeAttributeConverter
internal class CSharpTypeAttributeConverter : CSharpModifierAttributeConverter
{
private static volatile string[] s_names;
private static volatile object[] s_values;
private static volatile CSharpTypeAttributeConverter s_defaultConverter;
private CSharpTypeAttributeConverter()
{
// no need to create an instance; use Default
}
public static CSharpTypeAttributeConverter Default
{
get
{
if (s_defaultConverter == null)
{
s_defaultConverter = new CSharpTypeAttributeConverter();
}
return s_defaultConverter;
}
}
/// <devdoc>
/// Retrieves an array of names for attributes.
/// </devdoc>
protected override string[] Names
{
get
{
if (s_names == null)
{
s_names = new string[] {
"Public",
"Internal"
};
}
return s_names;
}
}
/// <devdoc>
/// Retrieves an array of values for attributes.
/// </devdoc>
protected override object[] Values
{
get
{
if (s_values == null)
{
s_values = new object[] {
(object)TypeAttributes.Public,
(object)TypeAttributes.NotPublic
};
}
return s_values;
}
}
protected override object DefaultValue
{
get
{
return TypeAttributes.NotPublic;
}
}
} // CSharpTypeAttributeConverter
#endregion class CSharpTypeAttributeConverter
#region class CSharpMemberAttributeConverter
internal class CSharpMemberAttributeConverter : CSharpModifierAttributeConverter
{
private static volatile string[] s_names;
private static volatile object[] s_values;
private static volatile CSharpMemberAttributeConverter s_defaultConverter;
private CSharpMemberAttributeConverter()
{
// no need to create an instance; use Default
}
public static CSharpMemberAttributeConverter Default
{
get
{
if (s_defaultConverter == null)
{
s_defaultConverter = new CSharpMemberAttributeConverter();
}
return s_defaultConverter;
}
}
/// <devdoc>
/// Retrieves an array of names for attributes.
/// </devdoc>
protected override string[] Names
{
get
{
if (s_names == null)
{
s_names = new string[] {
"Public",
"Protected",
"Protected Internal",
"Internal",
"Private"
};
}
return s_names;
}
}
/// <devdoc>
/// Retrieves an array of values for attributes.
/// </devdoc>
protected override object[] Values
{
get
{
if (s_values == null)
{
s_values = new object[] {
(object)MemberAttributes.Public,
(object)MemberAttributes.Family,
(object)MemberAttributes.FamilyOrAssembly,
(object)MemberAttributes.Assembly,
(object)MemberAttributes.Private
};
}
return s_values;
}
}
protected override object DefaultValue
{
get
{
return MemberAttributes.Private;
}
}
} // CSharpMemberAttributeConverter
#endregion class CSharpMemberAttributeConverter
#region class CSharpModifierAttributeConverter
/// <devdoc>
/// This type converter provides common values for MemberAttributes
/// </devdoc>
internal abstract class CSharpModifierAttributeConverter : TypeConverter
{
protected abstract object[] Values { get; }
protected abstract string[] Names { get; }
protected abstract object DefaultValue { get; }
/// <devdoc>
/// We override this because we can convert from string types.
/// </devdoc>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <devdoc>
/// Converts the given object to the converter's native type.
/// </devdoc>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
string name = (string)value;
string[] names = Names;
for (int i = 0; i < names.Length; i++)
{
if (names[i].Equals(name))
{
return Values[i];
}
}
}
return DefaultValue;
}
/// <devdoc>
/// Converts the given object to another type. The most common types to convert
/// are to and from a string object. The default implementation will make a call
/// to ToString on the object if the object is valid and if the destination
/// type is string. If this cannot convert to the desitnation type, this will
/// throw a NotSupportedException.
/// </devdoc>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == null)
{
throw new ArgumentNullException("destinationType");
}
if (destinationType == typeof(string))
{
object[] modifiers = Values;
for (int i = 0; i < modifiers.Length; i++)
{
if (modifiers[i].Equals(value))
{
return Names[i];
}
}
return SRCodeDom.toStringUnknown;
}
return base.ConvertTo(context, culture, value, destinationType);
}
} // CSharpModifierAttributeConverter
#endregion class CSharpModifierAttributeConverter
}
|