f2b0ca6aca7d7e90d890099b63585d75adfc0a53
[mono.git] / mcs / mcs / field.cs
1 //
2 // field.cs: All field handlers
3 //
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 //          Martin Baulig (martin@ximian.com)
6 //          Marek Safar (marek.safar@seznam.cz)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004-2008 Novell, Inc
12 //
13
14 using System;
15 using System.Collections.Generic;
16 using System.Runtime.InteropServices;
17
18 #if STATIC
19 using MetaType = IKVM.Reflection.Type;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
22 #else
23 using MetaType = System.Type;
24 using System.Reflection;
25 using System.Reflection.Emit;
26 #endif
27
28 namespace Mono.CSharp
29 {
30         public class FieldDeclarator
31         {
32                 public FieldDeclarator (SimpleMemberName name, Expression initializer)
33                 {
34                         this.Name = name;
35                         this.Initializer = initializer;
36                 }
37
38                 #region Properties
39
40                 public SimpleMemberName Name { get; private set; }
41                 public Expression Initializer { get; private set; }
42
43                 #endregion
44         }
45
46         //
47         // Abstract class for all fields
48         //
49         abstract public class FieldBase : MemberBase
50         {
51                 protected FieldBuilder FieldBuilder;
52                 protected FieldSpec spec;
53                 public Status status;
54                 protected Expression initializer;
55                 protected List<FieldDeclarator> declarators;
56
57                 [Flags]
58                 public enum Status : byte {
59                         HAS_OFFSET = 4          // Used by FieldMember.
60                 }
61
62                 static readonly string[] attribute_targets = new string [] { "field" };
63
64                 protected FieldBase (DeclSpace parent, FullNamedExpression type, Modifiers mod,
65                                      Modifiers allowed_mod, MemberName name, Attributes attrs)
66                         : base (parent, null, type, mod, allowed_mod | Modifiers.ABSTRACT, Modifiers.PRIVATE,
67                                 name, attrs)
68                 {
69                         if ((mod & Modifiers.ABSTRACT) != 0)
70                                 Report.Error (681, Location, "The modifier 'abstract' is not valid on fields. Try using a property instead");
71                 }
72
73                 #region Properties
74
75                 public override AttributeTargets AttributeTargets {
76                         get {
77                                 return AttributeTargets.Field;
78                         }
79                 }
80
81                 public Expression Initializer {
82                         get {
83                                 return initializer;
84                         }
85                         set {
86                                 this.initializer = value;
87                         }
88                 }
89
90                 public FieldSpec Spec {
91                         get {
92                                 return spec;
93                         }
94                 }
95
96                 public override string[] ValidAttributeTargets  {
97                         get {
98                                 return attribute_targets;
99                         }
100                 }
101
102                 #endregion
103
104                 public void AddDeclarator (FieldDeclarator declarator)
105                 {
106                         if (declarators == null)
107                                 declarators = new List<FieldDeclarator> (2);
108
109                         declarators.Add (declarator);
110
111                         // TODO: This will probably break
112                         Parent.AddMember (this, declarator.Name.Value);
113                 }
114
115                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
116                 {
117                         if (a.Type == pa.FieldOffset) {
118                                 status |= Status.HAS_OFFSET;
119
120                                 if (!Parent.PartialContainer.HasExplicitLayout) {
121                                         Report.Error (636, Location, "The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit)");
122                                         return;
123                                 }
124
125                                 if ((ModFlags & Modifiers.STATIC) != 0 || this is Const) {
126                                         Report.Error (637, Location, "The FieldOffset attribute is not allowed on static or const fields");
127                                         return;
128                                 }
129                         }
130
131                         if (a.Type == pa.FixedBuffer) {
132                                 Report.Error (1716, Location, "Do not use 'System.Runtime.CompilerServices.FixedBuffer' attribute. Use the 'fixed' field modifier instead");
133                                 return;
134                         }
135
136 #if false
137                         if (a.Type == pa.MarshalAs) {
138                                 UnmanagedMarshal marshal = a.GetMarshal (this);
139                                 if (marshal != null) {
140                                         FieldBuilder.SetMarshal (marshal);
141                                 }
142                                 return;
143                         }
144 #endif
145                         if ((a.HasSecurityAttribute)) {
146                                 a.Error_InvalidSecurityParent ();
147                                 return;
148                         }
149
150                         if (a.Type == pa.Dynamic) {
151                                 a.Error_MisusedDynamicAttribute ();
152                                 return;
153                         }
154
155                         FieldBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
156                 }
157
158                 public void SetCustomAttribute (MethodSpec ctor, byte[] data)
159                 {
160                         FieldBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), data);
161                 }
162
163                 protected override bool CheckBase ()
164                 {
165                         if (!base.CheckBase ())
166                                 return false;
167
168                         MemberSpec candidate;
169                         var conflict_symbol = MemberCache.FindBaseMember (this, out candidate);
170                         if (conflict_symbol == null)
171                                 conflict_symbol = candidate;
172
173                         if (conflict_symbol == null) {
174                                 if ((ModFlags & Modifiers.NEW) != 0) {
175                                         Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required",
176                                                 GetSignatureForError ());
177                                 }
178                         } else {
179                                 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE | Modifiers.BACKING_FIELD)) == 0) {
180                                         Report.SymbolRelatedToPreviousError (conflict_symbol);
181                                         Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
182                                                 GetSignatureForError (), conflict_symbol.GetSignatureForError ());
183                                 }
184
185                                 if (conflict_symbol.IsAbstract) {
186                                         Report.SymbolRelatedToPreviousError (conflict_symbol);
187                                         Report.Error (533, Location, "`{0}' hides inherited abstract member `{1}'",
188                                                 GetSignatureForError (), conflict_symbol.GetSignatureForError ());
189                                 }
190                         }
191  
192                         return true;
193                 }
194
195                 public virtual Constant ConvertInitializer (ResolveContext rc, Constant expr)
196                 {
197                         return expr.ConvertImplicitly (rc, MemberType);
198                 }
199
200                 protected override void DoMemberTypeDependentChecks ()
201                 {
202                         base.DoMemberTypeDependentChecks ();
203
204                         if (MemberType.IsGenericParameter)
205                                 return;
206
207                         if (MemberType.IsStatic)
208                                 Error_VariableOfStaticClass (Location, GetSignatureForError (), MemberType, Report);
209
210                         CheckBase ();
211                         IsTypePermitted ();
212                 }
213
214                 //
215                 //   Represents header string for documentation comment.
216                 //
217                 public override string DocCommentHeader {
218                         get { return "F:"; }
219                 }
220
221                 public override void Emit ()
222                 {
223                         if (member_type == InternalType.Dynamic) {
224                                 Module.PredefinedAttributes.Dynamic.EmitAttribute (FieldBuilder);
225                         } else if (!(Parent is CompilerGeneratedClass) && member_type.HasDynamicElement) {
226                                 Module.PredefinedAttributes.Dynamic.EmitAttribute (FieldBuilder, member_type, Location);
227                         }
228
229                         if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
230                                 Module.PredefinedAttributes.CompilerGenerated.EmitAttribute (FieldBuilder);
231
232                         if (OptAttributes != null) {
233                                 OptAttributes.Emit ();
234                         }
235
236                         if (((status & Status.HAS_OFFSET) == 0) && (ModFlags & (Modifiers.STATIC | Modifiers.BACKING_FIELD)) == 0 && Parent.PartialContainer.HasExplicitLayout) {
237                                 Report.Error (625, Location, "`{0}': Instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute", GetSignatureForError ());
238                         }
239
240                         base.Emit ();
241                 }
242
243                 public static void Error_VariableOfStaticClass (Location loc, string variable_name, TypeSpec static_class, Report Report)
244                 {
245                         Report.SymbolRelatedToPreviousError (static_class);
246                         Report.Error (723, loc, "`{0}': cannot declare variables of static types",
247                                 variable_name);
248                 }
249
250                 protected override bool VerifyClsCompliance ()
251                 {
252                         if (!base.VerifyClsCompliance ())
253                                 return false;
254
255                         if (!MemberType.IsCLSCompliant () || this is FixedField) {
256                                 Report.Warning (3003, 1, Location, "Type of `{0}' is not CLS-compliant",
257                                         GetSignatureForError ());
258                         }
259                         return true;
260                 }
261         }
262
263         //
264         // Field specification
265         //
266         public class FieldSpec : MemberSpec, IInterfaceMemberSpec
267         {
268                 FieldInfo metaInfo;
269                 TypeSpec memberType;
270
271                 public FieldSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo info, Modifiers modifiers)
272                         : base (MemberKind.Field, declaringType, definition, modifiers)
273                 {
274                         this.metaInfo = info;
275                         this.memberType = memberType;
276                 }
277
278                 #region Properties
279
280                 public bool IsReadOnly {
281                         get {
282                                 return (Modifiers & Modifiers.READONLY) != 0;
283                         }
284                 }
285
286                 public TypeSpec MemberType {
287                         get {
288                                 return memberType;
289                         }
290                 }
291
292 #endregion
293
294                 public FieldInfo GetMetaInfo ()
295                 {
296                         if ((state & StateFlags.PendingMetaInflate) != 0) {
297                                 var decl_meta = DeclaringType.GetMetaInfo ();
298                                 if (DeclaringType.IsTypeBuilder) {
299                                         metaInfo = TypeBuilder.GetField (decl_meta, metaInfo);
300                                 } else {
301                                         var orig_token = metaInfo.MetadataToken;
302                                         metaInfo = decl_meta.GetField (Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
303                                         if (metaInfo.MetadataToken != orig_token)
304                                                 throw new NotImplementedException ("Resolved to wrong meta token");
305
306                                         // What a stupid API, does not work because field handle is imported
307                                         // metaInfo = FieldInfo.GetFieldFromHandle (metaInfo.FieldHandle, DeclaringType.MetaInfo.TypeHandle);
308                                 }
309
310                                 state &= ~StateFlags.PendingMetaInflate;
311                         }
312
313                         return metaInfo;
314                 }
315
316                 public override MemberSpec InflateMember (TypeParameterInflator inflator)
317                 {
318                         var fs = (FieldSpec) base.InflateMember (inflator);
319                         fs.memberType = inflator.Inflate (memberType);
320                         return fs;
321                 }
322
323                 public FieldSpec Mutate (TypeParameterMutator mutator)
324                 {
325                         var decl = DeclaringType;
326                         if (DeclaringType.IsGenericOrParentIsGeneric)
327                                 decl = mutator.Mutate (decl);
328
329                         if (decl == DeclaringType)
330                                 return this;
331
332                         var fs = (FieldSpec) MemberwiseClone ();
333                         fs.declaringType = decl;
334                         fs.state |= StateFlags.PendingMetaInflate;
335
336                         // Gets back FieldInfo in case of metaInfo was inflated
337                         fs.metaInfo = MemberCache.GetMember (TypeParameterMutator.GetMemberDeclaringType (DeclaringType), this).metaInfo;
338                         return fs;
339                 }
340
341                 public override List<TypeSpec> ResolveMissingDependencies ()
342                 {
343                         return memberType.ResolveMissingDependencies ();
344                 }
345         }
346
347         /// <summary>
348         /// Fixed buffer implementation
349         /// </summary>
350         public class FixedField : FieldBase
351         {
352                 public const string FixedElementName = "FixedElementField";
353                 static int GlobalCounter = 0;
354
355                 TypeBuilder fixed_buffer_type;
356
357                 const Modifiers AllowedModifiers =
358                         Modifiers.NEW |
359                         Modifiers.PUBLIC |
360                         Modifiers.PROTECTED |
361                         Modifiers.INTERNAL |
362                         Modifiers.PRIVATE |
363                         Modifiers.UNSAFE;
364
365                 public FixedField (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name, Attributes attrs)
366                         : base (parent, type, mod, AllowedModifiers, name, attrs)
367                 {
368                 }
369
370                 #region Properties
371
372                 //
373                 // Explicit struct layout set by parent
374                 //
375                 public CharSet? CharSet {
376                         get; set;
377                 }               
378
379                 #endregion
380
381                 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
382                 {
383                         return expr.ImplicitConversionRequired (rc, rc.BuildinTypes.Int, Location);
384                 }
385
386                 public override bool Define ()
387                 {
388                         if (!base.Define ())
389                                 return false;
390
391                         if (!BuildinTypeSpec.IsPrimitiveType (MemberType)) {
392                                 Report.Error (1663, Location,
393                                         "`{0}': Fixed size buffers type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double",
394                                         GetSignatureForError ());
395                         } else if (declarators != null) {
396                                 var t = new TypeExpression (MemberType, TypeExpression.Location);
397                                 int index = Parent.PartialContainer.Fields.IndexOf (this);
398                                 foreach (var d in declarators) {
399                                         var f = new FixedField (Parent, t, ModFlags, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
400                                         f.initializer = d.Initializer;
401                                         ((ConstInitializer) f.initializer).Name = d.Name.Value;
402                                         Parent.PartialContainer.Fields.Insert (++index, f);
403                                 }
404                         }
405                         
406                         // Create nested fixed buffer container
407                         string name = String.Format ("<{0}>__FixedBuffer{1}", Name, GlobalCounter++);
408                         fixed_buffer_type = Parent.TypeBuilder.DefineNestedType (name,
409                                 TypeAttributes.NestedPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit,
410                                 Compiler.BuildinTypes.ValueType.GetMetaInfo ());
411
412                         fixed_buffer_type.DefineField (FixedElementName, MemberType.GetMetaInfo (), FieldAttributes.Public);
413                         
414                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, fixed_buffer_type, ModifiersExtensions.FieldAttr (ModFlags));
415                         var element_spec = new FieldSpec (null, this, MemberType, FieldBuilder, ModFlags);
416                         spec = new FixedFieldSpec (Parent.Definition, this, FieldBuilder, element_spec, ModFlags);
417
418                         Parent.MemberCache.AddMember (spec);
419                         return true;
420                 }
421
422                 protected override void DoMemberTypeIndependentChecks ()
423                 {
424                         base.DoMemberTypeIndependentChecks ();
425
426                         if (!IsUnsafe)
427                                 Expression.UnsafeError (Report, Location);
428
429                         if (Parent.PartialContainer.Kind != MemberKind.Struct) {
430                                 Report.Error (1642, Location, "`{0}': Fixed size buffer fields may only be members of structs",
431                                         GetSignatureForError ());
432                         }
433                 }
434
435                 public override void Emit()
436                 {
437                         ResolveContext rc = new ResolveContext (this);
438                         IntConstant buffer_size_const = initializer.Resolve (rc) as IntConstant;
439                         if (buffer_size_const == null)
440                                 return;
441
442                         int buffer_size = buffer_size_const.Value;
443
444                         if (buffer_size <= 0) {
445                                 Report.Error (1665, Location, "`{0}': Fixed size buffers must have a length greater than zero", GetSignatureForError ());
446                                 return;
447                         }
448
449                         int type_size = BuildinTypeSpec.GetSize (MemberType);
450
451                         if (buffer_size > int.MaxValue / type_size) {
452                                 Report.Error (1664, Location, "Fixed size buffer `{0}' of length `{1}' and type `{2}' exceeded 2^31 limit",
453                                         GetSignatureForError (), buffer_size.ToString (), TypeManager.CSharpName (MemberType));
454                                 return;
455                         }
456
457                         EmitFieldSize (buffer_size);
458
459 #if STATIC
460                         if (Module.HasDefaultCharSet)
461                                 fixed_buffer_type.__SetAttributes (fixed_buffer_type.Attributes | Module.DefaultCharSetType);
462 #endif
463
464                         Module.PredefinedAttributes.UnsafeValueType.EmitAttribute (fixed_buffer_type);
465                         Module.PredefinedAttributes.CompilerGenerated.EmitAttribute (fixed_buffer_type);
466                         fixed_buffer_type.CreateType ();
467
468                         base.Emit ();
469                 }
470
471                 void EmitFieldSize (int buffer_size)
472                 {
473                         PredefinedAttribute pa;
474                         AttributeEncoder encoder;
475
476                         pa = Module.PredefinedAttributes.StructLayout;
477                         if (pa.Constructor == null && !pa.ResolveConstructor (Location, Compiler.BuildinTypes.Short))
478                                 return;
479
480                         var char_set_type = Module.PredefinedTypes.CharSet.Resolve (Location);
481                         if (char_set_type == null)
482                                 return;
483
484                         var field_size = pa.GetField ("Size", Compiler.BuildinTypes.Int, Location);
485                         var field_charset = pa.GetField ("CharSet", char_set_type, Location);
486                         if (field_size == null || field_charset == null)
487                                 return;
488
489                         var char_set = CharSet ?? Module.DefaultCharSet ?? 0;
490
491                         encoder = new AttributeEncoder ();
492                         encoder.Encode ((short)LayoutKind.Sequential);
493                         encoder.EncodeNamedArguments (
494                                 new [] { field_size, field_charset },
495                                 new Constant [] { new IntConstant (buffer_size, Location), new IntConstant ((int) char_set, Location) }
496                         );
497
498                         pa.EmitAttribute (fixed_buffer_type, encoder);
499
500                         //
501                         // Don't emit FixedBufferAttribute attribute for private types
502                         //
503                         if ((ModFlags & Modifiers.PRIVATE) != 0)
504                                 return;
505
506                         pa = Module.PredefinedAttributes.FixedBuffer;
507                         if (pa.Constructor == null && !pa.ResolveConstructor (Location, Compiler.BuildinTypes.Type, Compiler.BuildinTypes.Int))
508                                 return;
509
510                         encoder = new AttributeEncoder ();
511                         encoder.EncodeTypeName (MemberType);
512                         encoder.Encode (buffer_size);
513                         encoder.EncodeEmptyNamedArguments ();
514
515                         pa.EmitAttribute (FieldBuilder, encoder);
516                 }
517         }
518
519         class FixedFieldSpec : FieldSpec
520         {
521                 readonly FieldSpec element;
522
523                 public FixedFieldSpec (TypeSpec declaringType, IMemberDefinition definition, FieldInfo info, FieldSpec element, Modifiers modifiers)
524                         : base (declaringType, definition, element.MemberType, info, modifiers)
525                 {
526                         this.element = element;
527
528                         // It's never CLS-Compliant
529                         state &= ~StateFlags.CLSCompliant_Undetected;
530                 }
531
532                 public FieldSpec Element {
533                         get {
534                                 return element;
535                         }
536                 }
537
538                 public TypeSpec ElementType {
539                         get {
540                                 return MemberType;
541                         }
542                 }
543         }
544
545         //
546         // The Field class is used to represents class/struct fields during parsing.
547         //
548         public class Field : FieldBase {
549                 // <summary>
550                 //   Modifiers allowed in a class declaration
551                 // </summary>
552                 const Modifiers AllowedModifiers =
553                         Modifiers.NEW |
554                         Modifiers.PUBLIC |
555                         Modifiers.PROTECTED |
556                         Modifiers.INTERNAL |
557                         Modifiers.PRIVATE |
558                         Modifiers.STATIC |
559                         Modifiers.VOLATILE |
560                         Modifiers.UNSAFE |
561                         Modifiers.READONLY;
562
563                 public Field (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name,
564                               Attributes attrs)
565                         : base (parent, type, mod, AllowedModifiers, name, attrs)
566                 {
567                 }
568
569                 bool CanBeVolatile ()
570                 {
571                         if (TypeManager.IsReferenceType (MemberType))
572                                 return true;
573
574                         switch (MemberType.BuildinType) {
575                         case BuildinTypeSpec.Type.Bool:
576                         case BuildinTypeSpec.Type.Char:
577                         case BuildinTypeSpec.Type.SByte:
578                         case BuildinTypeSpec.Type.Byte:
579                         case BuildinTypeSpec.Type.Short:
580                         case BuildinTypeSpec.Type.UShort:
581                         case BuildinTypeSpec.Type.Int:
582                         case BuildinTypeSpec.Type.UInt:
583                         case BuildinTypeSpec.Type.Float:
584                         case BuildinTypeSpec.Type.UIntPtr:
585                         case BuildinTypeSpec.Type.IntPtr:
586                                 return true;
587                         }
588
589                         if (MemberType.IsEnum)
590                                 return true;
591
592                         return false;
593                 }
594
595                 public override bool Define ()
596                 {
597                         if (!base.Define ())
598                                 return false;
599
600                         MetaType[] required_modifier = null;
601                         if ((ModFlags & Modifiers.VOLATILE) != 0) {
602                                 var mod = Module.PredefinedTypes.IsVolatile.Resolve (Location);
603                                 if (mod != null)
604                                         required_modifier = new MetaType[] { mod.GetMetaInfo () };
605                         }
606
607                         FieldBuilder = Parent.TypeBuilder.DefineField (
608                                 Name, member_type.GetMetaInfo (), required_modifier, null, ModifiersExtensions.FieldAttr (ModFlags));
609
610                         spec = new FieldSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags);
611
612                         // Don't cache inaccessible fields
613                         if ((ModFlags & Modifiers.BACKING_FIELD) == 0) {
614                                 Parent.MemberCache.AddMember (spec);
615                         }
616
617                         if (initializer != null) {
618                                 ((TypeContainer) Parent).RegisterFieldForInitialization (this,
619                                         new FieldInitializer (spec, initializer, this));
620                         }
621
622                         if (declarators != null) {
623                                 var t = new TypeExpression (MemberType, TypeExpression.Location);
624                                 int index = Parent.PartialContainer.Fields.IndexOf (this);
625                                 foreach (var d in declarators) {
626                                         var f = new Field (Parent, t, ModFlags, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
627                                         if (d.Initializer != null)
628                                                 f.initializer = d.Initializer;
629
630                                         Parent.PartialContainer.Fields.Insert (++index, f);
631                                 }
632                         }
633
634                         return true;
635                 }
636
637                 protected override void DoMemberTypeDependentChecks ()
638                 {
639                         if ((ModFlags & Modifiers.BACKING_FIELD) != 0)
640                                 return;
641
642                         base.DoMemberTypeDependentChecks ();
643
644                         if ((ModFlags & Modifiers.VOLATILE) != 0) {
645                                 if (!CanBeVolatile ()) {
646                                         Report.Error (677, Location, "`{0}': A volatile field cannot be of the type `{1}'",
647                                                 GetSignatureForError (), TypeManager.CSharpName (MemberType));
648                                 }
649
650                                 if ((ModFlags & Modifiers.READONLY) != 0) {
651                                         Report.Error (678, Location, "`{0}': A field cannot be both volatile and readonly",
652                                                 GetSignatureForError ());
653                                 }
654                         }
655                 }
656
657                 protected override bool VerifyClsCompliance ()
658                 {
659                         if (!base.VerifyClsCompliance ())
660                                 return false;
661
662                         if ((ModFlags & Modifiers.VOLATILE) != 0) {
663                                 Report.Warning (3026, 1, Location, "CLS-compliant field `{0}' cannot be volatile", GetSignatureForError ());
664                         }
665
666                         return true;
667                 }
668         }
669 }