1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.Diagnostics; 8 using System.Diagnostics.CodeAnalysis; 9 using System.Linq; 10 using System.Reflection; 11 using System.Runtime.CompilerServices; 12 using System.Runtime.InteropServices; 13 using Microsoft.CSharp.RuntimeBinder.Semantics; 14 using Microsoft.CSharp.RuntimeBinder.Syntax; 15 16 namespace Microsoft.CSharp.RuntimeBinder 17 { 18 internal sealed class SymbolTable 19 { 20 ///////////////////////////////////////////////////////////////////////////////// 21 // Members 22 private readonly HashSet<Type> _typesWithConversionsLoaded = new HashSet<Type>(); 23 private readonly HashSet<NameHashKey> _namesLoadedForEachType = new HashSet<NameHashKey>(); 24 25 // Members from the managed binder. 26 private readonly SYMTBL _symbolTable; 27 private readonly SymFactory _symFactory; 28 private readonly TypeManager _typeManager; 29 private readonly BSYMMGR _bsymmgr; 30 private readonly CSemanticChecker _semanticChecker; 31 32 ///////////////////////////////////////////////////////////////////////////////// 33 34 private sealed class NameHashKey : IEquatable<NameHashKey> 35 { 36 internal readonly Type type; 37 internal readonly string name; 38 NameHashKey(Type type, string name)39 public NameHashKey(Type type, string name) 40 { 41 this.type = type; 42 this.name = name; 43 } 44 45 public bool Equals(NameHashKey other) => other != null && type.Equals(other.type) && name.Equals(other.name); 46 47 #if DEBUG 48 [ExcludeFromCodeCoverage] // Typed overload should always be the method called. 49 #endif Equals(object obj)50 public override bool Equals(object obj) 51 { 52 Debug.Fail("Sub-optimal overload called. Check if this can be avoided."); 53 return Equals(obj as NameHashKey); 54 } 55 GetHashCode()56 public override int GetHashCode() 57 { 58 return type.GetHashCode() ^ name.GetHashCode(); 59 } 60 } 61 62 ///////////////////////////////////////////////////////////////////////////////// 63 SymbolTable( SYMTBL symTable, SymFactory symFactory, TypeManager typeManager, BSYMMGR bsymmgr, CSemanticChecker semanticChecker)64 internal SymbolTable( 65 SYMTBL symTable, 66 SymFactory symFactory, 67 TypeManager typeManager, 68 BSYMMGR bsymmgr, 69 CSemanticChecker semanticChecker) 70 { 71 _symbolTable = symTable; 72 _symFactory = symFactory; 73 _typeManager = typeManager; 74 _bsymmgr = bsymmgr; 75 _semanticChecker = semanticChecker; 76 77 // Now populate object. 78 LoadSymbolsFromType(typeof(object)); 79 } 80 81 ///////////////////////////////////////////////////////////////////////////////// 82 PopulateSymbolTableWithName( string name, IEnumerable<Type> typeArguments, Type callingType)83 internal void PopulateSymbolTableWithName( 84 string name, 85 IEnumerable<Type> typeArguments, 86 Type callingType) 87 { 88 // The first argument is the object that we're calling off of. 89 if (callingType.IsGenericType) 90 { 91 callingType = callingType.GetGenericTypeDefinition(); 92 } 93 94 if (name == SpecialNames.Indexer) 95 { 96 // If we don't find an indexer name for this type, use SpecialNames.Indexer as a key on the 97 // empty results we'll get, so that those empty results gets cached. 98 name = callingType.GetIndexerName() ?? SpecialNames.Indexer; 99 } 100 101 NameHashKey key = new NameHashKey(callingType, name); 102 103 // If we've already populated this name/type pair, then just leave. 104 if (_namesLoadedForEachType.Contains(key)) 105 { 106 return; 107 } 108 109 // Add the names. 110 AddNamesOnType(key); 111 112 // Take each type argument and load its conversions into the symbol table. 113 if (typeArguments != null) 114 { 115 foreach (Type o in typeArguments) 116 { 117 AddConversionsForType(o); 118 } 119 } 120 } 121 122 ///////////////////////////////////////////////////////////////////////////////// 123 LookupMember( string name, Expr callingObject, ParentSymbol context, int arity, MemberLookup mem, bool allowSpecialNames, bool requireInvocable)124 internal SymWithType LookupMember( 125 string name, 126 Expr callingObject, 127 ParentSymbol context, 128 int arity, 129 MemberLookup mem, 130 bool allowSpecialNames, 131 bool requireInvocable) 132 { 133 CType type = callingObject.Type; 134 135 if (type is ArrayType) 136 { 137 type = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_ARRAY); 138 } 139 if (type is NullableType nub) 140 { 141 type = nub.GetAts(); 142 } 143 144 if (!mem.Lookup( 145 _semanticChecker, 146 type, 147 callingObject, 148 context, 149 GetName(name), 150 arity, 151 (allowSpecialNames ? 0 : MemLookFlags.UserCallable) | 152 (name == SpecialNames.Indexer ? MemLookFlags.Indexer : 0) | 153 (name == SpecialNames.Constructor ? MemLookFlags.Ctor : 0) | 154 (requireInvocable ? MemLookFlags.MustBeInvocable : 0))) 155 { 156 return null; 157 } 158 return mem.SwtFirst(); 159 } 160 AddParameterConversions(MethodBase method)161 private void AddParameterConversions(MethodBase method) 162 { 163 foreach (ParameterInfo param in method.GetParameters()) 164 { 165 AddConversionsForType(param.ParameterType); 166 } 167 } 168 169 #region InheritanceHierarchy AddNamesOnType(NameHashKey key)170 private void AddNamesOnType(NameHashKey key) 171 { 172 Debug.Assert(!_namesLoadedForEachType.Contains(key)); 173 174 // We need to declare all of its inheritance hierarchy. 175 List<Type> inheritance = CreateInheritanceHierarchyList(key.type); 176 177 // Now add every method as it appears in the inheritance hierarchy. 178 AddNamesInInheritanceHierarchy(key.name, inheritance); 179 } 180 181 ///////////////////////////////////////////////////////////////////////////////// 182 AddNamesInInheritanceHierarchy(string name, List<Type> inheritance)183 private void AddNamesInInheritanceHierarchy(string name, List<Type> inheritance) 184 { 185 for (int i = inheritance.Count - 1; i >= 0; --i) 186 { 187 Type type = inheritance[i]; 188 if (type.IsGenericType) 189 { 190 type = type.GetGenericTypeDefinition(); 191 } 192 193 if (!_namesLoadedForEachType.Add(new NameHashKey(type, name))) 194 { 195 continue; 196 } 197 198 // Now loop over all methods and add them. 199 IEnumerator<MemberInfo> memberEn = type 200 .GetMembers( 201 BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static) 202 .Where(member => member.DeclaringType == type && member.Name == name).GetEnumerator(); 203 if (memberEn.MoveNext()) 204 { 205 List<EventInfo> events = null; 206 CType cType = GetCTypeFromType(type); 207 if (!(cType is AggregateType aggType)) 208 continue; 209 AggregateSymbol aggregate = aggType.getAggregate(); 210 FieldSymbol addedField = null; 211 212 // We need to add fields before the actual events, so do the first iteration 213 // excluding events. 214 do 215 { 216 MemberInfo member = memberEn.Current; 217 if (member is MethodInfo method) 218 { 219 MethodKindEnum kind; 220 switch (member.Name) 221 { 222 case SpecialNames.Invoke: 223 kind = MethodKindEnum.Invoke; 224 break; 225 226 case SpecialNames.ImplicitConversion: 227 kind = MethodKindEnum.ImplicitConv; 228 break; 229 230 case SpecialNames.ExplicitConversion: 231 kind = MethodKindEnum.ExplicitConv; 232 break; 233 234 default: 235 kind = MethodKindEnum.Actual; 236 break; 237 } 238 239 AddMethodToSymbolTable(method, aggregate, kind); 240 AddParameterConversions(method); 241 } 242 else if (member is ConstructorInfo ctor) 243 { 244 AddMethodToSymbolTable(ctor, aggregate, MethodKindEnum.Constructor); 245 AddParameterConversions(ctor); 246 } 247 else if (member is PropertyInfo prop) 248 { 249 AddPropertyToSymbolTable(prop, aggregate); 250 } 251 else if (member is FieldInfo field) 252 { 253 // Store this field so that if we also find an event, we can 254 // mark it as the backing field of the event. 255 Debug.Assert(addedField == null); 256 addedField = AddFieldToSymbolTable(field, aggregate); 257 } 258 else if (member is EventInfo e) 259 { 260 // Store events until after all fields 261 (events = events ?? new List<EventInfo>()).Add(e); 262 } 263 } while (memberEn.MoveNext()); 264 265 if (events != null) 266 { 267 foreach (EventInfo e in events) 268 { 269 AddEventToSymbolTable(e, aggregate, addedField); 270 } 271 } 272 } 273 } 274 } 275 276 ///////////////////////////////////////////////////////////////////////////////// 277 CreateInheritanceHierarchyList(Type type)278 private List<Type> CreateInheritanceHierarchyList(Type type) 279 { 280 List<Type> list; 281 if (type.IsInterface) 282 { 283 Type[] ifaces = type.GetInterfaces(); 284 285 // Since IsWindowsRuntimeType() is rare, this is probably the final size 286 list = new List<Type>(ifaces.Length + 2) 287 { 288 type 289 }; 290 foreach (Type iface in type.GetInterfaces()) 291 { 292 LoadSymbolsFromType(iface); 293 list.Add(iface); 294 } 295 296 Type obj = typeof(object); 297 LoadSymbolsFromType(obj); 298 list.Add(obj); 299 } 300 else 301 { 302 list = new List<Type> { type }; 303 for (Type parent = type.BaseType; parent != null; parent = parent.BaseType) 304 { 305 // Load it in the symbol table. 306 LoadSymbolsFromType(parent); 307 308 // Insert into our list of Types. 309 list.Add(parent); 310 } 311 } 312 313 // If we have a WinRT type then we should load the members of it's collection interfaces 314 // as well as those members are on this type as far as the user is concerned. 315 CType ctype = GetCTypeFromType(type); 316 if (ctype.IsWindowsRuntimeType()) 317 { 318 TypeArray collectioniFaces = ((AggregateType)ctype).GetWinRTCollectionIfacesAll(_semanticChecker.SymbolLoader); 319 320 for (int i = 0; i < collectioniFaces.Count; i++) 321 { 322 CType collectionType = collectioniFaces[i]; 323 Debug.Assert(collectionType.isInterfaceType()); 324 325 // Insert into our list of Types. 326 list.Add(collectionType.AssociatedSystemType); 327 } 328 } 329 return list; 330 } 331 #endregion 332 333 #region GetName 334 ///////////////////////////////////////////////////////////////////////////////// 335 GetName(string p)336 private Name GetName(string p) 337 { 338 return NameManager.Add(p ?? ""); 339 } 340 341 ///////////////////////////////////////////////////////////////////////////////// 342 GetName(Type type)343 private Name GetName(Type type) 344 { 345 string name = type.Name; 346 if (type.IsGenericType) 347 { 348 int idx = name.IndexOf('`'); 349 if (idx >= 0) 350 { 351 return NameManager.Add(name, idx); 352 } 353 } 354 355 return NameManager.Add(name); 356 } 357 358 #endregion 359 360 #region TypeParameters 361 ///////////////////////////////////////////////////////////////////////////////// 362 GetMethodTypeParameters(MethodInfo method, MethodSymbol parent)363 private TypeArray GetMethodTypeParameters(MethodInfo method, MethodSymbol parent) 364 { 365 if (method.IsGenericMethod) 366 { 367 Type[] genericArguments = method.GetGenericArguments(); 368 CType[] ctypes = new CType[genericArguments.Length]; 369 for (int i = 0; i < genericArguments.Length; i++) 370 { 371 Type t = genericArguments[i]; 372 ctypes[i] = LoadMethodTypeParameter(parent, t); 373 } 374 375 // After we load the type parameters, we need to resolve their bounds. 376 for (int i = 0; i < genericArguments.Length; i++) 377 { 378 Type t = genericArguments[i]; 379 ((TypeParameterType)ctypes[i]).GetTypeParameterSymbol().SetBounds( 380 _bsymmgr.AllocParams( 381 GetCTypeArrayFromTypes(t.GetGenericParameterConstraints()))); 382 } 383 return _bsymmgr.AllocParams(ctypes.Length, ctypes); 384 } 385 return BSYMMGR.EmptyTypeArray(); 386 } 387 388 ///////////////////////////////////////////////////////////////////////////////// 389 GetAggregateTypeParameters(Type type, AggregateSymbol agg)390 private TypeArray GetAggregateTypeParameters(Type type, AggregateSymbol agg) 391 { 392 if (type.IsGenericType) 393 { 394 Type genericDefinition = type.GetGenericTypeDefinition(); 395 Type[] genericArguments = genericDefinition.GetGenericArguments(); 396 List<CType> ctypes = new List<CType>(); 397 int outerParameters = agg.isNested() ? agg.GetOuterAgg().GetTypeVarsAll().Count : 0; 398 399 for (int i = 0; i < genericArguments.Length; i++) 400 { 401 // Suppose we have the following: 402 // 403 // class A<A1, A2, ..., An> 404 // { 405 // class B<B1, B2, ..., Bm> 406 // { 407 // } 408 // } 409 // 410 // B will have m+n generic arguments - { A1, A2, ..., An, B1, B2, ..., Bn }. 411 // As we enumerate these, we need to skip type parameters whose GenericParameterPosition 412 // is less than n, since the first n type parameters are { A1, A2, ..., An }. 413 414 Type t = genericArguments[i]; 415 416 if (t.GenericParameterPosition < outerParameters) 417 { 418 continue; 419 } 420 421 CType ctype; 422 if (t.IsGenericParameter && t.DeclaringType == genericDefinition) 423 { 424 ctype = LoadClassTypeParameter(agg, t); 425 } 426 else 427 { 428 ctype = GetCTypeFromType(t); 429 } 430 431 // We check to make sure we own the type parameter - this is because we're 432 // currently calculating TypeArgsThis, NOT TypeArgsAll. 433 if (((TypeParameterType)ctype).GetOwningSymbol() == agg) 434 { 435 ctypes.Add(ctype); 436 } 437 } 438 return _bsymmgr.AllocParams(ctypes.Count, ctypes.ToArray()); 439 } 440 return BSYMMGR.EmptyTypeArray(); 441 } 442 443 ///////////////////////////////////////////////////////////////////////////////// 444 LoadClassTypeParameter(AggregateSymbol parent, Type t)445 private TypeParameterType LoadClassTypeParameter(AggregateSymbol parent, Type t) 446 { 447 for (AggregateSymbol p = parent; p != null; p = p.parent as AggregateSymbol) 448 { 449 for (TypeParameterSymbol typeParam = _bsymmgr.LookupAggMember( 450 GetName(t), p, symbmask_t.MASK_TypeParameterSymbol) as TypeParameterSymbol; 451 typeParam != null; 452 typeParam = BSYMMGR.LookupNextSym(typeParam, p, symbmask_t.MASK_TypeParameterSymbol) as TypeParameterSymbol) 453 { 454 if (AreTypeParametersEquivalent(typeParam.GetTypeParameterType().AssociatedSystemType, t)) 455 { 456 return typeParam.GetTypeParameterType(); 457 } 458 } 459 } 460 return AddTypeParameterToSymbolTable(parent, null, t, true); 461 } 462 463 ///////////////////////////////////////////////////////////////////////////////// 464 AreTypeParametersEquivalent(Type t1, Type t2)465 private bool AreTypeParametersEquivalent(Type t1, Type t2) 466 { 467 Debug.Assert(t1.IsGenericParameter && t2.IsGenericParameter); 468 469 if (t1 == t2) 470 { 471 return true; 472 } 473 474 Type t1Original = GetOriginalTypeParameterType(t1); 475 Type t2Original = GetOriginalTypeParameterType(t2); 476 477 return t1Original == t2Original; 478 } 479 480 ///////////////////////////////////////////////////////////////////////////////// 481 482 // GetOriginalTypeParameterType 483 // This was added so that LoadClassTypeParameter would not fail to find outer 484 // type parameters when given a System.Type from an outer class and a matching 485 // type parameter from in an inner class. In Reflection type parameters are 486 // always declared by their inner most declaring class. For example, given: 487 // 488 // class A<T> { 489 // class B<U> { } 490 // } 491 // 492 // in Reflection there are two Ts, A<T>'s T, and B<U>'s T. In our world there is 493 // only A<T>'s T. 494 // 495 // So this method here drills down and finds the type parameter type corresponding 496 // to the position of the given type parameter, from the outer most containing 497 // type. So in the above example, given B<U>'s T from reflection, this will return 498 // A<T>'s T, so that you can make a reference comparison of type parameters coming 499 // from different nesting levels. 500 // 501 // There is an exception, we don't handle the case where you have type parameters 502 // coming from different partially constructed methods. E.g. 503 // 504 // class A<T,S> { 505 // public void M<U> { } 506 // } 507 // 508 // A<T,int>.M<U> 509 // A<T,string>.M<U> 510 // 511 // In the above two methods, the two U's are different in Reflection. Here we just 512 // return the type parameter type given if it is in a method, we do not try to 513 // generalize these occurrences for reference equality. 514 // GetOriginalTypeParameterType(Type t)515 private Type GetOriginalTypeParameterType(Type t) 516 { 517 Debug.Assert(t.IsGenericParameter); 518 519 int pos = t.GenericParameterPosition; 520 521 Type parentType = t.DeclaringType; 522 if (parentType != null && parentType.IsGenericType) 523 { 524 parentType = parentType.GetGenericTypeDefinition(); 525 } 526 527 if (t.DeclaringMethod != null) 528 { 529 if (parentType.GetGenericArguments() == null || pos >= parentType.GetGenericArguments().Length) 530 { 531 return t; 532 } 533 } 534 535 while (parentType.GetGenericArguments().Length > pos) 536 { 537 Type nextParent = parentType.DeclaringType; 538 if (nextParent != null && nextParent.IsGenericType) 539 { 540 nextParent = nextParent.GetGenericTypeDefinition(); 541 } 542 543 if (nextParent?.GetGenericArguments()?.Length > pos) 544 { 545 parentType = nextParent; 546 } 547 else 548 { 549 break; 550 } 551 } 552 553 return parentType.GetGenericArguments()[pos]; 554 } 555 556 ///////////////////////////////////////////////////////////////////////////////// 557 LoadMethodTypeParameter(MethodSymbol parent, Type t)558 private TypeParameterType LoadMethodTypeParameter(MethodSymbol parent, Type t) 559 { 560 for (Symbol sym = parent.firstChild; sym != null; sym = sym.nextChild) 561 { 562 if (!(sym is TypeParameterSymbol parSym)) 563 { 564 continue; 565 } 566 567 TypeParameterType type = parSym.GetTypeParameterType(); 568 if (AreTypeParametersEquivalent(type.AssociatedSystemType, t)) 569 { 570 return type; 571 } 572 } 573 574 return AddTypeParameterToSymbolTable(null, parent, t, false); 575 } 576 577 ///////////////////////////////////////////////////////////////////////////////// 578 AddTypeParameterToSymbolTable( AggregateSymbol agg, MethodSymbol meth, Type t, bool bIsAggregate)579 private TypeParameterType AddTypeParameterToSymbolTable( 580 AggregateSymbol agg, 581 MethodSymbol meth, 582 Type t, 583 bool bIsAggregate) 584 { 585 Debug.Assert((agg != null && bIsAggregate) || (meth != null && !bIsAggregate)); 586 587 TypeParameterSymbol typeParam; 588 if (bIsAggregate) 589 { 590 typeParam = _symFactory.CreateClassTypeParameter( 591 GetName(t), 592 agg, 593 t.GenericParameterPosition, 594 t.GenericParameterPosition); 595 } 596 else 597 { 598 typeParam = _symFactory.CreateMethodTypeParameter( 599 GetName(t), 600 meth, 601 t.GenericParameterPosition, 602 t.GenericParameterPosition); 603 } 604 605 if ((t.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0) 606 { 607 typeParam.Covariant = true; 608 } 609 if ((t.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0) 610 { 611 typeParam.Contravariant = true; 612 } 613 614 SpecCons cons = SpecCons.None; 615 616 if ((t.GenericParameterAttributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0) 617 { 618 cons |= SpecCons.New; 619 } 620 if ((t.GenericParameterAttributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0) 621 { 622 cons |= SpecCons.Ref; 623 } 624 if ((t.GenericParameterAttributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) 625 { 626 cons |= SpecCons.Val; 627 } 628 629 typeParam.SetConstraints(cons); 630 typeParam.SetAccess(ACCESS.ACC_PUBLIC); 631 TypeParameterType typeParamType = _typeManager.GetTypeParameter(typeParam); 632 633 return typeParamType; 634 } 635 636 #endregion 637 638 #region LoadTypeChain 639 ///////////////////////////////////////////////////////////////////////////////// 640 LoadSymbolsFromType(Type type)641 private CType LoadSymbolsFromType(Type type) 642 { 643 List<object> declarationChain = BuildDeclarationChain(type); 644 645 NamespaceOrAggregateSymbol current = NamespaceSymbol.Root; 646 647 // Go through the declaration chain and add namespaces and types for 648 // each element in the chain. 649 for (int i = 0; i < declarationChain.Count; i++) 650 { 651 object o = declarationChain[i]; 652 if (o is Type t) 653 { 654 if (t.IsNullableType()) 655 { 656 return _typeManager.GetNullable(GetCTypeFromType(t.GetGenericArguments()[0])); 657 } 658 659 AggregateSymbol next = FindSymForType( 660 _symbolTable.LookupSym(GetName(t), current, symbmask_t.MASK_AggregateSymbol), t); 661 662 // If we haven't found this type yet, then add it to our symbol table. 663 if (next == null) 664 { 665 // Note that if we have anything other than an AggregateSymbol, 666 // we must be at the end of the line - that is, nothing else can 667 // have children. 668 CType ctype = ProcessSpecialTypeInChain(current, t); 669 if (ctype != null) 670 { 671 Debug.Assert(!(ctype is AggregateType)); 672 return ctype; 673 } 674 675 // This is a regular class. 676 next = AddAggregateToSymbolTable(current, t); 677 } 678 679 if (t == type) 680 { 681 return GetConstructedType(type, next); 682 } 683 684 current = next; 685 } 686 else if (o is MethodInfo m) 687 { 688 // We cant be at the end. 689 Debug.Assert(i + 1 < declarationChain.Count); 690 return ProcessMethodTypeParameter(m, declarationChain[++i] as Type, current as AggregateSymbol); 691 } 692 else 693 { 694 Debug.Assert(o is string); 695 current = AddNamespaceToSymbolTable(current, o as string); 696 } 697 } 698 699 Debug.Fail("Should be unreachable"); 700 return null; 701 } 702 703 ///////////////////////////////////////////////////////////////////////////////// 704 ProcessMethodTypeParameter(MethodInfo methinfo, Type t, AggregateSymbol parent)705 private TypeParameterType ProcessMethodTypeParameter(MethodInfo methinfo, Type t, AggregateSymbol parent) 706 { 707 MethodSymbol meth = FindMatchingMethod(methinfo, parent); 708 if (meth == null) 709 { 710 meth = AddMethodToSymbolTable(methinfo, parent, MethodKindEnum.Actual); 711 712 // Because we return null from AddMethodToSymbolTable when we have a MethodKindEnum.Actual 713 // and the method that we're trying to add is a special name, we need to assert that 714 // we indeed have added a method. This is because no special name should have a method 715 // type parameter on it. 716 Debug.Assert(meth != null); 717 } 718 return LoadMethodTypeParameter(meth, t); 719 } 720 721 ///////////////////////////////////////////////////////////////////////////////// 722 GetConstructedType(Type type, AggregateSymbol agg)723 private CType GetConstructedType(Type type, AggregateSymbol agg) 724 { 725 // We've found the one we want, so return it. 726 if (type.IsGenericType) 727 { 728 // If we're a generic type, then we need to add the type arguments. 729 List<CType> types = new List<CType>(); 730 731 foreach (Type argument in type.GetGenericArguments()) 732 { 733 types.Add(GetCTypeFromType(argument)); 734 } 735 736 TypeArray typeArray = _bsymmgr.AllocParams(types.ToArray()); 737 AggregateType aggType = _typeManager.GetAggregate(agg, typeArray); 738 return aggType; 739 } 740 CType ctype = agg.getThisType(); 741 return ctype; 742 } 743 744 ///////////////////////////////////////////////////////////////////////////////// 745 ProcessSpecialTypeInChain(NamespaceOrAggregateSymbol parent, Type t)746 private CType ProcessSpecialTypeInChain(NamespaceOrAggregateSymbol parent, Type t) 747 { 748 if (t.IsGenericParameter) 749 { 750 AggregateSymbol agg = parent as AggregateSymbol; 751 Debug.Assert(agg != null); 752 return LoadClassTypeParameter(agg, t); 753 } 754 755 if (t.IsArray) 756 { 757 // Now we return an array of nesting level corresponding to the rank. 758 return _typeManager.GetArray( 759 GetCTypeFromType(t.GetElementType()), 760 t.GetArrayRank(), 761 #if netcoreapp 762 t.IsSZArray 763 #else 764 t.GetElementType().MakeArrayType() == t 765 #endif 766 ); 767 } 768 769 if (t.IsPointer) 770 { 771 // Now we return the pointer type that we want. 772 return _typeManager.GetPointer(GetCTypeFromType(t.GetElementType())); 773 } 774 775 return null; 776 } 777 778 ///////////////////////////////////////////////////////////////////////////////// 779 BuildDeclarationChain(Type callingType)780 private static List<object> BuildDeclarationChain(Type callingType) 781 { 782 // We need to build the parent chain of the calling type. Since we only 783 // have the type itself, first we need to build the chain up from the 784 // type down to the root namespace, then we need to ensure that 785 // the chain exists in our symbol table by searching from the root namespace 786 // back down to the calling type. Also note that if we have a method type 787 // parameter, then we'll also add the MethodBase to the chain. 788 // 789 // Note that we'll populate this list in a hybrid way - we'll add the 790 // types for the type part of the chain, and we'll just add the string names 791 // of the namespaces. 792 793 // Strip off the ref-ness. 794 if (callingType.IsByRef) 795 { 796 callingType = callingType.GetElementType(); 797 } 798 799 List<object> callChain = new List<object>(); 800 for (Type t = callingType; t != null; t = t.DeclaringType) 801 { 802 callChain.Add(t); 803 804 if (t.IsGenericParameter && t.DeclaringMethod != null) 805 { 806 MethodBase methodBase = t.DeclaringMethod; 807 bool bAdded = false; 808 #if UNSUPPORTEDAPI 809 foreach (MethodInfo methinfo in Enumerable.Where(t.DeclaringType.GetRuntimeMethods(), m => m.MetadataToken == methodBase.MetadataToken)) 810 #else 811 foreach (MethodInfo methinfo in Enumerable.Where(t.DeclaringType.GetRuntimeMethods(), m => m.HasSameMetadataDefinitionAs(methodBase))) 812 #endif 813 { 814 if (!methinfo.IsGenericMethod) 815 { 816 continue; 817 } 818 819 Debug.Assert(!bAdded); 820 callChain.Add(methinfo); 821 bAdded = true; 822 } 823 Debug.Assert(bAdded); 824 } 825 } 826 827 callChain.Reverse(); 828 829 // Now take out the namespaces and add them to the end of the chain. 830 if (callingType.Namespace != null) 831 { 832 callChain.InsertRange(0, callingType.Namespace.Split('.')); 833 } 834 return callChain; 835 } 836 837 // We have an aggregate symbol of the correct parent and full name, but it may have the wrong arity, or, due to 838 // dynamic loading or creation, two different types can exist that have the same name. 839 840 // In the static compiler, this would have been an error and name lookup would be ambiguous, but here we never have 841 // to lookup names of types for real (only names of members). 842 843 // For either case, move onto the next symbol in the chain, and check again for appropriate type. FindSymForType(Symbol sym, Type t)844 private AggregateSymbol FindSymForType(Symbol sym, Type t) 845 { 846 while (sym != null) 847 { 848 // We use "IsEquivalentTo" so that unified local types match. 849 if (sym is AggregateSymbol agg) 850 if (agg.AssociatedSystemType.IsEquivalentTo(t.IsGenericType ? t.GetGenericTypeDefinition() : t)) 851 { 852 return agg; 853 } 854 855 sym = sym.nextSameName; 856 } 857 858 return null; 859 } 860 AddNamespaceToSymbolTable(NamespaceOrAggregateSymbol parent, string sz)861 private NamespaceSymbol AddNamespaceToSymbolTable(NamespaceOrAggregateSymbol parent, string sz) 862 { 863 Name name = GetName(sz); 864 return _symbolTable.LookupSym(name, parent, symbmask_t.MASK_NamespaceSymbol) as NamespaceSymbol 865 ?? _symFactory.CreateNamespace(name, parent as NamespaceSymbol); 866 } 867 #endregion 868 869 #region CTypeFromType 870 ///////////////////////////////////////////////////////////////////////////////// 871 GetCTypeArrayFromTypes(Type[] types)872 internal CType[] GetCTypeArrayFromTypes(Type[] types) 873 { 874 Debug.Assert(types != null); 875 876 int length = types.Length; 877 if (length == 0) 878 { 879 return Array.Empty<CType>(); 880 } 881 882 CType[] ctypes = new CType[length]; 883 for (int i = 0; i < types.Length; i++) 884 { 885 Type t = types[i]; 886 Debug.Assert(t != null); 887 ctypes[i] = GetCTypeFromType(t); 888 } 889 890 return ctypes; 891 } 892 893 ///////////////////////////////////////////////////////////////////////////////// 894 895 internal CType GetCTypeFromType(Type type) => type.IsByRef 896 ? _typeManager.GetParameterModifier(LoadSymbolsFromType(type.GetElementType()), false) 897 : LoadSymbolsFromType(type); 898 899 #endregion 900 901 #region Aggregates 902 ///////////////////////////////////////////////////////////////////////////////// 903 AddAggregateToSymbolTable( NamespaceOrAggregateSymbol parent, Type type)904 private AggregateSymbol AddAggregateToSymbolTable( 905 NamespaceOrAggregateSymbol parent, 906 Type type) 907 { 908 AggregateSymbol agg = _symFactory.CreateAggregate(GetName(type), parent, _typeManager); 909 agg.AssociatedSystemType = type.IsGenericType ? type.GetGenericTypeDefinition() : type; 910 agg.AssociatedAssembly = type.Assembly; 911 912 // We have to set the TypeVars, access, and the AggKind before we can set the aggState 913 // because of the assertion checking the compiler does. 914 AggKindEnum kind; 915 if (type.IsInterface) 916 { 917 kind = AggKindEnum.Interface; 918 } 919 else if (type.IsEnum) 920 { 921 kind = AggKindEnum.Enum; 922 agg.SetUnderlyingType((AggregateType)GetCTypeFromType(Enum.GetUnderlyingType(type))); 923 } 924 else if (type.IsValueType) 925 { 926 kind = AggKindEnum.Struct; 927 } 928 else 929 { 930 // If it derives from Delegate or MulticastDelegate, then its 931 // a delegate type. However, MuticastDelegate itself is not a 932 // delegate type. 933 if (type.BaseType != null && 934 (type.BaseType.FullName == "System.MulticastDelegate" || 935 type.BaseType.FullName == "System.Delegate") && 936 type.FullName != "System.MulticastDelegate") 937 { 938 kind = AggKindEnum.Delegate; 939 } 940 else 941 { 942 kind = AggKindEnum.Class; 943 } 944 } 945 agg.SetAggKind(kind); 946 agg.SetTypeVars(BSYMMGR.EmptyTypeArray()); 947 948 ACCESS access; 949 if (type.IsPublic) 950 { 951 access = ACCESS.ACC_PUBLIC; 952 } 953 else if (type.IsNested) 954 { 955 // If its nested, we may have other accessibility options. 956 if (type.IsNestedAssembly) 957 { 958 access = ACCESS.ACC_INTERNAL; 959 } 960 else if (type.IsNestedFamORAssem) 961 { 962 access = ACCESS.ACC_INTERNALPROTECTED; 963 } 964 else if (type.IsNestedPrivate) 965 { 966 access = ACCESS.ACC_PRIVATE; 967 } 968 else if (type.IsNestedFamily) 969 { 970 access = ACCESS.ACC_PROTECTED; 971 } 972 else if (type.IsNestedFamANDAssem) 973 { 974 access = ACCESS.ACC_INTERNAL_AND_PROTECTED; 975 } 976 else 977 { 978 Debug.Assert(type.IsPublic || type.IsNestedPublic); 979 access = ACCESS.ACC_PUBLIC; 980 } 981 } 982 else 983 { 984 // We're not public and we're not nested - we must be internal. 985 access = ACCESS.ACC_INTERNAL; 986 } 987 agg.SetAccess(access); 988 989 if (!type.IsGenericParameter) 990 { 991 agg.SetTypeVars(GetAggregateTypeParameters(type, agg)); 992 } 993 994 if (type.IsGenericType) 995 { 996 Type genericDefinition = type.GetGenericTypeDefinition(); 997 Type[] genericArguments = genericDefinition.GetGenericArguments(); 998 999 // After we load the type parameters, we need to resolve their bounds. 1000 for (int i = 0; i < agg.GetTypeVars().Count; i++) 1001 { 1002 Type t = genericArguments[i]; 1003 if (agg.GetTypeVars()[i] is TypeParameterType typeVar) 1004 { 1005 typeVar.GetTypeParameterSymbol().SetBounds( 1006 _bsymmgr.AllocParams( 1007 GetCTypeArrayFromTypes(t.GetGenericParameterConstraints()))); 1008 } 1009 } 1010 } 1011 1012 agg.SetAbstract(type.IsAbstract); 1013 1014 { 1015 string typeName = type.FullName; 1016 if (type.IsGenericType) 1017 { 1018 typeName = type.GetGenericTypeDefinition().FullName; 1019 } 1020 if (typeName != null) 1021 { 1022 PredefinedType predefinedType = PredefinedTypeFacts.TryGetPredefTypeIndex(typeName); 1023 if (predefinedType != PredefinedType.PT_UNDEFINEDINDEX) 1024 { 1025 PredefinedTypes.InitializePredefinedType(agg, predefinedType); 1026 } 1027 } 1028 } 1029 1030 agg.SetSealed(type.IsSealed); 1031 if (type.BaseType != null) 1032 { 1033 // type.BaseType can be null for Object or for interface types. 1034 Type t = type.BaseType; 1035 if (t.IsGenericType) 1036 { 1037 t = t.GetGenericTypeDefinition(); 1038 } 1039 agg.SetBaseClass((AggregateType)GetCTypeFromType(t)); 1040 } 1041 agg.SetTypeManager(_typeManager); 1042 agg.SetFirstUDConversion(null); 1043 SetInterfacesOnAggregate(agg, type); 1044 agg.SetHasPubNoArgCtor(type.GetConstructor(Type.EmptyTypes) != null); 1045 1046 // If we have a delegate, get its invoke and constructor methods as well. 1047 if (agg.IsDelegate()) 1048 { 1049 PopulateSymbolTableWithName(SpecialNames.Constructor, null, type); 1050 PopulateSymbolTableWithName(SpecialNames.Invoke, null, type); 1051 } 1052 1053 return agg; 1054 } 1055 1056 ///////////////////////////////////////////////////////////////////////////////// 1057 SetInterfacesOnAggregate(AggregateSymbol aggregate, Type type)1058 private void SetInterfacesOnAggregate(AggregateSymbol aggregate, Type type) 1059 { 1060 if (type.IsGenericType) 1061 { 1062 type = type.GetGenericTypeDefinition(); 1063 } 1064 Type[] interfaces = type.GetInterfaces(); 1065 1066 // We won't be able to find the difference between Ifaces and 1067 // IfacesAll anymore - at runtime, the class implements all of its 1068 // Ifaces and IfacesAll, so theres no way to differentiate. 1069 // 1070 // This actually doesn't matter though - for conversions and methodcalls, 1071 // we don't really care where they've come from as long as we know the overall 1072 // set of IfacesAll. 1073 1074 aggregate.SetIfaces(_bsymmgr.AllocParams(interfaces.Length, GetCTypeArrayFromTypes(interfaces))); 1075 aggregate.SetIfacesAll(aggregate.GetIfaces()); 1076 } 1077 #endregion 1078 1079 #region Field 1080 ///////////////////////////////////////////////////////////////////////////////// 1081 AddFieldToSymbolTable(FieldInfo fieldInfo, AggregateSymbol aggregate)1082 private FieldSymbol AddFieldToSymbolTable(FieldInfo fieldInfo, AggregateSymbol aggregate) 1083 { 1084 FieldSymbol field = _symbolTable.LookupSym( 1085 GetName(fieldInfo.Name), 1086 aggregate, 1087 symbmask_t.MASK_FieldSymbol) as FieldSymbol; 1088 if (field != null) 1089 { 1090 return field; 1091 } 1092 1093 field = _symFactory.CreateMemberVar(GetName(fieldInfo.Name), aggregate); 1094 field.AssociatedFieldInfo = fieldInfo; 1095 1096 field.isStatic = fieldInfo.IsStatic; 1097 ACCESS access; 1098 if (fieldInfo.IsPublic) 1099 { 1100 access = ACCESS.ACC_PUBLIC; 1101 } 1102 else if (fieldInfo.IsPrivate) 1103 { 1104 access = ACCESS.ACC_PRIVATE; 1105 } 1106 else if (fieldInfo.IsFamily) 1107 { 1108 access = ACCESS.ACC_PROTECTED; 1109 } 1110 else if (fieldInfo.IsAssembly) 1111 { 1112 access = ACCESS.ACC_INTERNAL; 1113 } 1114 else if (fieldInfo.IsFamilyOrAssembly) 1115 { 1116 access = ACCESS.ACC_INTERNALPROTECTED; 1117 } 1118 else 1119 { 1120 Debug.Assert(fieldInfo.IsFamilyAndAssembly); 1121 access = ACCESS.ACC_INTERNAL_AND_PROTECTED; 1122 } 1123 field.SetAccess(access); 1124 field.isReadOnly = fieldInfo.IsInitOnly; 1125 field.isEvent = false; 1126 field.isAssigned = true; 1127 field.SetType(GetCTypeFromType(fieldInfo.FieldType)); 1128 1129 return field; 1130 } 1131 #endregion 1132 1133 #region Events 1134 1135 ///////////////////////////////////////////////////////////////////////////////// 1136 1137 private static readonly Type s_Sentinel = typeof(SymbolTable); 1138 private static Type s_EventRegistrationTokenType = s_Sentinel; 1139 private static Type s_WindowsRuntimeMarshal = s_Sentinel; 1140 private static Type s_EventRegistrationTokenTable = s_Sentinel; 1141 1142 internal static Type EventRegistrationTokenType 1143 { 1144 get 1145 { 1146 return GetTypeByName(ref s_EventRegistrationTokenType, "System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken, System.Runtime.InteropServices.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); 1147 } 1148 } 1149 1150 internal static Type WindowsRuntimeMarshalType 1151 { 1152 get 1153 { 1154 return GetTypeByName(ref s_WindowsRuntimeMarshal, "System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal, System.Runtime.InteropServices.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); 1155 } 1156 } 1157 1158 private static Type EventRegistrationTokenTableType 1159 { 1160 get 1161 { 1162 return GetTypeByName(ref s_EventRegistrationTokenTable, "System.Runtime.InteropServices.WindowsRuntime.EventRegistrationTokenTable`1, System.Runtime.InteropServices.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); 1163 } 1164 } 1165 GetTypeByName(ref Type cachedResult, string name)1166 private static Type GetTypeByName(ref Type cachedResult, string name) 1167 { 1168 if ((object)cachedResult == s_Sentinel) 1169 { 1170 System.Threading.Interlocked.CompareExchange(ref cachedResult, Type.GetType(name, throwOnError: false), s_Sentinel); 1171 } 1172 1173 return cachedResult; 1174 } 1175 AddEventToSymbolTable(EventInfo eventInfo, AggregateSymbol aggregate, FieldSymbol addedField)1176 private void AddEventToSymbolTable(EventInfo eventInfo, AggregateSymbol aggregate, FieldSymbol addedField) 1177 { 1178 EventSymbol ev = _symbolTable.LookupSym( 1179 GetName(eventInfo.Name), 1180 aggregate, 1181 symbmask_t.MASK_EventSymbol) as EventSymbol; 1182 if (ev != null) 1183 { 1184 Debug.Assert(ev.AssociatedEventInfo == eventInfo); 1185 return; 1186 } 1187 1188 ev = _symFactory.CreateEvent(GetName(eventInfo.Name), aggregate); 1189 ev.AssociatedEventInfo = eventInfo; 1190 1191 // EventSymbol 1192 ACCESS access = ACCESS.ACC_PRIVATE; 1193 if (eventInfo.AddMethod != null) 1194 { 1195 ev.methAdd = AddMethodToSymbolTable(eventInfo.AddMethod, aggregate, MethodKindEnum.EventAccessor); 1196 ev.methAdd.SetEvent(ev); 1197 ev.isOverride = ev.methAdd.IsOverride(); 1198 1199 access = ev.methAdd.GetAccess(); 1200 } 1201 if (eventInfo.RemoveMethod != null) 1202 { 1203 ev.methRemove = AddMethodToSymbolTable(eventInfo.RemoveMethod, aggregate, MethodKindEnum.EventAccessor); 1204 ev.methRemove.SetEvent(ev); 1205 ev.isOverride = ev.methRemove.IsOverride(); 1206 1207 access = ev.methRemove.GetAccess(); 1208 } 1209 Debug.Assert(ev.methAdd != null || ev.methRemove != null); 1210 ev.isStatic = false; 1211 ev.type = GetCTypeFromType(eventInfo.EventHandlerType); 1212 1213 // Symbol 1214 ev.SetAccess(access); 1215 1216 Type eventRegistrationTokenType = EventRegistrationTokenType; 1217 if ((object)eventRegistrationTokenType != null && (object)WindowsRuntimeMarshalType != null && 1218 ev.methAdd.RetType.AssociatedSystemType == eventRegistrationTokenType && 1219 ev.methRemove.Params[0].AssociatedSystemType == eventRegistrationTokenType) 1220 { 1221 ev.IsWindowsRuntimeEvent = true; 1222 } 1223 1224 // If we imported a field on the same aggregate, with the same name, and it also 1225 // has the same type, then that field is the backing field for this event, and 1226 // we mark it as such. This is used for the CSharpIsEventBinder. 1227 // In the case of a WindowsRuntime event, the field will be of type 1228 // EventRegistrationTokenTable<delegateType>. 1229 CType addedFieldType = addedField?.GetType(); 1230 if (addedFieldType != null) 1231 { 1232 if (addedFieldType == ev.type) 1233 { 1234 addedField.isEvent = true; 1235 } 1236 else 1237 { 1238 Type associated = addedFieldType.AssociatedSystemType; 1239 if (associated.IsConstructedGenericType 1240 && associated.GetGenericTypeDefinition() == EventRegistrationTokenTableType 1241 && associated.GenericTypeArguments[0] == ev.type.AssociatedSystemType) 1242 { 1243 addedField.isEvent = true; 1244 } 1245 } 1246 } 1247 } 1248 #endregion 1249 1250 #region Properties 1251 ///////////////////////////////////////////////////////////////////////////////// 1252 AddPredefinedPropertyToSymbolTable(AggregateSymbol type, Name property)1253 internal void AddPredefinedPropertyToSymbolTable(AggregateSymbol type, Name property) 1254 { 1255 AggregateType aggtype = type.getThisType(); 1256 Type t = aggtype.AssociatedSystemType; 1257 1258 var props = Enumerable.Where(t.GetRuntimeProperties(), x => x.Name == property.Text); 1259 1260 foreach (PropertyInfo pi in props) 1261 { 1262 AddPropertyToSymbolTable(pi, type); 1263 } 1264 } 1265 1266 ///////////////////////////////////////////////////////////////////////////////// 1267 AddPropertyToSymbolTable(PropertyInfo property, AggregateSymbol aggregate)1268 private void AddPropertyToSymbolTable(PropertyInfo property, AggregateSymbol aggregate) 1269 { 1270 Name name; 1271 bool isIndexer = property.GetIndexParameters().Length != 0 1272 && property.DeclaringType?.GetCustomAttribute<DefaultMemberAttribute>() 1273 ?.MemberName == property.Name; 1274 1275 if (isIndexer) 1276 { 1277 name = GetName(SpecialNames.Indexer); 1278 } 1279 else 1280 { 1281 name = GetName(property.Name); 1282 } 1283 PropertySymbol prop = _symbolTable.LookupSym( 1284 name, 1285 aggregate, 1286 symbmask_t.MASK_PropertySymbol) as PropertySymbol; 1287 1288 // If we already had one, see if it matches. 1289 if (prop != null) 1290 { 1291 PropertySymbol prevProp = null; 1292 1293 // We'll have multiple properties with the same name if we have indexers. 1294 // In that case, we need to look at every indexer to see if we find one with 1295 // the matching associated sym that we want. 1296 while (prop != null) 1297 { 1298 if (prop.AssociatedPropertyInfo.IsEquivalentTo(property)) 1299 { 1300 return; 1301 } 1302 1303 prevProp = prop; 1304 prop = SymbolLoader.LookupNextSym(prop, prop.parent, symbmask_t.MASK_PropertySymbol) as PropertySymbol; 1305 } 1306 1307 prop = prevProp; 1308 if (isIndexer) 1309 { 1310 // We have an indexer for a different property info, so 1311 // create a new symbol for it. 1312 prop = null; 1313 } 1314 } 1315 1316 // If we already had a property but its associated info doesn't match, 1317 // then we repurpose the property that we've found. This can happen 1318 // in the case of generic instantiations. 1319 // 1320 // Note that this is a bit of a hack - the best way to fix this is 1321 // by not depending on the instantiated properties at all, but rather depending 1322 // on their non-instantiated generic form, which can be gotten from the 1323 // parent's generic type definition's member. From there, we'll also need to 1324 // keep track of the instantiation as we move along, so that when we need the 1325 // associated property, we can instantiate it correctly. 1326 // 1327 // This seems far too heavyweight - since we know we will never bind to more 1328 // than one property per payload, lets just blast it each time. 1329 if (prop == null) 1330 { 1331 if (isIndexer) 1332 { 1333 prop = _semanticChecker.SymbolLoader.GetGlobalSymbolFactory().CreateIndexer(name, aggregate, GetName(property.Name)); 1334 prop.Params = CreateParameterArray(null, property.GetIndexParameters()); 1335 } 1336 else 1337 { 1338 prop = _symFactory.CreateProperty(GetName(property.Name), aggregate); 1339 prop.Params = BSYMMGR.EmptyTypeArray(); 1340 } 1341 } 1342 prop.AssociatedPropertyInfo = property; 1343 1344 prop.isStatic = property.GetGetMethod(true) != null ? property.GetGetMethod(true).IsStatic : property.GetSetMethod(true).IsStatic; 1345 prop.isParamArray = DoesMethodHaveParameterArray(property.GetIndexParameters()); 1346 prop.swtSlot = null; 1347 prop.RetType = GetCTypeFromType(property.PropertyType); 1348 prop.isOperator = isIndexer; 1349 1350 // Determine if its an override. We should always have an accessor, unless 1351 // the metadata was bogus. 1352 if (property.GetMethod != null || property.SetMethod != null) 1353 { 1354 MethodInfo accessor = property.GetMethod ?? property.SetMethod; // Must have at least one. 1355 prop.isOverride = accessor.IsVirtual && accessor.IsHideBySig && accessor.GetRuntimeBaseDefinition() != accessor; 1356 prop.isHideByName = !accessor.IsHideBySig; 1357 } 1358 1359 SetParameterDataForMethProp(prop, property.GetIndexParameters()); 1360 1361 // Get and set. 1362 MethodInfo methGet = property.GetMethod; 1363 MethodInfo methSet = property.SetMethod; 1364 ACCESS access = ACCESS.ACC_PRIVATE; 1365 if (methGet != null) 1366 { 1367 prop.GetterMethod = AddMethodToSymbolTable(methGet, aggregate, MethodKindEnum.PropAccessor); 1368 1369 // If we have an indexed property, leave the method as a method we can call, 1370 // and mark the property as bogus. 1371 if (isIndexer || prop.GetterMethod.Params.Count == 0) 1372 { 1373 prop.GetterMethod.SetProperty(prop); 1374 } 1375 else 1376 { 1377 prop.Bogus = true; 1378 prop.GetterMethod.SetMethKind(MethodKindEnum.Actual); 1379 } 1380 1381 if (prop.GetterMethod.GetAccess() > access) 1382 { 1383 access = prop.GetterMethod.GetAccess(); 1384 } 1385 } 1386 if (methSet != null) 1387 { 1388 prop.SetterMethod = AddMethodToSymbolTable(methSet, aggregate, MethodKindEnum.PropAccessor); 1389 1390 // If we have an indexed property, leave the method as a method we can call, 1391 // and mark the property as bogus. 1392 if (isIndexer || prop.SetterMethod.Params.Count == 1) 1393 { 1394 prop.SetterMethod.SetProperty(prop); 1395 } 1396 else 1397 { 1398 prop.Bogus = true; 1399 prop.SetterMethod.SetMethKind(MethodKindEnum.Actual); 1400 } 1401 1402 if (prop.SetterMethod.GetAccess() > access) 1403 { 1404 access = prop.SetterMethod.GetAccess(); 1405 } 1406 } 1407 1408 // The access of the property is the least restrictive access of its getter/setter. 1409 prop.SetAccess(access); 1410 } 1411 1412 #endregion 1413 1414 #region Methods 1415 ///////////////////////////////////////////////////////////////////////////////// 1416 AddPredefinedMethodToSymbolTable(AggregateSymbol type, Name methodName)1417 internal void AddPredefinedMethodToSymbolTable(AggregateSymbol type, Name methodName) 1418 { 1419 Type t = type.getThisType().AssociatedSystemType; 1420 1421 // If we got here, it means we couldn't find it in our initial lookup. Means we haven't loaded it from reflection yet. 1422 // Lets go and do that now. 1423 // Check if we have constructors or not. 1424 if (methodName == NameManager.GetPredefinedName(PredefinedName.PN_CTOR)) 1425 { 1426 foreach (ConstructorInfo c in t.GetConstructors()) 1427 { 1428 AddMethodToSymbolTable( 1429 c, 1430 type, 1431 MethodKindEnum.Constructor); 1432 } 1433 } 1434 else 1435 { 1436 var methods = Enumerable.Where(t.GetRuntimeMethods(), m => m.Name == methodName.Text && m.DeclaringType == t); 1437 1438 foreach (MethodInfo m in methods) 1439 { 1440 AddMethodToSymbolTable( 1441 m, 1442 type, 1443 m.Name == SpecialNames.Invoke ? MethodKindEnum.Invoke : MethodKindEnum.Actual); 1444 } 1445 } 1446 } 1447 1448 ///////////////////////////////////////////////////////////////////////////////// 1449 AddMethodToSymbolTable(MethodBase member, AggregateSymbol callingAggregate, MethodKindEnum kind)1450 private MethodSymbol AddMethodToSymbolTable(MethodBase member, AggregateSymbol callingAggregate, MethodKindEnum kind) 1451 { 1452 MethodInfo method = member as MethodInfo; 1453 1454 Debug.Assert(method != null || member is ConstructorInfo); 1455 #if UNSUPPORTEDAPI 1456 Debug.Assert(member.DeclaringType == member.ReflectedType); 1457 #endif 1458 // If we are trying to add an actual method via MethodKindEnum.Actual, and 1459 // the memberinfo is a special name, and its not static, then return null. 1460 // We'll re-add the thing later with some other method kind. 1461 // 1462 // This will happen for things like indexers and properties. The ones that have 1463 // special names that we DO want to allow adding are things like operators, which 1464 // are static and will not be added again later. 1465 1466 if (kind == MethodKindEnum.Actual && // MethKindEnum.Actual 1467 (method == null || // Not a ConstructorInfo 1468 (!method.IsStatic && method.IsSpecialName))) // Not static and is a special name 1469 { 1470 return null; 1471 } 1472 1473 MethodSymbol methodSymbol = FindMatchingMethod(member, callingAggregate); 1474 if (methodSymbol != null) 1475 { 1476 return methodSymbol; 1477 } 1478 1479 ParameterInfo[] parameters = member.GetParameters(); 1480 // First create the method. 1481 methodSymbol = _symFactory.CreateMethod(GetName(member.Name), callingAggregate); 1482 methodSymbol.AssociatedMemberInfo = member; 1483 methodSymbol.SetMethKind(kind); 1484 if (kind == MethodKindEnum.ExplicitConv || kind == MethodKindEnum.ImplicitConv) 1485 { 1486 callingAggregate.SetHasConversion(); 1487 methodSymbol.SetConvNext(callingAggregate.GetFirstUDConversion()); 1488 callingAggregate.SetFirstUDConversion(methodSymbol); 1489 } 1490 1491 ACCESS access; 1492 if (member.IsPublic) 1493 { 1494 access = ACCESS.ACC_PUBLIC; 1495 } 1496 else if (member.IsPrivate) 1497 { 1498 access = ACCESS.ACC_PRIVATE; 1499 } 1500 else if (member.IsFamily) 1501 { 1502 access = ACCESS.ACC_PROTECTED; 1503 } 1504 else if (member.IsFamilyOrAssembly) 1505 { 1506 access = ACCESS.ACC_INTERNALPROTECTED; 1507 } 1508 else if (member.IsAssembly) 1509 { 1510 access = ACCESS.ACC_INTERNAL; 1511 } 1512 else 1513 { 1514 Debug.Assert(member.IsFamilyAndAssembly); 1515 access = ACCESS.ACC_INTERNAL_AND_PROTECTED; 1516 } 1517 1518 methodSymbol.SetAccess(access); 1519 methodSymbol.isVirtual = member.IsVirtual; 1520 methodSymbol.isStatic = member.IsStatic; 1521 1522 if (method != null) 1523 { 1524 methodSymbol.typeVars = GetMethodTypeParameters(method, methodSymbol); 1525 methodSymbol.isOverride = method.IsVirtual && method.IsHideBySig && method.GetRuntimeBaseDefinition() != method; 1526 methodSymbol.isOperator = IsOperator(method); 1527 methodSymbol.swtSlot = GetSlotForOverride(method); 1528 methodSymbol.RetType = GetCTypeFromType(method.ReturnType); 1529 } 1530 else 1531 { 1532 methodSymbol.typeVars = BSYMMGR.EmptyTypeArray(); 1533 methodSymbol.isOverride = false; 1534 methodSymbol.isOperator = false; 1535 methodSymbol.swtSlot = null; 1536 methodSymbol.RetType = _typeManager.GetVoid(); 1537 } 1538 1539 methodSymbol.modOptCount = GetCountOfModOpts(parameters); 1540 1541 methodSymbol.isParamArray = DoesMethodHaveParameterArray(parameters); 1542 methodSymbol.isHideByName = false; 1543 1544 methodSymbol.Params = CreateParameterArray(methodSymbol.AssociatedMemberInfo, parameters); 1545 1546 SetParameterDataForMethProp(methodSymbol, parameters); 1547 1548 return methodSymbol; 1549 } 1550 1551 ///////////////////////////////////////////////////////////////////////////////// 1552 SetParameterDataForMethProp(MethodOrPropertySymbol methProp, ParameterInfo[] parameters)1553 private void SetParameterDataForMethProp(MethodOrPropertySymbol methProp, ParameterInfo[] parameters) 1554 { 1555 if (parameters.Length > 0) 1556 { 1557 // See if we have a param array. 1558 if (parameters[parameters.Length - 1].GetCustomAttribute(typeof(ParamArrayAttribute), false) != null) 1559 { 1560 methProp.isParamArray = true; 1561 } 1562 1563 // Mark the names of the parameters, and their default values. 1564 for (int i = 0; i < parameters.Length; i++) 1565 { 1566 SetParameterAttributes(methProp, parameters, i); 1567 1568 // Insert the name. 1569 methProp.ParameterNames.Add(GetName(parameters[i].Name)); 1570 } 1571 } 1572 } 1573 1574 ///////////////////////////////////////////////////////////////////////////////// 1575 SetParameterAttributes(MethodOrPropertySymbol methProp, ParameterInfo[] parameters, int i)1576 private void SetParameterAttributes(MethodOrPropertySymbol methProp, ParameterInfo[] parameters, int i) 1577 { 1578 ParameterInfo parameter = parameters[i]; 1579 if ((parameter.Attributes & ParameterAttributes.Optional) != 0 && !parameter.ParameterType.IsByRef) 1580 { 1581 methProp.SetOptionalParameter(i); 1582 PopulateSymbolTableWithName("Value", new Type[] { typeof(Missing) }, typeof(Missing)); // We might need this later 1583 } 1584 1585 // Get MarshalAsAttribute 1586 if ((parameter.Attributes & ParameterAttributes.HasFieldMarshal) != 0) 1587 { 1588 MarshalAsAttribute attr = parameter.GetCustomAttribute<MarshalAsAttribute>(false); 1589 if (attr != null) 1590 { 1591 methProp.SetMarshalAsParameter(i, attr.Value); 1592 } 1593 } 1594 1595 DateTimeConstantAttribute dateAttr = parameter.GetCustomAttribute<DateTimeConstantAttribute>(false); 1596 // Get the various kinds of default values 1597 if (dateAttr != null) 1598 { 1599 // Get DateTimeConstant 1600 ConstVal cv = ConstVal.Get(((DateTime)dateAttr.Value).Ticks); 1601 CType cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_DATETIME); 1602 methProp.SetDefaultParameterValue(i, cvType, cv); 1603 } 1604 else 1605 { 1606 DecimalConstantAttribute decAttr = parameter.GetCustomAttribute<DecimalConstantAttribute>(); 1607 if (decAttr != null) 1608 { 1609 // Get DecimalConstant 1610 ConstVal cv = ConstVal.Get(decAttr.Value); 1611 CType cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_DECIMAL); 1612 methProp.SetDefaultParameterValue(i, cvType, cv); 1613 } 1614 else if ((parameter.Attributes & ParameterAttributes.HasDefault) != 0 && !parameter.ParameterType.IsByRef) 1615 { 1616 // Only set a default value if we have one, and the type that we're 1617 // looking at isn't a by ref type or a type parameter. 1618 1619 ConstVal cv = default(ConstVal); 1620 CType cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT); 1621 1622 // We need to use RawDefaultValue, because DefaultValue is too clever. 1623 #if UNSUPPORTEDAPI 1624 if (parameter.RawDefaultValue != null) 1625 { 1626 object defValue = parameter.RawDefaultValue; 1627 #else 1628 if (parameter.DefaultValue != null) 1629 { 1630 object defValue = parameter.DefaultValue; 1631 #endif 1632 Debug.Assert(Type.GetTypeCode(defValue.GetType()) != TypeCode.Decimal); // Handled above 1633 switch (Type.GetTypeCode(defValue.GetType())) 1634 { 1635 1636 case TypeCode.Byte: 1637 cv = ConstVal.Get((byte)defValue); 1638 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_BYTE); 1639 break; 1640 1641 case TypeCode.Int16: 1642 cv = ConstVal.Get((short)defValue); 1643 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_SHORT); 1644 break; 1645 1646 case TypeCode.Int32: 1647 cv = ConstVal.Get((int)defValue); 1648 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_INT); 1649 break; 1650 1651 case TypeCode.Int64: 1652 cv = ConstVal.Get((long)defValue); 1653 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_LONG); 1654 break; 1655 1656 case TypeCode.Single: 1657 cv = ConstVal.Get((float)defValue); 1658 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_FLOAT); 1659 break; 1660 1661 case TypeCode.Double: 1662 cv = ConstVal.Get((double)defValue); 1663 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_DOUBLE); 1664 break; 1665 1666 case TypeCode.Char: 1667 cv = ConstVal.Get((char)defValue); 1668 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_CHAR); 1669 break; 1670 1671 case TypeCode.Boolean: 1672 cv = ConstVal.Get((bool)defValue); 1673 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_BOOL); 1674 break; 1675 1676 case TypeCode.SByte: 1677 cv = ConstVal.Get((sbyte)defValue); 1678 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_SBYTE); 1679 break; 1680 1681 case TypeCode.UInt16: 1682 cv = ConstVal.Get((ushort)defValue); 1683 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_USHORT); 1684 break; 1685 1686 case TypeCode.UInt32: 1687 cv = ConstVal.Get((uint)defValue); 1688 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_UINT); 1689 break; 1690 1691 case TypeCode.UInt64: 1692 cv = ConstVal.Get((ulong)defValue); 1693 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_ULONG); 1694 break; 1695 1696 case TypeCode.String: 1697 cv = ConstVal.Get((string)defValue); 1698 cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_STRING); 1699 break; 1700 } 1701 1702 // if we hit no case in the switch, we get object/null 1703 // because that's how we initialized the constval. 1704 } 1705 1706 methProp.SetDefaultParameterValue(i, cvType, cv); 1707 } 1708 } 1709 } 1710 1711 ///////////////////////////////////////////////////////////////////////////////// 1712 1713 private MethodSymbol FindMatchingMethod(MemberInfo method, AggregateSymbol callingAggregate) 1714 { 1715 MethodSymbol meth = _bsymmgr.LookupAggMember(GetName(method.Name), callingAggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol; 1716 while (meth != null) 1717 { 1718 if (meth.AssociatedMemberInfo.IsEquivalentTo(method)) 1719 { 1720 return meth; 1721 } 1722 meth = BSYMMGR.LookupNextSym(meth, callingAggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol; 1723 } 1724 return null; 1725 } 1726 1727 ///////////////////////////////////////////////////////////////////////////////// 1728 1729 private uint GetCountOfModOpts(ParameterInfo[] parameters) 1730 { 1731 uint count = 0; 1732 #if UNSUPPORTEDAPI 1733 foreach (ParameterInfo p in parameters) 1734 { 1735 if (p.GetOptionalCustomModifiers() != null) 1736 { 1737 count += (uint)p.GetOptionalCustomModifiers().Length; 1738 } 1739 } 1740 #endif 1741 return count; 1742 } 1743 1744 ///////////////////////////////////////////////////////////////////////////////// 1745 1746 private TypeArray CreateParameterArray(MemberInfo associatedInfo, ParameterInfo[] parameters) 1747 { 1748 List<CType> types = new List<CType>(); 1749 1750 foreach (ParameterInfo p in parameters) 1751 { 1752 types.Add(GetTypeOfParameter(p, associatedInfo)); 1753 } 1754 1755 if (associatedInfo is MethodBase mb && (mb.CallingConvention & CallingConventions.VarArgs) != 0) 1756 { 1757 types.Add(_typeManager.GetArgListType()); 1758 } 1759 1760 return _bsymmgr.AllocParams(types.Count, types.ToArray()); 1761 } 1762 1763 ///////////////////////////////////////////////////////////////////////////////// 1764 1765 private CType GetTypeOfParameter(ParameterInfo p, MemberInfo m) 1766 { 1767 Type t = p.ParameterType; 1768 CType ctype; 1769 if (t.IsGenericParameter && t.DeclaringMethod != null && t.DeclaringMethod == m) 1770 { 1771 // If its a method type parameter from ourselves, just find it. 1772 ctype = LoadMethodTypeParameter(FindMethodFromMemberInfo(m), t); 1773 } 1774 else 1775 { 1776 ctype = GetCTypeFromType(t); 1777 } 1778 1779 // Check if we have an out parameter. 1780 if (ctype is ParameterModifierType mod && p.IsOut && !p.IsIn) 1781 { 1782 CType parameterType = mod.GetParameterType(); 1783 ctype = _typeManager.GetParameterModifier(parameterType, true); 1784 } 1785 1786 return ctype; 1787 } 1788 1789 ///////////////////////////////////////////////////////////////////////////////// 1790 1791 private bool DoesMethodHaveParameterArray(ParameterInfo[] parameters) 1792 { 1793 if (parameters.Length == 0) 1794 { 1795 return false; 1796 } 1797 1798 ParameterInfo p = parameters[parameters.Length - 1]; 1799 var attributes = p.GetCustomAttributes(false); 1800 1801 foreach (object o in attributes) 1802 { 1803 if (o is ParamArrayAttribute) 1804 { 1805 return true; 1806 } 1807 } 1808 return false; 1809 } 1810 1811 ///////////////////////////////////////////////////////////////////////////////// 1812 1813 private SymWithType GetSlotForOverride(MethodInfo method) 1814 { 1815 if (method.IsVirtual && method.IsHideBySig) 1816 { 1817 MethodInfo baseMethodInfo = method.GetRuntimeBaseDefinition(); 1818 if (baseMethodInfo == method) 1819 { 1820 // We just found ourselves, so we don't care here. 1821 return null; 1822 } 1823 1824 // We have the base class method that we're overriding. We can assume 1825 // that all the parent aggregate symbols were added, and that we added 1826 // the methods in order. As such, our parent methods should be in the 1827 // symbol table at this point. 1828 1829 AggregateSymbol aggregate = GetCTypeFromType(baseMethodInfo.DeclaringType).getAggregate(); 1830 MethodSymbol baseMethod = FindMethodFromMemberInfo(baseMethodInfo); 1831 Debug.Assert(baseMethod != null); 1832 return new SymWithType(baseMethod, aggregate.getThisType()); 1833 } 1834 1835 return null; 1836 } 1837 1838 ///////////////////////////////////////////////////////////////////////////////// 1839 1840 private MethodSymbol FindMethodFromMemberInfo(MemberInfo baseMemberInfo) 1841 { 1842 CType t = GetCTypeFromType(baseMemberInfo.DeclaringType); 1843 Debug.Assert(t is AggregateType); 1844 AggregateSymbol aggregate = t.getAggregate(); 1845 Debug.Assert(aggregate != null); 1846 1847 MethodSymbol meth = _semanticChecker.SymbolLoader.LookupAggMember( 1848 GetName(baseMemberInfo.Name), 1849 aggregate, 1850 symbmask_t.MASK_MethodSymbol) as MethodSymbol; 1851 for (; 1852 meth != null && !meth.AssociatedMemberInfo.IsEquivalentTo(baseMemberInfo); 1853 meth = SymbolLoader.LookupNextSym(meth, aggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol) 1854 ; 1855 1856 return meth; 1857 } 1858 1859 ///////////////////////////////////////////////////////////////////////////////// 1860 1861 internal bool AggregateContainsMethod(AggregateSymbol agg, string szName, symbmask_t mask) 1862 { 1863 return _semanticChecker.SymbolLoader.LookupAggMember(GetName(szName), agg, mask) != null; 1864 } 1865 #endregion 1866 1867 #region Conversions 1868 ///////////////////////////////////////////////////////////////////////////////// 1869 1870 internal void AddConversionsForType(Type type) 1871 { 1872 if (type.IsInterface) 1873 { 1874 AddConversionsForOneType(type); 1875 } 1876 for (Type t = type; t.BaseType != null; t = t.BaseType) 1877 { 1878 AddConversionsForOneType(t); 1879 } 1880 } 1881 1882 ///////////////////////////////////////////////////////////////////////////////// 1883 1884 private void AddConversionsForOneType(Type type) 1885 { 1886 if (type.IsGenericType) 1887 { 1888 type = type.GetGenericTypeDefinition(); 1889 } 1890 1891 if (!_typesWithConversionsLoaded.Add(type)) 1892 { 1893 return; 1894 } 1895 1896 // Always make the aggregate for the type, regardless of whether or not 1897 // there are any conversions. 1898 CType t = GetCTypeFromType(type); 1899 1900 if (!(t is AggregateType)) 1901 { 1902 CType endT; 1903 while ((endT = t.GetBaseOrParameterOrElementType()) != null) 1904 { 1905 t = endT; 1906 } 1907 } 1908 1909 if (t is TypeParameterType paramType) 1910 { 1911 // Add conversions for the bounds. 1912 foreach (CType bound in paramType.GetBounds().Items) 1913 { 1914 AddConversionsForType(bound.AssociatedSystemType); 1915 } 1916 return; 1917 } 1918 1919 Debug.Assert(t is AggregateType); 1920 AggregateSymbol aggregate = ((AggregateType)t).getAggregate(); 1921 1922 // Now find all the conversions and make them. 1923 foreach (MethodInfo conversion in type.GetRuntimeMethods()) 1924 { 1925 if (conversion.IsPublic && conversion.IsStatic && conversion.DeclaringType == type 1926 && conversion.IsSpecialName && !conversion.IsGenericMethod) 1927 { 1928 MethodKindEnum methodKind; 1929 switch (conversion.Name) 1930 { 1931 case SpecialNames.ImplicitConversion: 1932 methodKind = MethodKindEnum.ImplicitConv; 1933 break; 1934 case SpecialNames.ExplicitConversion: 1935 methodKind = MethodKindEnum.ExplicitConv; 1936 break; 1937 default: 1938 continue; 1939 } 1940 1941 AddMethodToSymbolTable(conversion, aggregate, methodKind); 1942 } 1943 } 1944 } 1945 #endregion 1946 1947 #region Operators 1948 ///////////////////////////////////////////////////////////////////////////////// 1949 1950 private static bool IsOperator(MethodInfo method) 1951 { 1952 if (method.IsSpecialName && method.IsStatic) 1953 { 1954 switch (method.Name) 1955 { 1956 case SpecialNames.ImplicitConversion: 1957 case SpecialNames.ExplicitConversion: 1958 case SpecialNames.CLR_Add: 1959 case SpecialNames.CLR_Subtract: 1960 case SpecialNames.CLR_Multiply: 1961 case SpecialNames.CLR_Division: 1962 case SpecialNames.CLR_Modulus: 1963 case SpecialNames.CLR_LShift: 1964 case SpecialNames.CLR_RShift: 1965 case SpecialNames.CLR_LT: 1966 case SpecialNames.CLR_GT: 1967 case SpecialNames.CLR_LTE: 1968 case SpecialNames.CLR_GTE: 1969 case SpecialNames.CLR_Equality: 1970 case SpecialNames.CLR_Inequality: 1971 case SpecialNames.CLR_BitwiseAnd: 1972 case SpecialNames.CLR_ExclusiveOr: 1973 case SpecialNames.CLR_BitwiseOr: 1974 case SpecialNames.CLR_LogicalNot: 1975 case SpecialNames.CLR_UnaryNegation: 1976 case SpecialNames.CLR_UnaryPlus: 1977 case SpecialNames.CLR_OnesComplement: 1978 case SpecialNames.CLR_True: 1979 case SpecialNames.CLR_False: 1980 case SpecialNames.CLR_PreIncrement: 1981 case SpecialNames.CLR_PreDecrement: 1982 return true; 1983 } 1984 } 1985 1986 return false; 1987 } 1988 1989 #endregion 1990 } 1991 } 1992