1 //------------------------------------------------------------------------------
2 // <copyright file="VBCodeProvider.cs" company="Microsoft">
4 // <OWNER>gpaperin</OWNER>
5 // Copyright (c) Microsoft Corporation. All rights reserved.
7 //------------------------------------------------------------------------------
9 using System.Diagnostics;
12 using System.Collections;
13 using System.Collections.Specialized;
14 using System.ComponentModel;
15 using System.Reflection;
18 using System.Text.RegularExpressions;
19 using System.Globalization;
20 using System.CodeDom.Compiler;
21 using System.Security.Permissions;
22 using Microsoft.Win32;
23 using System.Collections.Generic;
24 using System.Runtime.Versioning;
26 namespace Microsoft.VisualBasic {
28 #region class VBCodeProvider
31 /// <para>[To be supplied.]</para>
33 [PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")]
34 [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]
35 public class VBCodeProvider: CodeDomProvider {
36 private VBCodeGenerator generator;
38 public VBCodeProvider() {
39 generator = new VBCodeGenerator();
42 public VBCodeProvider(IDictionary<string, string> providerOptions) {
43 if (providerOptions == null) {
44 throw new ArgumentNullException("providerOptions");
47 generator = new VBCodeGenerator(providerOptions);
51 /// <para>Retrieves the default extension to use when saving files using this code dom provider.</para>
53 public override string FileExtension {
60 /// <para>Returns flags representing language variations.</para>
62 public override LanguageOptions LanguageOptions {
64 return LanguageOptions.CaseInsensitive;
68 [Obsolete("Callers should not use the ICodeGenerator interface and should instead use the methods directly on the CodeDomProvider class.")]
69 public override ICodeGenerator CreateGenerator() {
70 return (ICodeGenerator)generator;
73 [Obsolete("Callers should not use the ICodeCompiler interface and should instead use the methods directly on the CodeDomProvider class.")]
74 public override ICodeCompiler CreateCompiler() {
75 return (ICodeCompiler)generator;
79 /// This method allows a code dom provider implementation to provide a different type converter
80 /// for a given data type. At design time, a designer may pass data types through this
81 /// method to see if the code dom provider wants to provide an additional converter.
82 /// A typical way this would be used is if the language this code dom provider implements
83 /// does not support all of the values of the MemberAttributes enumeration, or if the language
84 /// uses different names (Protected instead of Family, for example). The default
85 /// implementation just calls TypeDescriptor.GetConverter for the given type.
87 public override TypeConverter GetConverter(Type type) {
88 if (type == typeof(MemberAttributes)) {
89 return VBMemberAttributeConverter.Default;
91 else if(type == typeof(TypeAttributes)) {
92 return VBTypeAttributeConverter.Default;
95 return base.GetConverter(type);
98 public override void GenerateCodeFromMember(CodeTypeMember member, TextWriter writer, CodeGeneratorOptions options) {
99 generator.GenerateCodeFromMember(member, writer, options);
104 #endregion class VBCodeProvider
107 #region class VBCodeGenerator
111 /// Visual Basic 7 Code Generator.
114 internal class VBCodeGenerator : CodeCompiler {
115 private const int MaxLineLength = 80;
117 private const GeneratorSupport LanguageSupport = GeneratorSupport.EntryPointMethod |
118 GeneratorSupport.GotoStatements |
119 GeneratorSupport.ArraysOfArrays |
120 GeneratorSupport.MultidimensionalArrays |
121 GeneratorSupport.StaticConstructors |
122 GeneratorSupport.ReturnTypeAttributes |
123 GeneratorSupport.AssemblyAttributes |
124 GeneratorSupport.TryCatchStatements |
125 GeneratorSupport.DeclareValueTypes |
126 GeneratorSupport.DeclareEnums |
127 GeneratorSupport.DeclareEvents |
128 GeneratorSupport.DeclareDelegates |
129 GeneratorSupport.DeclareInterfaces |
130 GeneratorSupport.ParameterAttributes |
131 GeneratorSupport.ReferenceParameters |
132 GeneratorSupport.ChainedConstructorArguments |
133 GeneratorSupport.NestedTypes |
134 GeneratorSupport.MultipleInterfaceMembers |
135 GeneratorSupport.PublicStaticMembers |
136 GeneratorSupport.ComplexExpressions |
137 GeneratorSupport.Win32Resources |
138 GeneratorSupport.Resources|
139 GeneratorSupport.PartialTypes|
140 GeneratorSupport.GenericTypeReference |
141 GeneratorSupport.GenericTypeDeclaration |
142 GeneratorSupport.DeclareIndexerProperties;
144 private static volatile Regex outputReg;
146 private int statementDepth = 0;
147 private IDictionary<string, string> provOptions;
149 // This is the keyword list. To minimize search time and startup time, this is stored by length
150 // and then alphabetically for use by FixedStringLookup.Contains.
151 private static readonly string[][] keywords = new string[][] {
153 new string[] { // 2 characters
165 new string[] { // 3 characters
182 new string[] { // 4 characters
214 new string[] { // 5 characters
244 new string[] { // 6 characters
267 new string[] { // 7 characters
288 new string[] { // 8 characters
303 new string [] { // 9 characters
314 new string [] { // 10 characters
322 new string[] { // 11 characters
326 new string[] { // 12 characters
329 new string [] { // 13 characters
332 // class_finalize and class_initialize are not keywords anymore,
333 // but it will be nice to escape them to avoid warning
334 new string [] { // 14 characters
339 null, // 15 characters
345 internal VBCodeGenerator() {
348 internal VBCodeGenerator(IDictionary<string, string> providerOptions) {
349 provOptions = providerOptions;
354 static VBCodeGenerator() {
355 FixedStringLookup.VerifyLookupTable(keywords, true);
357 // Sanity check: try some values;
358 Debug.Assert(IsKeyword("for"));
359 Debug.Assert(IsKeyword("foR"));
360 Debug.Assert(IsKeyword("cdec"));
361 Debug.Assert(!IsKeyword("cdab"));
362 Debug.Assert(!IsKeyword("cdum"));
368 /// Gets or the file extension to use for source files.
371 protected override string FileExtension { get { return ".vb"; } }
375 /// Gets the name of the compiler exe
378 protected override string CompilerName { get { return "vbc.exe"; } }
382 /// Tells whether or not the current class should be generated as a module
385 private bool IsCurrentModule {
387 return (IsCurrentClass && GetUserData(CurrentClass, "Module", false));
393 /// Gets the token that is used to represent <see langword='null'/>.
396 protected override string NullToken {
402 private void EnsureInDoubleQuotes(ref bool fInDoubleQuotes, StringBuilder b) {
403 if (fInDoubleQuotes) return;
405 fInDoubleQuotes = true;
408 private void EnsureNotInDoubleQuotes(ref bool fInDoubleQuotes, StringBuilder b) {
409 if (!fInDoubleQuotes) return;
411 fInDoubleQuotes = false;
416 /// Provides conversion to formatting with escape codes.
419 protected override string QuoteSnippetString(string value) {
420 StringBuilder b = new StringBuilder(value.Length+5);
422 bool fInDoubleQuotes = true;
423 Indentation indentObj = new Indentation((IndentedTextWriter)Output, Indent + 1);
428 while(i < value.Length) {
432 // These are the inward sloping quotes used by default in some cultures like CHS.
433 // VBC.EXE does a mapping ANSI that results in it treating these as syntactically equivalent to a
434 // regular double quote.
438 EnsureInDoubleQuotes(ref fInDoubleQuotes, b);
443 EnsureNotInDoubleQuotes(ref fInDoubleQuotes, b);
444 if (i < value.Length - 1 && value[i+1] == '\n') {
445 b.Append("&Global.Microsoft.VisualBasic.ChrW(13)&Global.Microsoft.VisualBasic.ChrW(10)");
449 b.Append("&Global.Microsoft.VisualBasic.ChrW(13)");
453 EnsureNotInDoubleQuotes(ref fInDoubleQuotes, b);
454 b.Append("&Global.Microsoft.VisualBasic.ChrW(9)");
457 EnsureNotInDoubleQuotes(ref fInDoubleQuotes, b);
458 b.Append("&Global.Microsoft.VisualBasic.ChrW(0)");
461 EnsureNotInDoubleQuotes(ref fInDoubleQuotes, b);
462 b.Append("&Global.Microsoft.VisualBasic.ChrW(10)");
466 EnsureNotInDoubleQuotes(ref fInDoubleQuotes, b);
467 AppendEscapedChar(b,ch);
470 EnsureInDoubleQuotes(ref fInDoubleQuotes, b);
475 if (i > 0 && i % MaxLineLength == 0) {
477 // If current character is a high surrogate and the following
478 // character is a low surrogate, don't break them.
479 // Otherwise when we write the string to a file, we might lose
482 if( Char.IsHighSurrogate(value[i])
483 && (i < value.Length -1)
484 && Char.IsLowSurrogate(value[i+1])){
485 b.Append(value[++i]);
490 fInDoubleQuotes = true;
493 b.Append(Environment.NewLine);
494 b.Append(indentObj.IndentationString);
507 private static void AppendEscapedChar(StringBuilder b, char value) {
508 b.Append("&Global.Microsoft.VisualBasic.ChrW(");
509 b.Append(((int)value).ToString(CultureInfo.InvariantCulture));
513 protected override void ProcessCompilerOutputLine(CompilerResults results, string line) {
514 if (outputReg == null) {
515 outputReg = new Regex(@"^([^(]*)\(?([0-9]*)\)? ?:? ?(error|warning) ([A-Z]+[0-9]+) ?: ((.|\n)*)");
517 Match m = outputReg.Match(line);
519 CompilerError ce = new CompilerError();
520 ce.FileName = m.Groups[1].Value;
521 string rawLine = m.Groups[2].Value;
522 if (rawLine != null && rawLine.Length > 0) {
523 ce.Line = int.Parse(rawLine, CultureInfo.InvariantCulture);
525 if (string.Compare(m.Groups[3].Value, "warning", StringComparison.OrdinalIgnoreCase) == 0) {
528 ce.ErrorNumber = m.Groups[4].Value;
529 ce.ErrorText = m.Groups[5].Value;
530 results.Errors.Add(ce);
534 [ResourceExposure(ResourceScope.None)]
535 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
536 protected override string CmdArgsFromParameters(CompilerParameters options) {
537 // The VB Compiler throws an error if an empty string is specified as an assembly reference.
538 foreach (string s in options.ReferencedAssemblies)
540 if(String.IsNullOrEmpty(s))
542 throw new ArgumentException(SR.GetString(SR.NullOrEmpty_Value_in_Property, "ReferencedAssemblies"), "options");
546 StringBuilder sb = new StringBuilder(128);
547 if (options.GenerateExecutable) {
548 sb.Append("/t:exe ");
549 if (options.MainClass != null && options.MainClass.Length > 0) {
551 sb.Append(options.MainClass);
556 sb.Append("/t:library ");
559 // Get UTF8 output from the compiler
560 sb.Append("/utf8output ");
562 string coreAssemblyFileName = options.CoreAssemblyFileName;
564 if (String.IsNullOrWhiteSpace(options.CoreAssemblyFileName)) {
565 string probableCoreAssemblyFilePath;
566 if (CodeDomProvider.TryGetProbableCoreAssemblyFilePath(options, out probableCoreAssemblyFilePath)) {
567 coreAssemblyFileName = probableCoreAssemblyFilePath;
571 if (!String.IsNullOrWhiteSpace(coreAssemblyFileName)) {
573 string asmblFilePath = coreAssemblyFileName.Trim();
574 string asmblFileDir = Path.GetDirectoryName(asmblFilePath);
576 sb.Append("/nostdlib ");
577 sb.Append("/sdkpath:\"").Append(asmblFileDir).Append("\" ");
578 sb.Append("/R:\"").Append(asmblFilePath).Append("\" ");
581 foreach (string s in options.ReferencedAssemblies) {
583 // Ignore any Microsoft.VisualBasic.dll, since Visual Basic implies it (
584 string fileName = Path.GetFileName(s);
585 if (string.Compare(fileName, "Microsoft.VisualBasic.dll", StringComparison.OrdinalIgnoreCase) == 0)
588 // Same deal for mscorlib (
589 if (string.Compare(fileName, "mscorlib.dll", StringComparison.OrdinalIgnoreCase) == 0)
601 sb.Append(options.OutputAssembly);
605 if (options.IncludeDebugInformation) {
606 sb.Append("/D:DEBUG=1 ");
607 sb.Append("/debug+ ");
610 sb.Append("/debug- ");
613 if (options.Win32Resource != null) {
614 sb.Append("/win32resource:\"" + options.Win32Resource + "\" ");
617 foreach (string s in options.EmbeddedResources) {
618 sb.Append("/res:\"");
623 foreach (string s in options.LinkedResources) {
624 sb.Append("/linkres:\"");
629 if (options.TreatWarningsAsErrors) {
630 sb.Append("/warnaserror+ ");
633 if (options.CompilerOptions != null) {
634 sb.Append(options.CompilerOptions + " ");
637 return sb.ToString();
640 protected override void OutputAttributeArgument(CodeAttributeArgument arg) {
641 if (arg.Name != null && arg.Name.Length > 0) {
642 OutputIdentifier(arg.Name);
645 ((ICodeGenerator)this).GenerateCodeFromExpression(arg.Value, ((IndentedTextWriter)Output).InnerWriter, Options);
648 private void OutputAttributes(CodeAttributeDeclarationCollection attributes, bool inLine) {
649 OutputAttributes(attributes, inLine, null, false);
652 private void OutputAttributes(CodeAttributeDeclarationCollection attributes, bool inLine, string prefix, bool closingLine) {
653 if (attributes.Count == 0) return;
654 IEnumerator en = attributes.GetEnumerator();
655 bool firstAttr = true;
656 GenerateAttributeDeclarationsStart(attributes);
657 while (en.MoveNext()) {
665 ContinueOnNewLine("");
670 if (prefix != null && prefix.Length > 0) {
671 Output.Write(prefix);
674 CodeAttributeDeclaration current = (CodeAttributeDeclaration)en.Current;
676 if( current.AttributeType != null) {
677 Output.Write(GetTypeOutput(current.AttributeType));
681 bool firstArg = true;
682 foreach (CodeAttributeArgument arg in current.Arguments) {
690 OutputAttributeArgument(arg);
696 GenerateAttributeDeclarationsEnd(attributes);
703 ContinueOnNewLine("");
708 protected override void OutputDirection(FieldDirection dir) {
710 case FieldDirection.In:
711 Output.Write("ByVal ");
713 case FieldDirection.Out:
714 case FieldDirection.Ref:
715 Output.Write("ByRef ");
720 protected override void GenerateDefaultValueExpression(CodeDefaultValueExpression e) {
721 Output.Write("CType(Nothing, " + GetTypeOutput(e.Type) + ")");
724 protected override void GenerateDirectionExpression(CodeDirectionExpression e) {
725 // Visual Basic does not need to adorn the calling point with a direction, so just output the expression.
726 GenerateExpression(e.Expression);
730 protected override void OutputFieldScopeModifier(MemberAttributes attributes) {
731 switch (attributes & MemberAttributes.ScopeMask) {
732 case MemberAttributes.Final:
735 case MemberAttributes.Static:
736 // ignore Static for fields in a Module since all fields in a module are already
737 // static and it is a syntax error to explicitly mark them as static
739 if (!IsCurrentModule) {
740 Output.Write("Shared ");
743 case MemberAttributes.Const:
744 Output.Write("Const ");
754 /// Generates code for the specified CodeDom based member
755 /// access modifier representation.
758 protected override void OutputMemberAccessModifier(MemberAttributes attributes) {
759 switch (attributes & MemberAttributes.AccessMask) {
760 case MemberAttributes.Assembly:
761 Output.Write("Friend ");
763 case MemberAttributes.FamilyAndAssembly:
764 Output.Write("Friend ");
766 case MemberAttributes.Family:
767 Output.Write("Protected ");
769 case MemberAttributes.FamilyOrAssembly:
770 Output.Write("Protected Friend ");
772 case MemberAttributes.Private:
773 Output.Write("Private ");
775 case MemberAttributes.Public:
776 Output.Write("Public ");
781 private void OutputVTableModifier(MemberAttributes attributes) {
782 switch (attributes & MemberAttributes.VTableMask) {
783 case MemberAttributes.New:
784 Output.Write("Shadows ");
791 /// Generates code for the specified CodeDom based member scope modifier
795 protected override void OutputMemberScopeModifier(MemberAttributes attributes) {
797 switch (attributes & MemberAttributes.ScopeMask) {
798 case MemberAttributes.Abstract:
799 Output.Write("MustOverride ");
801 case MemberAttributes.Final:
804 case MemberAttributes.Static:
805 // ignore Static for members in a Module since all members in a module are already
806 // static and it is a syntax error to explicitly mark them as static
808 if (!IsCurrentModule) {
809 Output.Write("Shared ");
812 case MemberAttributes.Override:
813 Output.Write("Overrides ");
815 case MemberAttributes.Private:
816 Output.Write("Private ");
819 switch (attributes & MemberAttributes.AccessMask) {
820 case MemberAttributes.Family:
821 case MemberAttributes.Public:
822 case MemberAttributes.Assembly:
823 Output.Write("Overridable ");
835 /// Generates code for the specified CodeDom based operator
839 protected override void OutputOperator(CodeBinaryOperatorType op) {
841 case CodeBinaryOperatorType.IdentityInequality:
844 case CodeBinaryOperatorType.IdentityEquality:
847 case CodeBinaryOperatorType.BooleanOr:
848 Output.Write("OrElse");
850 case CodeBinaryOperatorType.BooleanAnd:
851 Output.Write("AndAlso");
853 case CodeBinaryOperatorType.ValueEquality:
856 case CodeBinaryOperatorType.Modulus:
859 case CodeBinaryOperatorType.BitwiseOr:
862 case CodeBinaryOperatorType.BitwiseAnd:
866 base.OutputOperator(op);
871 private void GenerateNotIsNullExpression(CodeExpression e) {
872 Output.Write("(Not (");
873 GenerateExpression(e);
874 Output.Write(") Is ");
875 Output.Write(NullToken);
879 protected override void GenerateBinaryOperatorExpression(CodeBinaryOperatorExpression e) {
880 if (e.Operator != CodeBinaryOperatorType.IdentityInequality) {
881 base.GenerateBinaryOperatorExpression(e);
885 // "o <> nothing" should be "not o is nothing"
886 if (e.Right is CodePrimitiveExpression && ((CodePrimitiveExpression)e.Right).Value == null){
887 GenerateNotIsNullExpression(e.Left);
890 if (e.Left is CodePrimitiveExpression && ((CodePrimitiveExpression)e.Left).Value == null){
891 GenerateNotIsNullExpression(e.Right);
895 base.GenerateBinaryOperatorExpression(e);
899 /// <para>[To be supplied.]</para>
901 protected override string GetResponseFileCmdArgs(CompilerParameters options, string cmdArgs) {
903 // Always specify the /noconfig flag (outside of the response file)
904 return "/noconfig " + base.GetResponseFileCmdArgs(options, cmdArgs);
907 protected override void OutputIdentifier(string ident) {
908 Output.Write(CreateEscapedIdentifier(ident));
913 /// Generates code for the specified CodeDom based return type
917 protected override void OutputType(CodeTypeReference typeRef) {
918 Output.Write(GetTypeOutputWithoutArrayPostFix(typeRef));
921 private void OutputTypeAttributes(CodeTypeDeclaration e) {
922 if((e.Attributes & MemberAttributes.New) != 0) {
923 Output.Write("Shadows ");
926 TypeAttributes attributes = e.TypeAttributes;
929 Output.Write("Partial ");
932 switch(attributes & TypeAttributes.VisibilityMask) {
933 case TypeAttributes.Public:
934 case TypeAttributes.NestedPublic:
935 Output.Write("Public ");
937 case TypeAttributes.NestedPrivate:
938 Output.Write("Private ");
941 case TypeAttributes.NestedFamily:
942 Output.Write("Protected ");
944 case TypeAttributes.NotPublic:
945 case TypeAttributes.NestedAssembly:
946 case TypeAttributes.NestedFamANDAssem:
947 Output.Write("Friend ");
949 case TypeAttributes.NestedFamORAssem:
950 Output.Write("Protected Friend ");
955 Output.Write("Structure ");
958 Output.Write("Enum ");
962 switch (attributes & TypeAttributes.ClassSemanticsMask) {
963 case TypeAttributes.Class:
964 // if this "class" should generate as a module, then don't check
965 // inheritance flags since modules can't inherit
966 if (IsCurrentModule) {
967 Output.Write("Module ");
970 if ((attributes & TypeAttributes.Sealed) == TypeAttributes.Sealed) {
971 Output.Write("NotInheritable ");
973 if ((attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract) {
974 Output.Write("MustInherit ");
976 Output.Write("Class ");
979 case TypeAttributes.Interface:
980 Output.Write("Interface ");
989 /// Generates code for the specified CodeDom based type name pair
993 protected override void OutputTypeNamePair(CodeTypeReference typeRef, string name) {
994 if (string.IsNullOrEmpty(name))
995 name = "__exception";
997 OutputIdentifier(name);
998 OutputArrayPostfix(typeRef);
999 Output.Write(" As ");
1000 OutputType(typeRef);
1003 private string GetArrayPostfix(CodeTypeReference typeRef) {
1005 if (typeRef.ArrayElementType != null) {
1007 s = GetArrayPostfix(typeRef.ArrayElementType);
1010 if (typeRef.ArrayRank > 0) {
1011 char [] results = new char [typeRef.ArrayRank + 1];
1013 results[typeRef.ArrayRank] = ')';
1014 for (int i = 1; i < typeRef.ArrayRank; i++) {
1017 s = new string(results) + s;
1024 private void OutputArrayPostfix(CodeTypeReference typeRef) {
1025 if (typeRef.ArrayRank > 0) {
1026 Output.Write(GetArrayPostfix(typeRef));
1032 /// Generates code for the specified CodeDom based for loop statement
1036 protected override void GenerateIterationStatement(CodeIterationStatement e) {
1037 GenerateStatement(e.InitStatement);
1038 Output.Write("Do While ");
1039 GenerateExpression(e.TestExpression);
1040 Output.WriteLine("");
1042 GenerateVBStatements(e.Statements);
1043 GenerateStatement(e.IncrementStatement);
1045 Output.WriteLine("Loop");
1050 /// Generates code for the specified CodeDom based primitive expression
1054 protected override void GeneratePrimitiveExpression(CodePrimitiveExpression e) {
1055 if (e.Value is char) {
1056 Output.Write("Global.Microsoft.VisualBasic.ChrW(" + ((IConvertible)e.Value).ToInt32(CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture) + ")");
1058 else if (e.Value is SByte) {
1059 Output.Write("CSByte(");
1060 Output.Write(((SByte)e.Value).ToString(CultureInfo.InvariantCulture));
1063 else if (e.Value is UInt16) {
1064 Output.Write(((UInt16)e.Value).ToString(CultureInfo.InvariantCulture));
1067 else if (e.Value is UInt32) {
1068 Output.Write(((UInt32)e.Value).ToString(CultureInfo.InvariantCulture));
1071 else if (e.Value is UInt64) {
1072 Output.Write(((UInt64)e.Value).ToString(CultureInfo.InvariantCulture));
1076 base.GeneratePrimitiveExpression(e);
1082 /// Generates code for the specified CodeDom based throw exception statement
1086 protected override void GenerateThrowExceptionStatement(CodeThrowExceptionStatement e) {
1087 Output.Write("Throw");
1088 if (e.ToThrow != null) {
1090 GenerateExpression(e.ToThrow);
1092 Output.WriteLine("");
1098 /// Generates code for the specified CodeDom based array creation expression
1102 protected override void GenerateArrayCreateExpression(CodeArrayCreateExpression e) {
1103 Output.Write("New ");
1105 CodeExpressionCollection init = e.Initializers;
1106 if (init.Count > 0) {
1107 String typeName = GetTypeOutput(e.CreateType);
1108 Output.Write(typeName);
1112 if( typeName.IndexOf('(') == -1) {
1118 OutputExpressionList(init);
1123 String typeName = GetTypeOutput(e.CreateType);
1125 int index = typeName.IndexOf('(');
1129 Output.Write(typeName);
1133 Output.Write(typeName.Substring(0, index+1));
1136 // The tricky thing is we need to declare the size - 1
1137 if (e.SizeExpression != null) {
1139 GenerateExpression(e.SizeExpression);
1140 Output.Write(") - 1");
1143 Output.Write(e.Size - 1);
1150 Output.Write(typeName.Substring(index+1));
1153 Output.Write(" {}");
1159 /// Generates code for the specified CodeDom based base reference expression
1163 protected override void GenerateBaseReferenceExpression(CodeBaseReferenceExpression e) {
1164 Output.Write("MyBase");
1169 /// Generates code for the specified CodeDom based cast expression representation.
1172 protected override void GenerateCastExpression(CodeCastExpression e) {
1173 Output.Write("CType(");
1174 GenerateExpression(e.Expression);
1176 OutputType(e.TargetType);
1177 OutputArrayPostfix(e.TargetType);
1183 /// Generates code for the specified CodeDom based delegate creation expression
1187 protected override void GenerateDelegateCreateExpression(CodeDelegateCreateExpression e) {
1188 Output.Write("AddressOf ");
1189 GenerateExpression(e.TargetObject);
1191 OutputIdentifier(e.MethodName);
1196 /// Generates code for the specified CodeDom based field reference expression
1200 protected override void GenerateFieldReferenceExpression(CodeFieldReferenceExpression e) {
1202 if (e.TargetObject != null) {
1203 GenerateExpression(e.TargetObject);
1207 OutputIdentifier(e.FieldName);
1210 protected override void GenerateSingleFloatValue(Single s) {
1211 if( float.IsNaN(s)) {
1212 Output.Write("Single.NaN");
1214 else if( float.IsNegativeInfinity(s)) {
1215 Output.Write("Single.NegativeInfinity");
1217 else if( float.IsPositiveInfinity(s)) {
1218 Output.Write("Single.PositiveInfinity");
1221 Output.Write(s.ToString(CultureInfo.InvariantCulture));
1226 protected override void GenerateDoubleValue(double d) {
1227 if( double.IsNaN(d)) {
1228 Output.Write("Double.NaN");
1230 else if( double.IsNegativeInfinity(d)) {
1231 Output.Write("Double.NegativeInfinity");
1233 else if( double.IsPositiveInfinity(d)) {
1234 Output.Write("Double.PositiveInfinity");
1237 Output.Write(d.ToString("R", CultureInfo.InvariantCulture));
1238 // 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)
1243 protected override void GenerateDecimalValue(Decimal d) {
1244 Output.Write(d.ToString(CultureInfo.InvariantCulture));
1248 protected override void GenerateArgumentReferenceExpression(CodeArgumentReferenceExpression e) {
1249 OutputIdentifier(e.ParameterName);
1252 protected override void GenerateVariableReferenceExpression(CodeVariableReferenceExpression e) {
1253 OutputIdentifier(e.VariableName);
1258 /// Generates code for the specified CodeDom based indexer expression
1262 protected override void GenerateIndexerExpression(CodeIndexerExpression e) {
1263 GenerateExpression(e.TargetObject);
1264 // If this IndexerExpression is referencing to base, we need to emit
1265 // .Item after MyBase. Otherwise the code won't compile.
1266 if( e.TargetObject is CodeBaseReferenceExpression) {
1267 Output.Write(".Item");
1272 foreach(CodeExpression exp in e.Indices) {
1279 GenerateExpression(exp);
1285 protected override void GenerateArrayIndexerExpression(CodeArrayIndexerExpression e) {
1286 GenerateExpression(e.TargetObject);
1289 foreach(CodeExpression exp in e.Indices) {
1296 GenerateExpression(exp);
1304 /// Generates code for the specified CodeDom based code snippet expression
1308 protected override void GenerateSnippetExpression(CodeSnippetExpression e) {
1309 Output.Write(e.Value);
1313 /// Generates code for the specified CodeDom based method invoke
1317 protected override void GenerateMethodInvokeExpression(CodeMethodInvokeExpression e) {
1318 GenerateMethodReferenceExpression(e.Method);
1319 CodeExpressionCollection parameters = e.Parameters;
1320 if (parameters.Count > 0) {
1322 OutputExpressionList(e.Parameters);
1327 protected override void GenerateMethodReferenceExpression(CodeMethodReferenceExpression e) {
1328 if (e.TargetObject != null) {
1329 GenerateExpression(e.TargetObject);
1331 Output.Write(e.MethodName);
1334 OutputIdentifier(e.MethodName);
1337 if( e.TypeArguments.Count > 0) {
1338 Output.Write(GetTypeArgumentsOutput(e.TypeArguments));
1342 protected override void GenerateEventReferenceExpression(CodeEventReferenceExpression e) {
1343 if (e.TargetObject != null) {
1344 bool localReference = (e.TargetObject is CodeThisReferenceExpression);
1345 GenerateExpression(e.TargetObject);
1347 if (localReference) {
1348 Output.Write(e.EventName + "Event");
1351 Output.Write(e.EventName);
1355 OutputIdentifier(e.EventName + "Event");
1359 private void GenerateFormalEventReferenceExpression(CodeEventReferenceExpression e) {
1360 if (e.TargetObject != null) {
1361 // Visual Basic Compiler does not like the me reference like this.
1362 if (!(e.TargetObject is CodeThisReferenceExpression)) {
1363 GenerateExpression(e.TargetObject);
1367 OutputIdentifier(e.EventName);
1373 /// Generates code for the specified CodeDom based delegate invoke
1377 protected override void GenerateDelegateInvokeExpression(CodeDelegateInvokeExpression e) {
1378 if (e.TargetObject != null) {
1379 if (e.TargetObject is CodeEventReferenceExpression) {
1380 Output.Write("RaiseEvent ");
1381 GenerateFormalEventReferenceExpression((CodeEventReferenceExpression)e.TargetObject);
1384 GenerateExpression(e.TargetObject);
1388 CodeExpressionCollection parameters = e.Parameters;
1389 if (parameters.Count > 0) {
1391 OutputExpressionList(e.Parameters);
1398 /// Generates code for the specified CodeDom based object creation
1402 protected override void GenerateObjectCreateExpression(CodeObjectCreateExpression e) {
1403 Output.Write("New ");
1404 OutputType(e.CreateType);
1405 // always write out the () to disambiguate cases like "New System.Random().Next(x,y)"
1407 OutputExpressionList(e.Parameters);
1413 /// Generates code for the specified CodeDom
1414 /// based parameter declaration expression representation.
1417 protected override void GenerateParameterDeclarationExpression(CodeParameterDeclarationExpression e) {
1418 if (e.CustomAttributes.Count > 0) {
1419 OutputAttributes(e.CustomAttributes, true);
1421 OutputDirection(e.Direction);
1422 OutputTypeNamePair(e.Type, e.Name);
1425 protected override void GeneratePropertySetValueReferenceExpression(CodePropertySetValueReferenceExpression e) {
1426 Output.Write("value");
1431 /// Generates code for the specified CodeDom based this reference expression
1435 protected override void GenerateThisReferenceExpression(CodeThisReferenceExpression e) {
1441 /// Generates code for the specified CodeDom based method invoke statement
1445 protected override void GenerateExpressionStatement(CodeExpressionStatement e) {
1446 GenerateExpression(e.Expression);
1447 Output.WriteLine("");
1452 /// Tells whether or not the given comment is a DocComment
1455 private bool IsDocComment(CodeCommentStatement comment) {
1457 return ((comment != null) && (comment.Comment != null) && comment.Comment.DocComment);
1460 /// <include file='doc\VBCodeProvider.uex' path='docs/doc[@for="VBCodeGenerator.GenerateCommentStatements"]/*' />
1462 /// <para>Overridden in order to output XML DocComments in the correct order for VB</para>
1464 protected override void GenerateCommentStatements(CodeCommentStatementCollection e) {
1466 // since the compiler emits a warning if XML DocComment blocks appear before
1467 // normal comments, we need to output non-DocComments first, followed by
1470 foreach (CodeCommentStatement comment in e) {
1471 if (!IsDocComment(comment)) {
1472 GenerateCommentStatement(comment);
1476 foreach (CodeCommentStatement comment in e) {
1477 if (IsDocComment(comment)) {
1478 GenerateCommentStatement(comment);
1483 protected override void GenerateComment(CodeComment e) {
1484 String commentLineStart = e.DocComment? "'''": "'";
1485 Output.Write(commentLineStart);
1486 string value = e.Text;
1487 for (int i=0; i<value.Length; i++) {
1488 Output.Write(value[i]);
1490 if( value[i] == '\r') {
1491 if (i < value.Length - 1 && value[i+1] == '\n') { // if next char is '\n', skip it
1495 ((IndentedTextWriter) Output).InternalOutputTabs();
1496 Output.Write(commentLineStart);
1498 else if( value[i] == '\n') {
1499 ((IndentedTextWriter) Output).InternalOutputTabs();
1500 Output.Write(commentLineStart);
1502 else if( value[i] == '\u2028' || value[i] == '\u2029' || value[i] == '\u0085') {
1503 Output.Write(commentLineStart);
1511 /// Generates code for the specified CodeDom based method return statement
1515 protected override void GenerateMethodReturnStatement(CodeMethodReturnStatement e) {
1516 if (e.Expression != null) {
1517 Output.Write("Return ");
1518 GenerateExpression(e.Expression);
1519 Output.WriteLine("");
1522 Output.WriteLine("Return");
1528 /// Generates code for the specified CodeDom based if statement representation.
1531 protected override void GenerateConditionStatement(CodeConditionStatement e) {
1532 Output.Write("If ");
1533 GenerateExpression(e.Condition);
1534 Output.WriteLine(" Then");
1536 GenerateVBStatements(e.TrueStatements);
1539 CodeStatementCollection falseStatemetns = e.FalseStatements;
1540 if (falseStatemetns.Count > 0) {
1541 Output.Write("Else");
1542 Output.WriteLine("");
1544 GenerateVBStatements(e.FalseStatements);
1547 Output.WriteLine("End If");
1552 /// Generates code for the specified CodeDom based try catch finally statement
1556 protected override void GenerateTryCatchFinallyStatement(CodeTryCatchFinallyStatement e) {
1557 Output.WriteLine("Try ");
1559 GenerateVBStatements(e.TryStatements);
1561 CodeCatchClauseCollection catches = e.CatchClauses;
1562 if (catches.Count > 0) {
1563 IEnumerator en = catches.GetEnumerator();
1564 while (en.MoveNext()) {
1565 CodeCatchClause current = (CodeCatchClause)en.Current;
1566 Output.Write("Catch ");
1567 OutputTypeNamePair(current.CatchExceptionType, current.LocalName);
1568 Output.WriteLine("");
1570 GenerateVBStatements(current.Statements);
1575 CodeStatementCollection finallyStatements = e.FinallyStatements;
1576 if (finallyStatements.Count > 0) {
1577 Output.WriteLine("Finally");
1579 GenerateVBStatements(finallyStatements);
1582 Output.WriteLine("End Try");
1587 /// Generates code for the specified CodeDom based assignment statement
1591 protected override void GenerateAssignStatement(CodeAssignStatement e) {
1592 GenerateExpression(e.Left);
1593 Output.Write(" = ");
1594 GenerateExpression(e.Right);
1595 Output.WriteLine("");
1598 protected override void GenerateAttachEventStatement(CodeAttachEventStatement e) {
1599 Output.Write("AddHandler ");
1600 GenerateFormalEventReferenceExpression(e.Event);
1602 GenerateExpression(e.Listener);
1603 Output.WriteLine("");
1606 protected override void GenerateRemoveEventStatement(CodeRemoveEventStatement e) {
1607 Output.Write("RemoveHandler ");
1608 GenerateFormalEventReferenceExpression(e.Event);
1610 GenerateExpression(e.Listener);
1611 Output.WriteLine("");
1614 protected override void GenerateSnippetStatement(CodeSnippetStatement e) {
1615 Output.WriteLine(e.Value);
1618 protected override void GenerateGotoStatement(CodeGotoStatement e) {
1619 Output.Write("goto ");
1620 Output.WriteLine(e.Label);
1623 protected override void GenerateLabeledStatement(CodeLabeledStatement e) {
1625 Output.Write(e.Label);
1626 Output.WriteLine(":");
1628 if (e.Statement != null) {
1629 GenerateStatement(e.Statement);
1635 /// Generates code for the specified CodeDom variable declaration statement
1639 protected override void GenerateVariableDeclarationStatement(CodeVariableDeclarationStatement e) {
1642 Output.Write("Dim ");
1644 CodeTypeReference typeRef = e.Type;
1645 if (typeRef.ArrayRank == 1 && e.InitExpression != null) {
1646 CodeArrayCreateExpression eAsArrayCreate = e.InitExpression as CodeArrayCreateExpression;
1647 if (eAsArrayCreate != null && eAsArrayCreate.Initializers.Count == 0) {
1649 OutputIdentifier(e.Name);
1652 if (eAsArrayCreate.SizeExpression != null) {
1654 GenerateExpression(eAsArrayCreate.SizeExpression);
1655 Output.Write(") - 1");
1658 Output.Write(eAsArrayCreate.Size - 1);
1663 if (typeRef.ArrayElementType != null)
1664 OutputArrayPostfix(typeRef.ArrayElementType);
1666 Output.Write(" As ");
1667 OutputType(typeRef);
1670 OutputTypeNamePair(e.Type, e.Name);
1673 OutputTypeNamePair(e.Type, e.Name);
1675 if (doInit && e.InitExpression != null) {
1676 Output.Write(" = ");
1677 GenerateExpression(e.InitExpression);
1680 Output.WriteLine("");
1684 /// Generates code for the specified CodeDom based line pragma start
1688 protected override void GenerateLinePragmaStart(CodeLinePragma e) {
1689 Output.WriteLine("");
1690 Output.Write("#ExternalSource(\"");
1691 Output.Write(e.FileName);
1692 Output.Write("\",");
1693 Output.Write(e.LineNumber);
1694 Output.WriteLine(")");
1698 /// Generates code for the specified CodeDom based line pragma end
1702 protected override void GenerateLinePragmaEnd(CodeLinePragma e) {
1703 Output.WriteLine("");
1704 Output.WriteLine("#End ExternalSource");
1708 protected override void GenerateEvent(CodeMemberEvent e, CodeTypeDeclaration c) {
1709 if (IsCurrentDelegate || IsCurrentEnum) return;
1711 if (e.CustomAttributes.Count > 0) {
1712 OutputAttributes(e.CustomAttributes, false);
1715 string eventName = e.Name;
1716 if (e.PrivateImplementationType != null)
1718 string impl = GetBaseTypeOutput(e.PrivateImplementationType);
1719 impl = impl.Replace('.', '_');
1720 e.Name = impl + "_" + e.Name;
1723 OutputMemberAccessModifier(e.Attributes);
1724 Output.Write("Event ");
1725 OutputTypeNamePair(e.Type, e.Name);
1727 if (e.ImplementationTypes.Count > 0) {
1728 Output.Write(" Implements ");
1730 foreach (CodeTypeReference type in e.ImplementationTypes) {
1735 Output.Write(" , ");
1739 OutputIdentifier(eventName);
1742 else if (e.PrivateImplementationType != null) {
1743 Output.Write(" Implements ");
1744 OutputType(e.PrivateImplementationType);
1746 OutputIdentifier(eventName);
1749 Output.WriteLine("");
1754 /// Generates code for the specified CodeDom based member
1755 /// field representation.
1758 protected override void GenerateField(CodeMemberField e) {
1759 if (IsCurrentDelegate || IsCurrentInterface) return;
1761 if (IsCurrentEnum) {
1762 if (e.CustomAttributes.Count > 0) {
1763 OutputAttributes(e.CustomAttributes, false);
1766 OutputIdentifier(e.Name);
1767 if (e.InitExpression != null) {
1768 Output.Write(" = ");
1769 GenerateExpression(e.InitExpression);
1771 Output.WriteLine("");
1774 if (e.CustomAttributes.Count > 0) {
1775 OutputAttributes(e.CustomAttributes, false);
1778 OutputMemberAccessModifier(e.Attributes);
1779 OutputVTableModifier(e.Attributes);
1780 OutputFieldScopeModifier(e.Attributes);
1782 if (GetUserData(e, "WithEvents", false)) {
1783 Output.Write("WithEvents ");
1786 OutputTypeNamePair(e.Type, e.Name);
1787 if (e.InitExpression != null) {
1788 Output.Write(" = ");
1789 GenerateExpression(e.InitExpression);
1791 Output.WriteLine("");
1795 private bool MethodIsOverloaded(CodeMemberMethod e, CodeTypeDeclaration c) {
1796 if ((e.Attributes & MemberAttributes.Overloaded) != 0) {
1799 IEnumerator en = c.Members.GetEnumerator();
1800 while (en.MoveNext()) {
1801 if (!(en.Current is CodeMemberMethod))
1803 CodeMemberMethod meth = (CodeMemberMethod) en.Current;
1805 if (!(en.Current is CodeTypeConstructor)
1806 && !(en.Current is CodeConstructor)
1808 && meth.Name.Equals(e.Name, StringComparison.OrdinalIgnoreCase)
1809 && meth.PrivateImplementationType == null)
1820 /// Generates code for
1821 /// the specified CodeDom based snippet member representation.
1824 protected override void GenerateSnippetMember(CodeSnippetTypeMember e) {
1825 Output.Write(e.Text);
1828 protected override void GenerateMethod(CodeMemberMethod e, CodeTypeDeclaration c) {
1829 if (!(IsCurrentClass || IsCurrentStruct || IsCurrentInterface)) return;
1831 if (e.CustomAttributes.Count > 0) {
1832 OutputAttributes(e.CustomAttributes, false);
1835 // need to change the implements name before doing overloads resolution
1837 string methodName = e.Name;
1838 if (e.PrivateImplementationType != null) {
1839 string impl = GetBaseTypeOutput(e.PrivateImplementationType);
1840 impl = impl.Replace('.', '_');
1841 e.Name = impl + "_" + e.Name;
1844 if (!IsCurrentInterface) {
1845 if (e.PrivateImplementationType == null) {
1846 OutputMemberAccessModifier(e.Attributes);
1847 if (MethodIsOverloaded(e, c))
1848 Output.Write("Overloads ");
1850 OutputVTableModifier(e.Attributes);
1851 OutputMemberScopeModifier(e.Attributes);
1854 // interface may still need "Shadows"
1855 OutputVTableModifier(e.Attributes);
1858 if (e.ReturnType.BaseType.Length == 0 || string.Compare(e.ReturnType.BaseType, typeof(void).FullName, StringComparison.OrdinalIgnoreCase) == 0) {
1863 Output.Write("Sub ");
1866 Output.Write("Function ");
1870 OutputIdentifier(e.Name);
1871 OutputTypeParameters(e.TypeParameters);
1874 OutputParameters(e.Parameters);
1878 Output.Write(" As ");
1879 if (e.ReturnTypeCustomAttributes.Count > 0) {
1880 OutputAttributes(e.ReturnTypeCustomAttributes, true);
1883 OutputType(e.ReturnType);
1884 OutputArrayPostfix(e.ReturnType);
1886 if (e.ImplementationTypes.Count > 0) {
1887 Output.Write(" Implements ");
1889 foreach (CodeTypeReference type in e.ImplementationTypes) {
1894 Output.Write(" , ");
1898 OutputIdentifier(methodName);
1901 else if (e.PrivateImplementationType != null) {
1902 Output.Write(" Implements ");
1903 OutputType(e.PrivateImplementationType);
1905 OutputIdentifier(methodName);
1907 Output.WriteLine("");
1908 if (!IsCurrentInterface
1909 && (e.Attributes & MemberAttributes.ScopeMask) != MemberAttributes.Abstract) {
1912 GenerateVBStatements(e.Statements);
1916 Output.WriteLine("End Sub");
1919 Output.WriteLine("End Function");
1922 // reset the name that possibly got changed with the implements clause
1923 e.Name = methodName;
1926 protected override void GenerateEntryPointMethod(CodeEntryPointMethod e, CodeTypeDeclaration c) {
1927 if (e.CustomAttributes.Count > 0) {
1928 OutputAttributes(e.CustomAttributes, false);
1931 Output.WriteLine("Public Shared Sub Main()");
1934 GenerateVBStatements(e.Statements);
1937 Output.WriteLine("End Sub");
1940 private bool PropertyIsOverloaded(CodeMemberProperty e, CodeTypeDeclaration c) {
1941 if ((e.Attributes & MemberAttributes.Overloaded) != 0) {
1944 IEnumerator en = c.Members.GetEnumerator();
1945 while (en.MoveNext()) {
1946 if (!(en.Current is CodeMemberProperty))
1948 CodeMemberProperty prop = (CodeMemberProperty) en.Current;
1950 && prop.Name.Equals(e.Name, StringComparison.OrdinalIgnoreCase)
1951 && prop.PrivateImplementationType == null)
1962 /// Generates code for the specified CodeDom based member property
1966 protected override void GenerateProperty(CodeMemberProperty e, CodeTypeDeclaration c) {
1967 if (!(IsCurrentClass || IsCurrentStruct || IsCurrentInterface)) return;
1969 if (e.CustomAttributes.Count > 0) {
1970 OutputAttributes(e.CustomAttributes, false);
1973 string propName = e.Name;
1974 if (e.PrivateImplementationType != null)
1976 string impl = GetBaseTypeOutput(e.PrivateImplementationType);
1977 impl = impl.Replace('.', '_');
1978 e.Name = impl + "_" + e.Name;
1980 if (!IsCurrentInterface) {
1981 if (e.PrivateImplementationType == null) {
1982 OutputMemberAccessModifier(e.Attributes);
1983 if (PropertyIsOverloaded(e,c)) {
1984 Output.Write("Overloads ");
1987 OutputVTableModifier(e.Attributes);
1988 OutputMemberScopeModifier(e.Attributes);
1991 // interface may still need "Shadows"
1992 OutputVTableModifier(e.Attributes);
1994 if (e.Parameters.Count > 0 && String.Compare(e.Name, "Item", StringComparison.OrdinalIgnoreCase) == 0) {
1995 Output.Write("Default ");
1999 Output.Write("ReadOnly ");
2002 else if (e.HasSet) {
2003 Output.Write("WriteOnly ");
2005 Output.Write("Property ");
2006 OutputIdentifier(e.Name);
2008 if (e.Parameters.Count > 0) {
2009 OutputParameters(e.Parameters);
2012 Output.Write(" As ");
2014 OutputArrayPostfix(e.Type);
2016 if (e.ImplementationTypes.Count > 0) {
2017 Output.Write(" Implements ");
2019 foreach (CodeTypeReference type in e.ImplementationTypes) {
2024 Output.Write(" , ");
2028 OutputIdentifier(propName);
2031 else if (e.PrivateImplementationType != null) {
2032 Output.Write(" Implements ");
2033 OutputType(e.PrivateImplementationType);
2035 OutputIdentifier(propName);
2038 Output.WriteLine("");
2040 if (!c.IsInterface && (e.Attributes & MemberAttributes.ScopeMask) != MemberAttributes.Abstract) {
2045 Output.WriteLine("Get");
2046 if (!IsCurrentInterface) {
2049 GenerateVBStatements(e.GetStatements);
2053 Output.WriteLine("End Get");
2057 Output.WriteLine("Set");
2058 if (!IsCurrentInterface) {
2060 GenerateVBStatements(e.SetStatements);
2062 Output.WriteLine("End Set");
2066 Output.WriteLine("End Property");
2074 /// Generates code for the specified CodeDom based property reference
2075 /// expression representation.
2078 protected override void GeneratePropertyReferenceExpression(CodePropertyReferenceExpression e) {
2080 if (e.TargetObject != null) {
2081 GenerateExpression(e.TargetObject);
2083 Output.Write(e.PropertyName);
2086 OutputIdentifier(e.PropertyName);
2092 /// Generates code for the specified CodeDom based constructor
2096 protected override void GenerateConstructor(CodeConstructor e, CodeTypeDeclaration c) {
2097 if (!(IsCurrentClass || IsCurrentStruct)) return;
2099 if (e.CustomAttributes.Count > 0) {
2100 OutputAttributes(e.CustomAttributes, false);
2103 OutputMemberAccessModifier(e.Attributes);
2104 Output.Write("Sub New(");
2105 OutputParameters(e.Parameters);
2106 Output.WriteLine(")");
2109 CodeExpressionCollection baseArgs = e.BaseConstructorArgs;
2110 CodeExpressionCollection thisArgs = e.ChainedConstructorArgs;
2112 if (thisArgs.Count > 0) {
2113 Output.Write("Me.New(");
2114 OutputExpressionList(thisArgs);
2116 Output.WriteLine("");
2118 else if (baseArgs.Count > 0) {
2119 Output.Write("MyBase.New(");
2120 OutputExpressionList(baseArgs);
2122 Output.WriteLine("");
2124 else if(IsCurrentClass) {
2125 // struct doesn't have MyBase
2126 Output.WriteLine("MyBase.New");
2129 GenerateVBStatements(e.Statements);
2131 Output.WriteLine("End Sub");
2135 /// Generates code for the specified CodeDom based class constructor
2139 protected override void GenerateTypeConstructor(CodeTypeConstructor e) {
2140 if (!(IsCurrentClass || IsCurrentStruct)) return;
2142 if (e.CustomAttributes.Count > 0) {
2143 OutputAttributes(e.CustomAttributes, false);
2146 Output.WriteLine("Shared Sub New()");
2148 GenerateVBStatements(e.Statements);
2150 Output.WriteLine("End Sub");
2153 protected override void GenerateTypeOfExpression(CodeTypeOfExpression e) {
2154 Output.Write("GetType(");
2155 Output.Write(GetTypeOutput(e.Type));
2161 /// Generates code for the CodeDom based class start representation.
2164 protected override void GenerateTypeStart(CodeTypeDeclaration e) {
2165 if (IsCurrentDelegate) {
2166 if (e.CustomAttributes.Count > 0) {
2167 OutputAttributes(e.CustomAttributes, false);
2170 switch (e.TypeAttributes & TypeAttributes.VisibilityMask) {
2171 case TypeAttributes.Public:
2172 Output.Write("Public ");
2174 case TypeAttributes.NotPublic:
2179 CodeTypeDelegate del = (CodeTypeDelegate)e;
2180 if (del.ReturnType.BaseType.Length > 0 && string.Compare(del.ReturnType.BaseType, "System.Void", StringComparison.OrdinalIgnoreCase) != 0)
2181 Output.Write("Delegate Function ");
2183 Output.Write("Delegate Sub ");
2184 OutputIdentifier(e.Name);
2186 OutputParameters(del.Parameters);
2188 if (del.ReturnType.BaseType.Length > 0 && string.Compare(del.ReturnType.BaseType, "System.Void", StringComparison.OrdinalIgnoreCase) != 0) {
2189 Output.Write(" As ");
2190 OutputType(del.ReturnType);
2191 OutputArrayPostfix(del.ReturnType);
2193 Output.WriteLine("");
2195 else if (e.IsEnum) {
2196 if (e.CustomAttributes.Count > 0) {
2197 OutputAttributes(e.CustomAttributes, false);
2199 OutputTypeAttributes(e);
2201 OutputIdentifier(e.Name);
2203 if (e.BaseTypes.Count > 0) {
2204 Output.Write(" As ");
2205 OutputType(e.BaseTypes[0]);
2208 Output.WriteLine("");
2212 if (e.CustomAttributes.Count > 0) {
2213 OutputAttributes(e.CustomAttributes, false);
2215 OutputTypeAttributes(e);
2217 OutputIdentifier(e.Name);
2218 OutputTypeParameters(e.TypeParameters);
2220 bool writtenInherits = false;
2221 bool writtenImplements = false;
2222 // For a structure we can't have an inherits clause
2224 writtenInherits = true;
2226 // For an interface we can't have an implements clause
2227 if (e.IsInterface) {
2228 writtenImplements = true;
2231 foreach (CodeTypeReference typeRef in e.BaseTypes) {
2232 // if we're generating an interface, we always want to use Inherits because interfaces can't Implement anything.
2233 if (!writtenInherits && (e.IsInterface || !typeRef.IsInterface)) {
2234 Output.WriteLine("");
2235 Output.Write("Inherits ");
2236 writtenInherits = true;
2238 else if (!writtenImplements) {
2239 Output.WriteLine("");
2240 Output.Write("Implements ");
2241 writtenImplements = true;
2246 OutputType(typeRef);
2249 Output.WriteLine("");
2253 private void OutputTypeParameters(CodeTypeParameterCollection typeParameters) {
2254 if( typeParameters.Count == 0) {
2258 Output.Write("(Of ");
2260 for(int i = 0; i < typeParameters.Count; i++) {
2267 Output.Write(typeParameters[i].Name);
2268 OutputTypeParameterConstraints(typeParameters[i]);
2274 // In VB, constraints are put right after the type paramater name.
2275 // In C#, there is a seperate "where" statement
2276 private void OutputTypeParameterConstraints(CodeTypeParameter typeParameter) {
2277 CodeTypeReferenceCollection constraints = typeParameter.Constraints;
2278 int constraintCount = constraints.Count;
2279 if( typeParameter.HasConstructorConstraint) {
2283 if( constraintCount == 0) {
2287 // generating something like: "ValType As {IComparable, Customer, New}"
2288 Output.Write(" As ");
2289 if(constraintCount > 1) {
2294 foreach (CodeTypeReference typeRef in constraints) {
2301 Output.Write(GetTypeOutput(typeRef));
2304 if( typeParameter.HasConstructorConstraint) {
2309 Output.Write("New");
2312 if(constraintCount > 1) {
2320 /// Generates code for the specified CodeDom based class end
2324 protected override void GenerateTypeEnd(CodeTypeDeclaration e) {
2325 if (!IsCurrentDelegate) {
2329 ending = "End Enum";
2331 else if (e.IsInterface) {
2332 ending = "End Interface";
2334 else if (e.IsStruct) {
2335 ending = "End Structure";
2337 if (IsCurrentModule) {
2338 ending = "End Module";
2341 ending = "End Class";
2344 Output.WriteLine(ending);
2350 /// Generates code for the CodeDom based namespace representation.
2353 protected override void GenerateNamespace(CodeNamespace e) {
2355 if (GetUserData(e, "GenerateImports", true)) {
2356 GenerateNamespaceImports(e);
2359 GenerateCommentStatements(e.Comments);
2360 GenerateNamespaceStart(e);
2362 GenerateNamespaceEnd(e);
2365 protected bool AllowLateBound(CodeCompileUnit e) {
2366 object o = e.UserData["AllowLateBound"];
2367 if (o != null && o is bool) {
2370 // We have Option Strict Off by default because it can fail on simple things like dividing
2375 protected bool RequireVariableDeclaration(CodeCompileUnit e) {
2376 object o = e.UserData["RequireVariableDeclaration"];
2377 if (o != null && o is bool) {
2383 private bool GetUserData(CodeObject e, string property, bool defaultValue) {
2384 object o = e.UserData[property];
2385 if (o != null && o is bool) {
2388 return defaultValue;
2391 protected override void GenerateCompileUnitStart(CodeCompileUnit e) {
2392 base.GenerateCompileUnitStart(e);
2394 Output.WriteLine("'------------------------------------------------------------------------------");
2395 Output.Write("' <");
2396 Output.WriteLine(SR.GetString(SR.AutoGen_Comment_Line1));
2398 Output.WriteLine(SR.GetString(SR.AutoGen_Comment_Line2));
2400 Output.Write(SR.GetString(SR.AutoGen_Comment_Line3));
2401 Output.WriteLine(System.Environment.Version.ToString());
2402 Output.WriteLine("'");
2404 Output.WriteLine(SR.GetString(SR.AutoGen_Comment_Line4));
2406 Output.WriteLine(SR.GetString(SR.AutoGen_Comment_Line5));
2407 Output.Write("' </");
2408 Output.WriteLine(SR.GetString(SR.AutoGen_Comment_Line1));
2409 Output.WriteLine("'------------------------------------------------------------------------------");
2410 Output.WriteLine("");
2412 if (AllowLateBound(e))
2413 Output.WriteLine("Option Strict Off");
2415 Output.WriteLine("Option Strict On");
2417 if (!RequireVariableDeclaration(e))
2418 Output.WriteLine("Option Explicit Off");
2420 Output.WriteLine("Option Explicit On");
2426 protected override void GenerateCompileUnit(CodeCompileUnit e) {
2428 GenerateCompileUnitStart(e);
2430 SortedList importList;
2431 // Visual Basic needs all the imports together at the top of the compile unit.
2432 // If generating multiple namespaces, gather all the imports together
2433 importList = new SortedList(StringComparer.OrdinalIgnoreCase);
2434 foreach (CodeNamespace nspace in e.Namespaces) {
2435 // mark the namespace to stop it generating its own import list
2436 nspace.UserData["GenerateImports"] = false;
2438 // Collect the unique list of imports
2439 foreach (CodeNamespaceImport import in nspace.Imports) {
2440 if (!importList.Contains(import.Namespace)) {
2441 importList.Add(import.Namespace, import.Namespace);
2445 // now output the imports
2446 foreach(string import in importList.Keys) {
2447 Output.Write("Imports ");
2448 OutputIdentifier(import);
2449 Output.WriteLine("");
2452 if (e.AssemblyCustomAttributes.Count > 0) {
2453 OutputAttributes(e.AssemblyCustomAttributes, false, "Assembly: ", true);
2456 GenerateNamespaces(e);
2457 GenerateCompileUnitEnd(e);
2460 protected override void GenerateDirectives(CodeDirectiveCollection directives) {
2461 for (int i = 0; i < directives.Count; i++) {
2462 CodeDirective directive = directives[i];
2463 if (directive is CodeChecksumPragma) {
2464 GenerateChecksumPragma((CodeChecksumPragma)directive);
2466 else if (directive is CodeRegionDirective) {
2467 GenerateCodeRegionDirective((CodeRegionDirective)directive);
2472 private void GenerateChecksumPragma(CodeChecksumPragma checksumPragma) {
2473 // the syntax is: #ExternalChecksum("FileName","GuidChecksum","ChecksumValue")
2474 Output.Write("#ExternalChecksum(\"");
2475 Output.Write(checksumPragma.FileName);
2476 Output.Write("\",\"");
2477 Output.Write(checksumPragma.ChecksumAlgorithmId.ToString("B", CultureInfo.InvariantCulture));
2478 Output.Write("\",\"");
2479 if (checksumPragma.ChecksumData != null) {
2480 foreach(Byte b in checksumPragma.ChecksumData) {
2481 Output.Write(b.ToString("X2", CultureInfo.InvariantCulture));
2484 Output.WriteLine("\")");
2487 private void GenerateCodeRegionDirective(CodeRegionDirective regionDirective) {
2488 // VB does not support regions within statement blocks
2489 if (IsGeneratingStatements()) {
2492 if (regionDirective.RegionMode == CodeRegionMode.Start) {
2493 Output.Write("#Region \"");
2494 Output.Write(regionDirective.RegionText);
2495 Output.WriteLine("\"");
2497 else if (regionDirective.RegionMode == CodeRegionMode.End) {
2498 Output.WriteLine("#End Region");
2504 /// Generates code for the specified CodeDom based namespace representation.
2507 protected override void GenerateNamespaceStart(CodeNamespace e) {
2508 if (e.Name != null && e.Name.Length > 0) {
2509 Output.Write("Namespace ");
2510 string[] names = e.Name.Split('.');
2511 Debug.Assert( names.Length > 0);
2512 OutputIdentifier(names[0]);
2513 for( int i = 1; i< names.Length; i++) {
2515 OutputIdentifier(names[i]);
2524 /// Generates code for the specified CodeDom based namespace representation.
2527 protected override void GenerateNamespaceEnd(CodeNamespace e) {
2528 if (e.Name != null && e.Name.Length > 0) {
2530 Output.WriteLine("End Namespace");
2536 /// Generates code for the specified CodeDom based namespace import
2540 protected override void GenerateNamespaceImport(CodeNamespaceImport e) {
2541 Output.Write("Imports ");
2542 OutputIdentifier(e.Namespace);
2543 Output.WriteLine("");
2548 /// Generates code for the specified CodeDom based attribute block start
2552 protected override void GenerateAttributeDeclarationsStart(CodeAttributeDeclarationCollection attributes) {
2557 /// Generates code for the specified CodeDom based attribute block end
2561 protected override void GenerateAttributeDeclarationsEnd(CodeAttributeDeclarationCollection attributes) {
2565 public static bool IsKeyword(string value) {
2566 return FixedStringLookup.Contains(keywords, value, true);
2569 protected override bool Supports(GeneratorSupport support) {
2570 return ((support & LanguageSupport) == support);
2575 /// Gets whether the specified identifier is valid.
2578 protected override bool IsValidIdentifier(string value) {
2580 // identifiers must be 1 char or longer
2582 if (value == null || value.Length == 0) {
2586 if (value.Length > 1023)
2589 // identifiers cannot be a keyword unless surrounded by []'s
2591 if (value[0] != '[' || value[value.Length - 1] != ']') {
2592 if (IsKeyword(value)) {
2596 value = value.Substring(1, value.Length - 2);
2599 // just _ as an identifier is not valid.
2600 if (value.Length == 1 && value[0] == '_')
2603 return CodeGenerator.IsValidLanguageIndependentIdentifier(value);
2606 protected override string CreateValidIdentifier(string name) {
2607 if (IsKeyword(name)) {
2613 protected override string CreateEscapedIdentifier(string name) {
2614 if (IsKeyword(name)) {
2615 return "[" + name + "]";
2620 private string GetBaseTypeOutput(CodeTypeReference typeRef) {
2621 string baseType = typeRef.BaseType;
2623 if (baseType.Length == 0) {
2626 else if (string.Compare(baseType, "System.Byte", StringComparison.OrdinalIgnoreCase) == 0) {
2629 else if (string.Compare(baseType, "System.SByte", StringComparison.OrdinalIgnoreCase) == 0) {
2632 else if (string.Compare(baseType, "System.Int16", StringComparison.OrdinalIgnoreCase) == 0) {
2635 else if (string.Compare(baseType, "System.Int32", StringComparison.OrdinalIgnoreCase) == 0) {
2638 else if (string.Compare(baseType, "System.Int64", StringComparison.OrdinalIgnoreCase) == 0) {
2641 else if (string.Compare(baseType, "System.UInt16", StringComparison.OrdinalIgnoreCase) == 0) {
2644 else if (string.Compare(baseType, "System.UInt32", StringComparison.OrdinalIgnoreCase) == 0) {
2647 else if (string.Compare(baseType, "System.UInt64", StringComparison.OrdinalIgnoreCase) == 0) {
2650 else if (string.Compare(baseType, "System.String", StringComparison.OrdinalIgnoreCase) == 0) {
2653 else if (string.Compare(baseType, "System.DateTime", StringComparison.OrdinalIgnoreCase) == 0) {
2656 else if (string.Compare(baseType, "System.Decimal", StringComparison.OrdinalIgnoreCase) == 0) {
2659 else if (string.Compare(baseType, "System.Single", StringComparison.OrdinalIgnoreCase) == 0) {
2662 else if (string.Compare(baseType, "System.Double", StringComparison.OrdinalIgnoreCase) == 0) {
2665 else if (string.Compare(baseType, "System.Boolean", StringComparison.OrdinalIgnoreCase) == 0) {
2668 else if (string.Compare(baseType, "System.Char", StringComparison.OrdinalIgnoreCase) == 0) {
2671 else if (string.Compare(baseType, "System.Object", StringComparison.OrdinalIgnoreCase) == 0) {
2675 StringBuilder sb = new StringBuilder(baseType.Length + 10);
2676 if((typeRef.Options & CodeTypeReferenceOptions.GlobalReference) != 0) {
2677 sb.Append("Global.");
2681 int currentTypeArgStart = 0;
2682 for (int i=0; i<baseType.Length; i++) {
2683 switch (baseType[i]) {
2686 sb.Append(CreateEscapedIdentifier(baseType.Substring(lastIndex, i-lastIndex)));
2693 sb.Append(CreateEscapedIdentifier(baseType.Substring(lastIndex, i-lastIndex)));
2695 int numTypeArgs = 0;
2696 while (i < baseType.Length && baseType[i] >= '0' && baseType[i] <='9') {
2697 numTypeArgs = numTypeArgs*10 + (baseType[i] - '0');
2701 GetTypeArgumentsOutput(typeRef.TypeArguments, currentTypeArgStart, numTypeArgs, sb);
2702 currentTypeArgStart += numTypeArgs;
2704 // Arity can be in the middle of a nested type name, so we might have a . or + after it.
2706 if (i < baseType.Length && (baseType[i] =='+' || baseType[i] == '.')) {
2716 if (lastIndex < baseType.Length)
2717 sb.Append(CreateEscapedIdentifier(baseType.Substring(lastIndex)));
2719 return sb.ToString();
2723 private string GetTypeOutputWithoutArrayPostFix(CodeTypeReference typeRef) {
2724 StringBuilder sb = new StringBuilder();
2726 while( typeRef.ArrayElementType != null) {
2727 typeRef = typeRef.ArrayElementType;
2730 sb.Append(GetBaseTypeOutput(typeRef));
2731 return sb.ToString();
2734 private String GetTypeArgumentsOutput(CodeTypeReferenceCollection typeArguments) {
2735 StringBuilder sb = new StringBuilder(128);
2736 GetTypeArgumentsOutput(typeArguments, 0, typeArguments.Count, sb);
2737 return sb.ToString();
2741 private void GetTypeArgumentsOutput(CodeTypeReferenceCollection typeArguments, int start, int length, StringBuilder sb) {
2744 for( int i = start; i < start+length; i++) {
2752 // it's possible that we call GetTypeArgumentsOutput with an empty typeArguments collection. This is the case
2753 // for open types, so we want to just output the brackets and commas.
2754 if (i < typeArguments.Count)
2755 sb.Append(GetTypeOutput(typeArguments[i]));
2760 protected override string GetTypeOutput(CodeTypeReference typeRef) {
2761 string s = String.Empty;
2762 s += GetTypeOutputWithoutArrayPostFix(typeRef);
2764 if (typeRef.ArrayRank > 0) {
2765 s += GetArrayPostfix(typeRef);
2770 protected override void ContinueOnNewLine(string st) {
2772 Output.WriteLine(" _");
2775 private bool IsGeneratingStatements() {
2776 Debug.Assert(statementDepth >= 0, "statementDepth >= 0");
2777 return (statementDepth > 0);
2780 private void GenerateVBStatements(CodeStatementCollection stms) {
2783 GenerateStatements(stms);
2790 [ResourceExposure(ResourceScope.Machine)]
2791 [ResourceConsumption(ResourceScope.Machine)]
2792 protected override CompilerResults FromFileBatch(CompilerParameters options, string[] fileNames) {
2793 if( options == null) {
2794 throw new ArgumentNullException("options");
2796 if (fileNames == null)
2797 throw new ArgumentNullException("fileNames");
2799 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
2801 string outputFile = null;
2804 CompilerResults results = new CompilerResults(options.TempFiles);
2805 SecurityPermission perm1 = new SecurityPermission(SecurityPermissionFlag.ControlEvidence);
2808 #pragma warning disable 618
2809 results.Evidence = options.Evidence;
2810 #pragma warning restore 618
2813 SecurityPermission.RevertAssert();
2815 bool createdEmptyAssembly = false;
2817 string extension = (options.GenerateExecutable) ? "exe" : "dll";
2818 string extensionWithDot = '.' + extension;
2820 if (options.OutputAssembly == null || options.OutputAssembly.Length == 0) {
2821 options.OutputAssembly = results.TempFiles.AddExtension(extension, !options.GenerateInMemory);
2823 // Create an empty assembly. This is so that the file will have permissions that
2824 // we can later access with our current credential.<
2826 new FileStream(options.OutputAssembly, FileMode.Create, FileAccess.ReadWrite).Close();
2827 createdEmptyAssembly = true;
2830 String outputAssemblyFile = options.OutputAssembly;
2832 if (!Path.GetExtension(outputAssemblyFile).Equals(extensionWithDot, StringComparison.OrdinalIgnoreCase)) {
2833 // The vb compiler automatically appends the 'dll' or 'exe' extension if it's not present.
2834 // We similarly determine the file name, so we can find it later.
2835 outputAssemblyFile += extensionWithDot;
2839 string pdbname = "ildb";
2841 string pdbname = "pdb";
2844 // hack so that we don't delete pdbs when debug=false but they have specified pdbonly.
2845 if (options.CompilerOptions!= null && options.CompilerOptions.IndexOf("/debug:pdbonly", StringComparison.OrdinalIgnoreCase) != -1)
2846 results.TempFiles.AddExtension(pdbname, true);
2848 results.TempFiles.AddExtension(pdbname);
2850 string args = CmdArgsFromParameters(options) + " " + JoinStringArray(fileNames, " ");
2852 // Use a response file if the compiler supports it
2853 string responseFileArgs = GetResponseFileCmdArgs(options, args);
2854 string trueArgs = null;
2855 if (responseFileArgs != null) {
2857 args = responseFileArgs;
2861 RedistVersionInfo.GetCompilerPath(provOptions, CompilerName),
2868 results.NativeCompilerReturnValue = retValue;
2870 // only look for errors/warnings if the compile failed or the caller set the warning level
2871 if (retValue != 0 || options.WarningLevel > 0) {
2873 // The VB Compiler generates multi-line error messages. Currently, the best way to obtain the
2874 // full message without going too far, is to use the distinction between \n and \r\n.
2875 // For multi-line error messages, the former is always output between lines of an error message,
2876 // and the latter is output at the end. So this rearranges the output of File.ReadAllLines
2877 // so that an error message is contained on a line.
2879 // As of now, this is the best way to match a full error message. This is because the compiler
2880 // may output other trailing data which isn't an error msg or warning, but doesn't belong to
2881 // the error message. So trailing data could get tacked on since the message doesn't always end
2882 // with punctuation or some other marker. I confirmed this with the VBC group.
2883 byte[] fileBytes = ReadAllBytes(outputFile, FileShare.ReadWrite);
2885 // The output of the compiler is in UTF8
2886 string fileStr = Encoding.UTF8.GetString(fileBytes);
2888 // Split lines only around \r\n (see above)
2889 string[] lines = Regex.Split(fileStr, @"\r\n");
2891 foreach (string line in lines) {
2892 results.Output.Add(line);
2894 ProcessCompilerOutputLine(results, line);
2897 // Delete the empty assembly if we created one
2898 if (retValue != 0 && createdEmptyAssembly)
2899 File.Delete(outputAssemblyFile);
2902 if (!results.Errors.HasErrors && options.GenerateInMemory) {
2903 FileStream fs = new FileStream(outputAssemblyFile, FileMode.Open, FileAccess.Read, FileShare.Read);
2905 int fileLen = (int)fs.Length;
2906 byte[] b = new byte[fileLen];
2907 fs.Read(b, 0, fileLen);
2908 SecurityPermission perm = new SecurityPermission(SecurityPermissionFlag.ControlEvidence);
2911 #pragma warning disable 618 // Load with evidence is obsolete - this warning is passed on via the options.Evidence parameter
2912 results.CompiledAssembly = Assembly.Load(b,null,options.Evidence);
2913 #pragma warning restore 618
2916 SecurityPermission.RevertAssert();
2925 results.PathToAssembly = outputAssemblyFile;
2931 private static byte[] ReadAllBytes(String file, FileShare share)
2934 using(FileStream stream = File.Open(file, FileMode.Open, FileAccess.Read, share))
2937 long fileLength = stream.Length;
2938 if (fileLength > Int32.MaxValue)
2939 throw new ArgumentOutOfRangeException("file");
2941 int count = (int) fileLength;
2942 bytes = new byte[count];
2944 int n = stream.Read(bytes, index, count);
2946 throw new EndOfStreamException();
2953 } // VBCodeGenerator
2955 #endregion class VBCodeGenerator
2958 #region class VBMemberAttributeConverter
2960 internal class VBMemberAttributeConverter : VBModifierAttributeConverter {
2962 private static volatile string[] names;
2963 private static volatile object[] values;
2964 private static volatile VBMemberAttributeConverter defaultConverter;
2967 private VBMemberAttributeConverter() {
2968 // no need to create an instance; use Default
2971 public static VBMemberAttributeConverter Default {
2973 if (defaultConverter == null) {
2974 defaultConverter = new VBMemberAttributeConverter();
2976 return defaultConverter;
2981 /// Retrieves an array of names for attributes.
2983 protected override string[] Names {
2985 if (names == null) {
2986 names = new string[] {
3000 /// Retrieves an array of values for attributes.
3002 protected override object[] Values {
3004 if (values == null) {
3005 values = new object[] {
3006 (object)MemberAttributes.Public,
3007 (object)MemberAttributes.Family,
3008 (object)MemberAttributes.FamilyOrAssembly,
3009 (object)MemberAttributes.Assembly,
3010 (object)MemberAttributes.Private
3018 protected override object DefaultValue {
3020 return MemberAttributes.Private;
3023 } // VBMemberAttributeConverter
3025 #endregion class VBMemberAttributeConverter
3028 #region class VBTypeAttributeConverter
3030 internal class VBTypeAttributeConverter : VBModifierAttributeConverter {
3031 private static volatile VBTypeAttributeConverter defaultConverter;
3032 private static volatile string[] names;
3033 private static volatile object[] values;
3035 private VBTypeAttributeConverter() {
3036 // no need to create an instance; use Default
3039 public static VBTypeAttributeConverter Default {
3041 if (defaultConverter == null) {
3042 defaultConverter = new VBTypeAttributeConverter();
3044 return defaultConverter;
3049 /// Retrieves an array of names for attributes.
3051 protected override string[] Names {
3053 if (names == null) {
3054 names = new string[] {
3065 /// Retrieves an array of values for attributes.
3067 protected override object[] Values {
3069 if (values == null) {
3070 values = new object[] {
3071 (object)TypeAttributes.Public,
3072 (object)TypeAttributes.NotPublic
3080 protected override object DefaultValue {
3082 return TypeAttributes.Public;
3085 } // VBTypeAttributeConverter
3087 #endregion class VBTypeAttributeConverter
3090 #region class VBModifierAttributeConverter
3093 /// This type converter provides common values for MemberAttributes
3095 internal abstract class VBModifierAttributeConverter : TypeConverter {
3097 protected abstract object[] Values { get; }
3098 protected abstract string[] Names { get; }
3099 protected abstract object DefaultValue { get; }
3102 /// We override this because we can convert from string types.
3104 public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
3105 if (sourceType == typeof(string)) {
3109 return base.CanConvertFrom(context, sourceType);
3113 /// Converts the given object to the converter's native type.
3115 public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
3116 if (value is string) {
3117 string name = (string)value;
3118 string[] names = Names;
3119 for (int i = 0; i < names.Length; i++) {
3120 if (names[i].Equals(name, StringComparison.OrdinalIgnoreCase)) {
3126 return DefaultValue;
3130 /// Converts the given object to another type. The most common types to convert
3131 /// are to and from a string object. The default implementation will make a call
3132 /// to ToString on the object if the object is valid and if the destination
3133 /// type is string. If this cannot convert to the desitnation type, this will
3134 /// throw a NotSupportedException.
3136 public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
3137 if (destinationType == null) {
3138 throw new ArgumentNullException("destinationType");
3141 if (destinationType == typeof(string)) {
3142 object[] modifiers = Values;
3143 for (int i = 0; i < modifiers.Length; i++) {
3144 if (modifiers[i].Equals(value)) {
3149 return SR.GetString(SR.toStringUnknown);
3152 return base.ConvertTo(context, culture, value, destinationType);
3156 /// Determines if the list of standard values returned from
3157 /// GetStandardValues is an exclusive list. If the list
3158 /// is exclusive, then no other values are valid, such as
3159 /// in an enum data type. If the list is not exclusive,
3160 /// then there are other valid values besides the list of
3161 /// standard values GetStandardValues provides.
3163 public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) {
3168 /// Determines if this object supports a standard set of values
3169 /// that can be picked from a list.
3171 public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
3176 /// Retrieves a collection containing a set of standard values
3177 /// for the data type this validator is designed for. This
3178 /// will return null if the data type does not support a
3179 /// standard set of values.
3181 public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) {
3182 return new StandardValuesCollection(Values);
3184 } // VBModifierAttributeConverter
3186 #endregion class VBModifierAttributeConverter