Appearance
| 1 | namespace Semantic is | |
| 2 | use Types.Type; | |
| 3 | ||
| 4 | // Recognises .NET delegate types and reports the function type that | |
| 5 | // describes how they are called. | |
| 6 | // | |
| 7 | // `Func` and `Action` are excluded: they are already modelled as | |
| 8 | // FUNCTION / ACTION, so `is_named_delegate` answers false for them | |
| 9 | // and callers keep their existing path. | |
| 10 | class DELEGATE_SHAPE is | |
| 11 | MULTICAST_DELEGATE_NAME: string static => "System.MulticastDelegate"; | |
| 12 | ||
| 13 | init() is | |
| 14 | si | |
| 15 | ||
| 16 | // True for a delegate type ghūl does not already model as a | |
| 17 | // function type. | |
| 18 | is_named_delegate(type: Type) -> bool => | |
| 19 | !type.is_function /\ _inherits_multicast_delegate(type); | |
| 20 | ||
| 21 | // The function type describing `type`'s call shape, or null when | |
| 22 | // `type` is not a named delegate or carries no usable `invoke`. | |
| 23 | try_get_function_type(type: Type, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> Type? is | |
| 24 | if !is_named_delegate(type) then | |
| 25 | return null; | |
| 26 | fi | |
| 27 | ||
| 28 | let invoke = _find_invoke(type); | |
| 29 | ||
| 30 | if !invoke? \/ !invoke.return_type? \/ !invoke.are_arguments_declared then | |
| 31 | return null; | |
| 32 | fi | |
| 33 | ||
| 34 | return invoke.get_full_type(innate_symbol_lookup); | |
| 35 | si | |
| 36 | ||
| 37 | // A delegate declares exactly one `Invoke`, so the group it | |
| 38 | // arrives in holds a single function. | |
| 39 | _find_invoke(type: Type) -> Symbols.Function? is | |
| 40 | let member = type.find_member("invoke"); | |
| 41 | ||
| 42 | if let group: Symbols.FUNCTION_GROUP = member then | |
| 43 | if group.count == 1 then | |
| 44 | return group.functions[0]; | |
| 45 | fi | |
| 46 | ||
| 47 | return null; | |
| 48 | fi | |
| 49 | ||
| 50 | return cast Symbols.Function?(member); | |
| 51 | si | |
| 52 | ||
| 53 | _inherits_multicast_delegate(type: Type) -> bool is | |
| 54 | for ancestor in type.ancestors do | |
| 55 | if ancestor.symbol.qualified_name =~ MULTICAST_DELEGATE_NAME then | |
| 56 | return true; | |
| 57 | fi | |
| 58 | ||
| 59 | if _inherits_multicast_delegate(ancestor) then | |
| 60 | return true; | |
| 61 | fi | |
| 62 | od | |
| 63 | ||
| 64 | return false; | |
| 65 | si | |
| 66 | si | |
| 67 | si |