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.Diagnostics;
7 using System.Reflection;
8 using Microsoft.CSharp.RuntimeBinder.Syntax;
9 
10 namespace Microsoft.CSharp.RuntimeBinder.Semantics
11 {
12     // Name used for AGGDECLs in the symbol table.
13 
14     // AggregateSymbol - a symbol representing an aggregate type. These are classes,
15     // interfaces, and structs. Parent is a namespace or class. Children are methods,
16     // properties, and member variables, and types (including its own AGGTYPESYMs).
17 
18     internal class AggregateSymbol : NamespaceOrAggregateSymbol
19     {
20         public Type AssociatedSystemType;
21         public Assembly AssociatedAssembly;
22 
23         // The instance type. Created when first needed.
24         private AggregateType _atsInst;
25 
26         private AggregateType _pBaseClass;     // For a class/struct/enum, the base class. For iface: unused.
27         private AggregateType _pUnderlyingType; // For enum, the underlying type. For iface, the resolved CoClass. Not used for class/struct.
28 
29         private TypeArray _ifaces;         // The explicit base interfaces for a class or interface.
30         private TypeArray _ifacesAll;      // Recursive closure of base interfaces ordered so an iface appears before all of its base ifaces.
31 
32         private TypeArray _typeVarsThis; // Type variables for this generic class, as declarations.
33         private TypeArray _typeVarsAll;     // The type variables for this generic class and all containing classes.
34 
35         private TypeManager _pTypeManager;     // This is so AGGTYPESYMs can instantiate their baseClass and ifacesAll members on demand.
36 
37         // First UD conversion operator. This chain is for this type only (not base types).
38         // The hasConversion flag indicates whether this or any base types have UD conversions.
39         private MethodSymbol _pConvFirst;
40 
41         // ------------------------------------------------------------------------
42         //
43         // Put members that are bits under here in a contiguous section.
44         //
45         // ------------------------------------------------------------------------
46 
47         private AggKindEnum _aggKind;
48 
49         // Where this came from - fabricated, source, import
50         // Fabricated AGGs have isSource == true but hasParseTree == false.
51         // N.B.: in incremental builds, it is quite possible for
52         // isSource==TRUE and hasParseTree==FALSE. Be
53         // sure you use the correct variable for what you are trying to do!
54 
55         // Predefined
56         private bool _isPredefined;    // A special predefined type.
57         private PredefinedType _iPredef;        // index of the predefined type, if isPredefined.
58 
59         // Flags
60         private bool _isAbstract;      // Can it be instantiated?
61         private bool _isSealed;        // Can it be derived from?
62 
63         // Constructors
64         private bool _hasPubNoArgCtor; // Whether it has a public instance constructor taking no args
65 
66         // User defined operators
67 
68         private bool _isSkipUDOps; // Never check for user defined operators on this type (eg, decimal, string, delegate).
69 
70         // When this is unset we don't know if we have conversions.  When this
71         // is set it indicates if this type or any base type has user defined
72         // conversion operators
73         private bool? _hasConversion;
74 
75         // ----------------------------------------------------------------------------
76         // AggregateSymbol
77         // ----------------------------------------------------------------------------
78 
GetBaseAgg()79         public AggregateSymbol GetBaseAgg()
80         {
81             return _pBaseClass?.getAggregate();
82         }
83 
getThisType()84         public AggregateType getThisType()
85         {
86             if (_atsInst == null)
87             {
88                 Debug.Assert(GetTypeVars() == GetTypeVarsAll() || isNested());
89 
90                 AggregateType pOuterType = isNested() ? GetOuterAgg().getThisType() : null;
91 
92                 _atsInst = _pTypeManager.GetAggregate(this, pOuterType, GetTypeVars());
93             }
94 
95             //Debug.Assert(GetTypeVars().Size == atsInst.GenericArguments.Count);
96             return _atsInst;
97         }
98 
FindBaseAgg(AggregateSymbol agg)99         public bool FindBaseAgg(AggregateSymbol agg)
100         {
101             for (AggregateSymbol aggT = this; aggT != null; aggT = aggT.GetBaseAgg())
102             {
103                 if (aggT == agg)
104                     return true;
105             }
106             return false;
107         }
108 
109         public NamespaceOrAggregateSymbol Parent => parent as NamespaceOrAggregateSymbol;
110 
isNested()111         public bool isNested() => parent is AggregateSymbol;
112 
GetOuterAgg()113         public AggregateSymbol GetOuterAgg() => parent as AggregateSymbol;
114 
isPredefAgg(PredefinedType pt)115         public bool isPredefAgg(PredefinedType pt)
116         {
117             return _isPredefined && (PredefinedType)_iPredef == pt;
118         }
119 
120         // ----------------------------------------------------------------------------
121         // The following are the Accessor functions for AggregateSymbol.
122         // ----------------------------------------------------------------------------
123 
AggKind()124         public AggKindEnum AggKind()
125         {
126             return (AggKindEnum)_aggKind;
127         }
128 
SetAggKind(AggKindEnum aggKind)129         public void SetAggKind(AggKindEnum aggKind)
130         {
131             // NOTE: When importing can demote types:
132             //  - enums with no underlying type go to struct
133             //  - delegates which are abstract or have no .ctor/Invoke method goto class
134             _aggKind = aggKind;
135 
136             //An interface is always abstract
137             if (aggKind == AggKindEnum.Interface)
138             {
139                 SetAbstract(true);
140             }
141         }
142 
IsClass()143         public bool IsClass()
144         {
145             return AggKind() == AggKindEnum.Class;
146         }
147 
IsDelegate()148         public bool IsDelegate()
149         {
150             return AggKind() == AggKindEnum.Delegate;
151         }
152 
IsInterface()153         public bool IsInterface()
154         {
155             return AggKind() == AggKindEnum.Interface;
156         }
157 
IsStruct()158         public bool IsStruct()
159         {
160             return AggKind() == AggKindEnum.Struct;
161         }
162 
IsEnum()163         public bool IsEnum()
164         {
165             return AggKind() == AggKindEnum.Enum;
166         }
167 
IsValueType()168         public bool IsValueType()
169         {
170             return AggKind() == AggKindEnum.Struct || AggKind() == AggKindEnum.Enum;
171         }
172 
IsRefType()173         public bool IsRefType()
174         {
175             return AggKind() == AggKindEnum.Class ||
176                 AggKind() == AggKindEnum.Interface || AggKind() == AggKindEnum.Delegate;
177         }
178 
IsStatic()179         public bool IsStatic()
180         {
181             return (_isAbstract && _isSealed);
182         }
183 
IsAbstract()184         public bool IsAbstract()
185         {
186             return _isAbstract;
187         }
188 
189         public void SetAbstract(bool @abstract)
190         {
191             _isAbstract = @abstract;
192         }
193 
IsPredefined()194         public bool IsPredefined()
195         {
196             return _isPredefined;
197         }
198 
SetPredefined(bool predefined)199         public void SetPredefined(bool predefined)
200         {
201             _isPredefined = predefined;
202         }
203 
GetPredefType()204         public PredefinedType GetPredefType()
205         {
206             return (PredefinedType)_iPredef;
207         }
208 
SetPredefType(PredefinedType predef)209         public void SetPredefType(PredefinedType predef)
210         {
211             _iPredef = predef;
212         }
213 
IsSealed()214         public bool IsSealed()
215         {
216             return _isSealed == true;
217         }
218 
219         public void SetSealed(bool @sealed)
220         {
221             _isSealed = @sealed;
222         }
223 
224         ////////////////////////////////////////////////////////////////////////////////
225 
HasConversion(SymbolLoader pLoader)226         public bool HasConversion(SymbolLoader pLoader)
227         {
228             pLoader.RuntimeBinderSymbolTable.AddConversionsForType(AssociatedSystemType);
229 
230             if (!_hasConversion.HasValue)
231             {
232                 // ok, we tried defining all the conversions, and we didn't get anything
233                 // for this type.  However, we will still think this type has conversions
234                 // if it's base type has conversions.
235                 _hasConversion = GetBaseAgg() != null && GetBaseAgg().HasConversion(pLoader);
236             }
237 
238             return _hasConversion.Value;
239         }
240 
241         ////////////////////////////////////////////////////////////////////////////////
242 
SetHasConversion()243         public void SetHasConversion()
244         {
245             _hasConversion = true;
246         }
247 
248         ////////////////////////////////////////////////////////////////////////////////
249 
HasPubNoArgCtor()250         public bool HasPubNoArgCtor()
251         {
252             return _hasPubNoArgCtor == true;
253         }
254 
SetHasPubNoArgCtor(bool hasPubNoArgCtor)255         public void SetHasPubNoArgCtor(bool hasPubNoArgCtor)
256         {
257             _hasPubNoArgCtor = hasPubNoArgCtor;
258         }
259 
IsSkipUDOps()260         public bool IsSkipUDOps()
261         {
262             return _isSkipUDOps == true;
263         }
264 
SetSkipUDOps(bool skipUDOps)265         public void SetSkipUDOps(bool skipUDOps)
266         {
267             _isSkipUDOps = skipUDOps;
268         }
269 
GetTypeVars()270         public TypeArray GetTypeVars()
271         {
272             return _typeVarsThis;
273         }
274 
SetTypeVars(TypeArray typeVars)275         public void SetTypeVars(TypeArray typeVars)
276         {
277             if (typeVars == null)
278             {
279                 _typeVarsThis = null;
280                 _typeVarsAll = null;
281             }
282             else
283             {
284                 TypeArray outerTypeVars;
285                 if (GetOuterAgg() != null)
286                 {
287                     Debug.Assert(GetOuterAgg().GetTypeVars() != null);
288                     Debug.Assert(GetOuterAgg().GetTypeVarsAll() != null);
289 
290                     outerTypeVars = GetOuterAgg().GetTypeVarsAll();
291                 }
292                 else
293                 {
294                     outerTypeVars = BSYMMGR.EmptyTypeArray();
295                 }
296 
297                 _typeVarsThis = typeVars;
298                 _typeVarsAll = _pTypeManager.ConcatenateTypeArrays(outerTypeVars, typeVars);
299             }
300         }
301 
GetTypeVarsAll()302         public TypeArray GetTypeVarsAll()
303         {
304             return _typeVarsAll;
305         }
306 
GetBaseClass()307         public AggregateType GetBaseClass()
308         {
309             return _pBaseClass;
310         }
311 
SetBaseClass(AggregateType baseClass)312         public void SetBaseClass(AggregateType baseClass)
313         {
314             _pBaseClass = baseClass;
315         }
316 
GetUnderlyingType()317         public AggregateType GetUnderlyingType()
318         {
319             return _pUnderlyingType;
320         }
321 
SetUnderlyingType(AggregateType underlyingType)322         public void SetUnderlyingType(AggregateType underlyingType)
323         {
324             _pUnderlyingType = underlyingType;
325         }
326 
GetIfaces()327         public TypeArray GetIfaces()
328         {
329             return _ifaces;
330         }
331 
SetIfaces(TypeArray ifaces)332         public void SetIfaces(TypeArray ifaces)
333         {
334             _ifaces = ifaces;
335         }
336 
GetIfacesAll()337         public TypeArray GetIfacesAll()
338         {
339             return _ifacesAll;
340         }
341 
SetIfacesAll(TypeArray ifacesAll)342         public void SetIfacesAll(TypeArray ifacesAll)
343         {
344             _ifacesAll = ifacesAll;
345         }
346 
GetTypeManager()347         public TypeManager GetTypeManager()
348         {
349             return _pTypeManager;
350         }
351 
SetTypeManager(TypeManager typeManager)352         public void SetTypeManager(TypeManager typeManager)
353         {
354             _pTypeManager = typeManager;
355         }
356 
GetFirstUDConversion()357         public MethodSymbol GetFirstUDConversion()
358         {
359             return _pConvFirst;
360         }
361 
SetFirstUDConversion(MethodSymbol conv)362         public void SetFirstUDConversion(MethodSymbol conv)
363         {
364             _pConvFirst = conv;
365         }
366 
InternalsVisibleTo(Assembly assembly)367         public bool InternalsVisibleTo(Assembly assembly)
368         {
369             return _pTypeManager.InternalsVisibleTo(AssociatedAssembly, assembly);
370         }
371     }
372 }
373