PageRenderTime 33ms CodeModel.GetById 2ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/Test/Mono.Cecil.Tests/CustomAttributesTests.cs

http://github.com/jbevain/cecil
C# | 679 lines | 505 code | 172 blank | 2 comment | 29 complexity | debd0687cb625139caff2cf5b7532326 MD5 | raw file
  1using System;
  2using System.Globalization;
  3using System.IO;
  4using System.Linq;
  5using System.Text;
  6
  7using Mono.Cecil;
  8using Mono.Cecil.Metadata;
  9using Mono.Cecil.PE;
 10
 11using NUnit.Framework;
 12
 13namespace Mono.Cecil.Tests {
 14
 15	[TestFixture]
 16	public class CustomAttributesTests : BaseTestFixture {
 17
 18		[Test]
 19		public void StringArgumentOnType ()
 20		{
 21			TestCSharp ("CustomAttributes.cs", module => {
 22				var hamster = module.GetType ("Hamster");
 23
 24				Assert.IsTrue (hamster.HasCustomAttributes);
 25				Assert.AreEqual (1, hamster.CustomAttributes.Count);
 26
 27				var attribute = hamster.CustomAttributes [0];
 28				Assert.AreEqual ("System.Void FooAttribute::.ctor(System.String)",
 29					attribute.Constructor.FullName);
 30
 31				Assert.IsTrue (attribute.HasConstructorArguments);
 32				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
 33
 34				AssertArgument ("bar", attribute.ConstructorArguments [0]);
 35			});
 36		}
 37
 38		[Test]
 39		public void NullString ()
 40		{
 41			TestCSharp ("CustomAttributes.cs", module => {
 42				var dentist = module.GetType ("Dentist");
 43
 44				var attribute = GetAttribute (dentist, "Foo");
 45				Assert.IsNotNull (attribute);
 46
 47				AssertArgument<string> (null, attribute.ConstructorArguments [0]);
 48			});
 49		}
 50
 51		[Test]
 52		public void Primitives1 ()
 53		{
 54			TestCSharp ("CustomAttributes.cs", module => {
 55				var steven = module.GetType ("Steven");
 56
 57				var attribute = GetAttribute (steven, "Foo");
 58				Assert.IsNotNull (attribute);
 59
 60				AssertArgument<sbyte> (-12, attribute.ConstructorArguments [0]);
 61				AssertArgument<byte> (242, attribute.ConstructorArguments [1]);
 62				AssertArgument<bool> (true, attribute.ConstructorArguments [2]);
 63				AssertArgument<bool> (false, attribute.ConstructorArguments [3]);
 64				AssertArgument<ushort> (4242, attribute.ConstructorArguments [4]);
 65				AssertArgument<short> (-1983, attribute.ConstructorArguments [5]);
 66				AssertArgument<char> ('c', attribute.ConstructorArguments [6]);
 67			});
 68		}
 69
 70		[Test]
 71		public void Primitives2 ()
 72		{
 73			TestCSharp ("CustomAttributes.cs", module => {
 74				var seagull = module.GetType ("Seagull");
 75
 76				var attribute = GetAttribute (seagull, "Foo");
 77				Assert.IsNotNull (attribute);
 78
 79				AssertArgument<int> (-100000, attribute.ConstructorArguments [0]);
 80				AssertArgument<uint> (200000, attribute.ConstructorArguments [1]);
 81				AssertArgument<float> (12.12f, attribute.ConstructorArguments [2]);
 82				AssertArgument<long> (long.MaxValue, attribute.ConstructorArguments [3]);
 83				AssertArgument<ulong> (ulong.MaxValue, attribute.ConstructorArguments [4]);
 84				AssertArgument<double> (64.646464, attribute.ConstructorArguments [5]);
 85			});
 86		}
 87
 88		[Test]
 89		public void StringArgumentOnAssembly ()
 90		{
 91			TestCSharp ("CustomAttributes.cs", module => {
 92				var assembly = module.Assembly;
 93
 94				var attribute = GetAttribute (assembly, "Foo");
 95				Assert.IsNotNull (attribute);
 96
 97				AssertArgument ("bingo", attribute.ConstructorArguments [0]);
 98			});
 99		}
100
101		[Test]
102		public void CharArray ()
103		{
104			TestCSharp ("CustomAttributes.cs", module => {
105				var rifle = module.GetType ("Rifle");
106
107				var attribute = GetAttribute (rifle, "Foo");
108				Assert.IsNotNull (attribute);
109
110				var argument = attribute.ConstructorArguments [0];
111
112				Assert.AreEqual ("System.Char[]", argument.Type.FullName);
113
114				var array = argument.Value as CustomAttributeArgument [];
115				Assert.IsNotNull (array);
116
117				var str = "cecil";
118
119				Assert.AreEqual (array.Length, str.Length);
120
121				for (int i = 0; i < str.Length; i++)
122				AssertArgument (str [i], array [i]);
123			});
124		}
125
126		[Test]
127		public void BoxedArguments ()
128		{
129			TestCSharp ("CustomAttributes.cs", module => {
130				var worm = module.GetType ("Worm");
131
132				var attribute = GetAttribute (worm, "Foo");
133				Assert.IsNotNull (attribute);
134
135				Assert.AreEqual (".ctor ((Object:(String:\"2\")), (Object:(I4:2)))", PrettyPrint (attribute));
136			});
137		}
138
139		[Test]
140		public void BoxedArraysArguments ()
141		{
142			TestCSharp ("CustomAttributes.cs", module => {
143				var sheep = module.GetType ("Sheep");
144
145				var attribute = GetAttribute (sheep, "Foo");
146				Assert.IsNotNull (attribute);
147
148				// [Foo (new object [] { "2", 2, 'c' }, new object [] { new object [] { 1, 2, 3}, null })]
149				AssertCustomAttribute (".ctor ((Object:(Object[]:{(Object:(String:\"2\")), (Object:(I4:2)), (Object:(Char:'c'))})), (Object:(Object[]:{(Object:(Object[]:{(Object:(I4:1)), (Object:(I4:2)), (Object:(I4:3))})), (Object:(String:null))})))", attribute);
150			});
151		}
152
153		[Test]
154		public void FieldsAndProperties ()
155		{
156			TestCSharp ("CustomAttributes.cs", module => {
157				var angola = module.GetType ("Angola");
158
159				var attribute = GetAttribute (angola, "Foo");
160				Assert.IsNotNull (attribute);
161
162				Assert.AreEqual (2, attribute.Fields.Count);
163
164				var argument = attribute.Fields.Where (a => a.Name == "Pan").First ();
165				AssertCustomAttributeArgument ("(Object:(Object[]:{(Object:(I4:1)), (Object:(String:\"2\")), (Object:(Char:'3'))}))", argument);
166
167				argument = attribute.Fields.Where (a => a.Name == "PanPan").First ();
168				AssertCustomAttributeArgument ("(String[]:{(String:\"yo\"), (String:\"yo\")})", argument);
169
170				Assert.AreEqual (2, attribute.Properties.Count);
171
172				argument = attribute.Properties.Where (a => a.Name == "Bang").First ();
173				AssertArgument (42, argument);
174
175				argument = attribute.Properties.Where (a => a.Name == "Fiou").First ();
176				AssertArgument<string> (null, argument);
177			});
178		}
179
180		[Test]
181		public void BoxedStringField ()
182		{
183			TestCSharp ("CustomAttributes.cs", module => {
184				var type = module.GetType ("BoxedStringField");
185
186				var attribute = GetAttribute (type, "Foo");
187				Assert.IsNotNull (attribute);
188
189				Assert.AreEqual (1, attribute.Fields.Count);
190
191				var argument = attribute.Fields.Where (a => a.Name == "Pan").First ();
192				AssertCustomAttributeArgument ("(Object:(String:\"fiouuu\"))", argument);
193			});
194		}
195
196		[Test]
197		public void TypeDefinitionEnum ()
198		{
199			TestCSharp ("CustomAttributes.cs", module => {
200				var zero = module.GetType ("Zero");
201
202				var attribute = GetAttribute (zero, "Foo");
203				Assert.IsNotNull (attribute);
204
205				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
206
207				Assert.AreEqual ((short) 2, attribute.ConstructorArguments [0].Value);
208				Assert.AreEqual ("Bingo", attribute.ConstructorArguments [0].Type.FullName);
209			});
210		}
211
212		[Test]
213		public void TypeReferenceEnum ()
214		{
215			TestCSharp ("CustomAttributes.cs", module => {
216				var ace = module.GetType ("Ace");
217
218				var attribute = GetAttribute (ace, "Foo");
219				Assert.IsNotNull (attribute);
220
221				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
222
223				Assert.AreEqual ((byte) 0x04, attribute.ConstructorArguments [0].Value);
224				Assert.AreEqual ("System.Security.AccessControl.AceFlags", attribute.ConstructorArguments [0].Type.FullName);
225				Assert.AreEqual (module, attribute.ConstructorArguments [0].Type.Module);
226			});
227		}
228
229		[Test]
230		public void BoxedEnumReference ()
231		{
232			TestCSharp ("CustomAttributes.cs", module => {
233				var bzzz = module.GetType ("Bzzz");
234
235				var attribute = GetAttribute (bzzz, "Foo");
236				Assert.IsNotNull (attribute);
237
238				// [Foo (new object [] { Bingo.Fuel, Bingo.Binga }, null, Pan = System.Security.AccessControl.AceFlags.NoPropagateInherit)]
239
240				Assert.AreEqual (2, attribute.ConstructorArguments.Count);
241
242				var argument = attribute.ConstructorArguments [0];
243
244				AssertCustomAttributeArgument ("(Object:(Object[]:{(Object:(Bingo:2)), (Object:(Bingo:4))}))", argument);
245
246				argument = attribute.ConstructorArguments [1];
247
248				AssertCustomAttributeArgument ("(Object:(String:null))", argument);
249
250				argument = attribute.Fields.Where (a => a.Name == "Pan").First ().Argument;
251
252				AssertCustomAttributeArgument ("(Object:(System.Security.AccessControl.AceFlags:4))", argument);
253			});
254		}
255
256		[Test]
257		public void TypeOfTypeDefinition ()
258		{
259			TestCSharp ("CustomAttributes.cs", module => {
260				var typed = module.GetType ("Typed");
261
262				var attribute = GetAttribute (typed, "Foo");
263				Assert.IsNotNull (attribute);
264
265				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
266
267				var argument = attribute.ConstructorArguments [0];
268
269				Assert.AreEqual ("System.Type", argument.Type.FullName);
270
271				var type = argument.Value as TypeDefinition;
272				Assert.IsNotNull (type);
273
274				Assert.AreEqual ("Bingo", type.FullName);
275			});
276		}
277
278		[Test]
279		public void TypeOfNestedTypeDefinition ()
280		{
281			TestCSharp ("CustomAttributes.cs", module => {
282				var typed = module.GetType ("NestedTyped");
283
284				var attribute = GetAttribute (typed, "Foo");
285				Assert.IsNotNull (attribute);
286
287				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
288
289				var argument = attribute.ConstructorArguments [0];
290
291				Assert.AreEqual ("System.Type", argument.Type.FullName);
292
293				var type = argument.Value as TypeDefinition;
294				Assert.IsNotNull (type);
295
296				Assert.AreEqual ("FooAttribute/Token", type.FullName);
297			});
298		}
299
300		[Test]
301		public void FieldTypeOf ()
302		{
303			TestCSharp ("CustomAttributes.cs", module => {
304				var truc = module.GetType ("Truc");
305
306				var attribute = GetAttribute (truc, "Foo");
307				Assert.IsNotNull (attribute);
308
309				var argument = attribute.Fields.Where (a => a.Name == "Chose").First ().Argument;
310
311				Assert.AreEqual ("System.Type", argument.Type.FullName);
312
313				var type = argument.Value as TypeDefinition;
314				Assert.IsNotNull (type);
315
316				Assert.AreEqual ("Typed", type.FullName);
317			});
318		}
319
320		[Test]
321		public void EscapedTypeName ()
322		{
323			TestModule ("bug-185.dll", module => {
324				var foo = module.GetType ("Foo");
325				var foo_do = foo.Methods.Where (m => !m.IsConstructor).First ();
326
327				var attribute = foo_do.CustomAttributes.Where (ca => ca.AttributeType.Name == "AsyncStateMachineAttribute").First ();
328
329				Assert.AreEqual (foo.NestedTypes [0], attribute.ConstructorArguments [0].Value);
330
331				var function = module.GetType ("Function`1");
332
333				var apply = function.Methods.Where(m => !m.IsConstructor).First ();
334
335				attribute = apply.CustomAttributes.Where (ca => ca.AttributeType.Name == "AsyncStateMachineAttribute").First ();
336
337				Assert.AreEqual (function.NestedTypes [0], attribute.ConstructorArguments [0].Value);
338			});
339		}
340
341		[Test]
342		public void FieldNullTypeOf ()
343		{
344			TestCSharp ("CustomAttributes.cs", module => {
345				var truc = module.GetType ("Machin");
346
347				var attribute = GetAttribute (truc, "Foo");
348				Assert.IsNotNull (attribute);
349
350				var argument = attribute.Fields.Where (a => a.Name == "Chose").First ().Argument;
351
352				Assert.AreEqual ("System.Type", argument.Type.FullName);
353
354				Assert.IsNull (argument.Value);
355			});
356		}
357
358		[Test]
359		public void OpenGenericTypeOf ()
360		{
361			TestCSharp ("CustomAttributes.cs", module => {
362				var open_generic = module.GetType ("OpenGeneric`2");
363				Assert.IsNotNull (open_generic);
364
365				var attribute = GetAttribute (open_generic, "Foo");
366				Assert.IsNotNull (attribute);
367
368				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
369
370				var argument = attribute.ConstructorArguments [0];
371
372				Assert.AreEqual ("System.Type", argument.Type.FullName);
373
374				var type = argument.Value as TypeReference;
375				Assert.IsNotNull (type);
376
377				Assert.AreEqual ("System.Collections.Generic.Dictionary`2", type.FullName);
378			});
379		}
380
381		[Test]
382		public void ClosedGenericTypeOf ()
383		{
384			TestCSharp ("CustomAttributes.cs", module => {
385				var closed_generic = module.GetType ("ClosedGeneric");
386				Assert.IsNotNull (closed_generic);
387
388				var attribute = GetAttribute (closed_generic, "Foo");
389				Assert.IsNotNull (attribute);
390
391				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
392
393				var argument = attribute.ConstructorArguments [0];
394
395				Assert.AreEqual ("System.Type", argument.Type.FullName);
396
397				var type = argument.Value as TypeReference;
398				Assert.IsNotNull (type);
399
400				Assert.AreEqual ("System.Collections.Generic.Dictionary`2<System.String,OpenGeneric`2<Machin,System.Int32>[,]>", type.FullName);
401			});
402		}
403
404		[Test]
405		public void TypeOfArrayOfNestedClass ()
406		{
407			TestCSharp ("CustomAttributes.cs", module => {
408				var parent = module.GetType ("Parent");
409				Assert.IsNotNull (parent);
410
411				var attribute = GetAttribute (parent, "Foo");
412				Assert.IsNotNull (attribute);
413
414				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
415
416				var argument = attribute.ConstructorArguments [0];
417
418				Assert.AreEqual ("System.Type", argument.Type.FullName);
419
420				var type = argument.Value as TypeReference;
421				Assert.IsNotNull (type);
422
423				Assert.AreEqual ("Parent/Child[]", type.FullName);
424			});
425		}
426
427		[Test]
428		public void EmptyBlob ()
429		{
430			TestIL ("ca-empty-blob.il", module => {
431				var attribute = module.GetType ("CustomAttribute");
432				Assert.AreEqual (1, attribute.CustomAttributes.Count);
433				Assert.AreEqual (0, attribute.CustomAttributes [0].ConstructorArguments.Count);
434			}, verify: !Platform.OnMono);
435		}
436
437		[Test]
438		public void InterfaceImplementation ()
439		{
440			OnlyOnWindows (); // Mono's ilasm doesn't support .interfaceimpl
441
442			TestIL ("ca-iface-impl.il", module => {
443				var type = module.GetType ("FooType");
444				var iface = type.Interfaces.Single (i => i.InterfaceType.FullName == "IFoo");
445				Assert.IsTrue (iface.HasCustomAttributes);
446				var attributes = iface.CustomAttributes;
447				Assert.AreEqual (1, attributes.Count);
448				Assert.AreEqual ("FooAttribute", attributes [0].AttributeType.FullName);
449			});
450		}
451
452		[Test]
453		public void GenericParameterConstraint ()
454		{
455			TestModule ("GenericParameterConstraintAttributes.dll", module => {
456				var type = module.GetType ("Foo.Library`1");
457				var gp = type.GenericParameters.Single ();
458				var constraint = gp.Constraints.Single ();
459
460				Assert.IsTrue (constraint.HasCustomAttributes);
461				var attributes = constraint.CustomAttributes;
462				Assert.AreEqual (1, attributes.Count);
463				Assert.AreEqual ("System.Runtime.CompilerServices.NullableAttribute", attributes [0].AttributeType.FullName);
464			}, verify: !Platform.OnMono);
465		}
466
467		[Test]
468		public void NullCharInString ()
469		{
470			TestCSharp ("CustomAttributes.cs", module => {
471				var type = module.GetType ("NullCharInString");
472				var attributes = type.CustomAttributes;
473				Assert.AreEqual (1, attributes.Count);
474				var attribute = attributes [0];
475				Assert.AreEqual (1, attribute.ConstructorArguments.Count);
476				var value = (string) attribute.ConstructorArguments [0].Value;
477				Assert.AreEqual (8, value.Length);
478				Assert.AreEqual ('\0', value [7]);
479			});
480		}
481
482		[Test]
483		public void OrderedAttributes ()
484		{
485			TestModule ("ordered-attrs.exe", module => {
486				var type = module.GetType ("Program");
487				var method = type.GetMethod ("Main");
488				var attributes = method.CustomAttributes;
489				Assert.AreEqual (6, attributes.Count);
490
491				Assert.AreEqual ("AAttribute", attributes [0].AttributeType.Name);
492				Assert.AreEqual ("Main.A1", attributes [0].Fields [0].Argument.Value as string);
493
494				Assert.AreEqual ("AAttribute", attributes [1].AttributeType.Name);
495				Assert.AreEqual ("Main.A2", attributes [1].Fields [0].Argument.Value as string);
496
497				Assert.AreEqual ("BAttribute", attributes [2].AttributeType.Name);
498				Assert.AreEqual ("Main.B1", attributes [2].Fields [0].Argument.Value as string);
499
500				Assert.AreEqual ("AAttribute", attributes [3].AttributeType.Name);
501				Assert.AreEqual ("Main.A3", attributes [3].Fields [0].Argument.Value as string);
502
503				Assert.AreEqual ("BAttribute", attributes [4].AttributeType.Name);
504				Assert.AreEqual ("Main.B2", attributes [4].Fields [0].Argument.Value as string);
505
506				Assert.AreEqual ("BAttribute", attributes [5].AttributeType.Name);
507				Assert.AreEqual ("Main.B3", attributes [5].Fields [0].Argument.Value as string);
508			});
509		}
510
511		[Test]
512		public void DefineCustomAttributeFromBlob ()
513		{
514			var file = Path.Combine (Path.GetTempPath (), "CaBlob.dll");
515
516			var module = ModuleDefinition.CreateModule ("CaBlob.dll", new ModuleParameters { Kind = ModuleKind.Dll, Runtime = TargetRuntime.Net_2_0 });
517			var assembly_title_ctor = module.ImportReference (typeof (System.Reflection.AssemblyTitleAttribute).GetConstructor (new [] {typeof (string)}));
518
519			Assert.IsNotNull (assembly_title_ctor);
520
521			var buffer = new ByteBuffer ();
522			buffer.WriteUInt16 (1); // ca signature
523
524			var title = Encoding.UTF8.GetBytes ("CaBlob");
525
526			buffer.WriteCompressedUInt32 ((uint) title.Length);
527			buffer.WriteBytes (title);
528
529			buffer.WriteUInt16 (0); // named arguments
530
531			var blob = new byte [buffer.length];
532			Buffer.BlockCopy (buffer.buffer, 0, blob, 0, buffer.length);
533
534			var attribute = new CustomAttribute (assembly_title_ctor, blob);
535			module.Assembly.CustomAttributes.Add (attribute);
536
537			module.Write (file);
538
539			module = ModuleDefinition.ReadModule (file);
540
541			attribute = GetAttribute (module.Assembly, "AssemblyTitle");
542
543			Assert.IsNotNull (attribute);
544			Assert.AreEqual ("CaBlob", (string) attribute.ConstructorArguments [0].Value);
545
546			module.Dispose ();
547		}
548
549		static void AssertCustomAttribute (string expected, CustomAttribute attribute)
550		{
551			Assert.AreEqual (expected, PrettyPrint (attribute));
552		}
553
554		static void AssertCustomAttributeArgument (string expected, CustomAttributeNamedArgument named_argument)
555		{
556			AssertCustomAttributeArgument (expected, named_argument.Argument);
557		}
558
559		static void AssertCustomAttributeArgument (string expected, CustomAttributeArgument argument)
560		{
561			var result = new StringBuilder ();
562			PrettyPrint (argument, result);
563
564			Assert.AreEqual (expected, result.ToString ());
565		}
566
567		static string PrettyPrint (CustomAttribute attribute)
568		{
569			var signature = new StringBuilder ();
570			signature.Append (".ctor (");
571
572			for (int i = 0; i < attribute.ConstructorArguments.Count; i++) {
573				if (i > 0)
574					signature.Append (", ");
575
576				PrettyPrint (attribute.ConstructorArguments [i], signature);
577			}
578
579			signature.Append (")");
580			return signature.ToString ();
581		}
582
583		static void PrettyPrint (CustomAttributeArgument argument, StringBuilder signature)
584		{
585			var value = argument.Value;
586
587			signature.Append ("(");
588
589			PrettyPrint (argument.Type, signature);
590
591			signature.Append (":");
592
593			PrettyPrintValue (argument.Value, signature);
594
595			signature.Append (")");
596		}
597
598		static void PrettyPrintValue (object value, StringBuilder signature)
599		{
600			if (value == null) {
601				signature.Append ("null");
602				return;
603			}
604
605			var arguments = value as CustomAttributeArgument [];
606			if (arguments != null) {
607				signature.Append ("{");
608				for (int i = 0; i < arguments.Length; i++) {
609					if (i > 0)
610						signature.Append (", ");
611
612					PrettyPrint (arguments [i], signature);
613				}
614				signature.Append ("}");
615
616				return;
617			}
618
619			switch (Type.GetTypeCode (value.GetType ())) {
620			case System.TypeCode.String:
621				signature.AppendFormat ("\"{0}\"", value);
622				break;
623			case System.TypeCode.Char:
624				signature.AppendFormat ("'{0}'", (char) value);
625				break;
626			default:
627				var formattable = value as IFormattable;
628				if (formattable != null) {
629					signature.Append (formattable.ToString (null, CultureInfo.InvariantCulture));
630					return;
631				}
632
633				if (value is CustomAttributeArgument) {
634					PrettyPrint ((CustomAttributeArgument) value, signature);
635					return;
636				}
637				break;
638			}
639		}
640
641		static void PrettyPrint (TypeReference type, StringBuilder signature)
642		{
643			if (type.IsArray) {
644				ArrayType array = (ArrayType) type;
645				signature.AppendFormat ("{0}[]", array.ElementType.etype.ToString ());
646			} else if (type.etype == ElementType.None) {
647				signature.Append (type.FullName);
648			} else
649				signature.Append (type.etype.ToString ());
650		}
651
652		static void AssertArgument<T> (T value, CustomAttributeNamedArgument named_argument)
653		{
654			AssertArgument (value, named_argument.Argument);
655		}
656
657		static void AssertArgument<T> (T value, CustomAttributeArgument argument)
658		{
659			AssertArgument (typeof (T).FullName, (object) value, argument);
660		}
661
662		static void AssertArgument (string type, object value, CustomAttributeArgument argument)
663		{
664			Assert.AreEqual (type, argument.Type.FullName);
665			Assert.AreEqual (value, argument.Value);
666		}
667
668		static CustomAttribute GetAttribute (ICustomAttributeProvider owner, string type)
669		{
670			Assert.IsTrue (owner.HasCustomAttributes);
671
672			foreach (var attribute in owner.CustomAttributes)
673				if (attribute.Constructor.DeclaringType.Name.StartsWith (type))
674					return attribute;
675
676			return null;
677		}
678	}
679}