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;
                                    }
                                }