public static void InjectMiddleware(ref IMarshalContext ctx, Action next) { var context = ctx; var injectDatas = ctx.MethodSymbol.GetAttributes().Where( x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, context.Compilation.GetTypeByMetadataName(typeof(InjectAttribute).FullName)) ); foreach (var injectData in injectDatas) { var injectPoint = (SilkTouchStage)injectData.ConstructorArguments[0].Value !; var code = (string)injectData.ConstructorArguments[1].Value !; ctx.AddSideEffectToStage(injectPoint, ctx => { if (injectPoint == SilkTouchStage.End) { var substitutions = _substitutionRegex.Match(code); if (substitutions.Success) { var codeBuilder = new StringBuilder(); var start = 0; string?resultStr = null; Dictionary <string, string>?pValues = null; while (substitutions.Success) { string?substitution = null; if (substitutions.Groups["result"].Success) { if (ctx.ResultVariable.HasValue) { // Cache for multiple-substitution if (resultStr is null) { resultStr = ParenthesizedExpression(ctx.ResolveVariable(ctx.ResultVariable.Value).Value) .NormalizeWhitespace() .ToFullString(); } substitution = resultStr; } } else { var parameterName = substitutions.Groups["pname"].Value; // Create parameter lookup dictionary first time we see the substitution. if (pValues is null) { pValues = ctx.MethodSymbol.Parameters .Select((p, i) => ( Name: p.Name, Value: ParenthesizedExpression(ctx.ResolveVariable(ctx.ParameterVariables[i]).Value) .NormalizeWhitespace() .ToFullString())) .ToDictionary(t => t.Name, t => t.Value); } if (pValues.TryGetValue(parameterName, out var value)) { substitution = value; } }