public static IList <MethodSymbol> GetSelfStaticCalls(BoundBlock block) { var visitor = new LateStaticCallsLookup(); visitor.Accept(block); return((IList <MethodSymbol>)visitor._lazyStaticCalls ?? Array.Empty <MethodSymbol>()); }
/// <summary> /// Walks static methods that don't use late static binding and checks if it should forward the late static type; /// hence it must know the late static as well. /// </summary> void ForwardLateStaticBindings() { var calls = new ConcurrentBag <KeyValuePair <SourceMethodSymbol, MethodSymbol> >(); // collect self:: or parent:: static calls this.WalkMethods(routine => { if (routine is SourceMethodSymbol caller && caller.IsStatic && (caller.Flags & RoutineFlags.UsesLateStatic) == 0) { var cfg = caller.ControlFlowGraph; if (cfg == null) { return; } // has self:: or parent:: call to a routine? var selfcalls = LateStaticCallsLookup.GetSelfStaticCalls(cfg.Start); if (selfcalls.Count == 0) { return; } // routine requires late static type? if (selfcalls.Any(sm => sm.HasLateStaticBoundParam())) { caller.Flags |= RoutineFlags.UsesLateStatic; } else { foreach (var callee in selfcalls) { calls.Add(new KeyValuePair <SourceMethodSymbol, MethodSymbol>(caller, callee)); } } } }, allowParallel: ConcurrentBuild); // process edges between caller and calles until we forward all the late static calls int forwarded; do { forwarded = 0; Parallel.ForEach(calls, edge => { if ((edge.Key.Flags & RoutineFlags.UsesLateStatic) == 0 && edge.Value.HasLateStaticBoundParam()) { edge.Key.Flags |= RoutineFlags.UsesLateStatic; Interlocked.Increment(ref forwarded); } }); } while (forwarded != 0); }