public void ParseEmptyFormatting(string input, string expectedOutput)
    {
        var processor = new ParameterFormattingProcessor();

        var info = processor.ParseParameterFormatting(input);

        Assert.NotNull(info);
        Assert.Equal(expectedOutput, info.Format);
    }
    public void ParseComplexFormatting()
    {
        var processor = new ParameterFormattingProcessor();

        var info = processor.ParseParameterFormatting("This is a {fileName} test with id = '{id}' and {fileName} but don't replace fileName");

        Assert.Equal("This is a {0} test with id = '{1}' and {0} but don't replace fileName", info.Format);
        Assert.Equal("fileName", info.ParameterNames[0]);
        Assert.Equal("id", info.ParameterNames[1]);
    }
    public void ParseSimpleFormatting()
    {
        var processor = new ParameterFormattingProcessor();

        var info = processor.ParseParameterFormatting("This is a {fileName}");

        Assert.NotNull(info);

        Assert.Equal("This is a {0}", info.Format);
        Assert.Equal("fileName", info.ParameterNames[0]);
    }
示例#4
0
    IEnumerable <Instruction> ProcessTimeAttribute(MethodDefinition methodDefinition, FieldDefinition formattedFieldDefinition)
    {
// Load everything for a string format
        var timeAttribute = methodDefinition.GetTimeAttribute();

        if (timeAttribute != null)
        {
            var value = timeAttribute.ConstructorArguments.FirstOrDefault().Value as string;
            if (!string.IsNullOrWhiteSpace(value))
            {
                var info = parameterFormattingProcessor.ParseParameterFormatting(value);

                yield return(Instruction.Create(OpCodes.Ldarg_0));

                yield return(Instruction.Create(OpCodes.Ldstr, info.Format));

                yield return(Instruction.Create(OpCodes.Ldc_I4, info.ParameterNames.Count));

                yield return(Instruction.Create(OpCodes.Newarr, ModuleWeaver.TypeSystem.ObjectReference));

                for (var i = 0; i < info.ParameterNames.Count; i++)
                {
                    yield return(Instruction.Create(OpCodes.Dup));

                    yield return(Instruction.Create(OpCodes.Ldc_I4, i));

                    var field = stateMachineType.Fields.FirstOrDefault(x => x.Name.Equals(info.ParameterNames[i]));
                    if (field == null)
                    {
                        ModuleWeaver.LogError($"Parameter '{info.ParameterNames[i]}' is not available on the async state machine. Probably it has been optimized away by the compiler. Please update the format so it excludes this parameter.");

                        yield return(Instruction.Create(OpCodes.Ldnull));
                    }
                    else
                    {
                        yield return(Instruction.Create(OpCodes.Ldarg_0));

                        yield return(Instruction.Create(OpCodes.Ldfld, field));

                        if (field.FieldType.IsBoxingRequired(ModuleWeaver.TypeSystem.ObjectReference))
                        {
                            yield return(Instruction.Create(OpCodes.Box, ModuleWeaver.ModuleDefinition.ImportReference(field.FieldType)));
                        }
                    }

                    yield return(Instruction.Create(OpCodes.Stelem_Ref));
                }

                yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.StringFormatWithArray));
            }
            else
            {
                // Load null a string
                yield return(Instruction.Create(OpCodes.Ldarg_0));

                yield return(Instruction.Create(OpCodes.Ldnull));
            }

            yield return(Instruction.Create(OpCodes.Stfld, formattedFieldDefinition));
        }
    }
示例#5
0
    IEnumerable <Instruction> GetWriteTimeInstruction(MethodDefinition methodDefinition)
    {
        yield return(Instruction.Create(OpCodes.Ldarg_0));

        yield return(Instruction.Create(OpCodes.Ldfld, stopwatchField));

        yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.StopMethod));

        var logWithMessageMethod = ModuleWeaver.LogWithMessageMethod;
        var logMethod            = ModuleWeaver.LogMethod;

        if (logWithMessageMethod != null)
        {
            // Important notes:
            // 1. Because async works with state machines, use the state machine & fields instead of method & variables.
            // 2. The ldarg_0 calls are required to load the state machine class and is required before every field call.

            //var moveNextMethodDefinition = stateMachineType.Methods.First(x => x.Name == "MoveNext");
            //var formattedVariableDefinition = new VariableDefinition(ModuleWeaver.ModuleDefinition.TypeSystem.String);
            //moveNextMethodDefinition.Body.Variables.Add(formattedVariableDefinition);

            var formattedFieldDefinition = stateMachineType.Fields.FirstOrDefault(x => x.Name.Equals("methodTimerMessage"));
            if (formattedFieldDefinition == null)
            {
                formattedFieldDefinition = new FieldDefinition("methodTimerMessage", FieldAttributes.Private | FieldAttributes.CompilerControlled, ModuleWeaver.ModuleDefinition.TypeSystem.String);
                stateMachineType.Fields.Add(formattedFieldDefinition);
            }

            // Load everything for a string format
            var timeAttribute = methodDefinition.GetTimeAttribute();
            if (timeAttribute != null)
            {
                var value = timeAttribute.ConstructorArguments.FirstOrDefault().Value as string;
                if (!string.IsNullOrWhiteSpace(value))
                {
                    var info = parameterFormattingProcessor.ParseParameterFormatting(value);

                    yield return(Instruction.Create(OpCodes.Ldarg_0));

                    yield return(Instruction.Create(OpCodes.Ldstr, info.Format));

                    yield return(Instruction.Create(OpCodes.Ldc_I4, info.ParameterNames.Count));

                    yield return(Instruction.Create(OpCodes.Newarr, ModuleWeaver.ModuleDefinition.TypeSystem.Object));

                    for (var i = 0; i < info.ParameterNames.Count; i++)
                    {
                        yield return(Instruction.Create(OpCodes.Dup));

                        yield return(Instruction.Create(OpCodes.Ldc_I4, i));

                        var field = stateMachineType.Fields.FirstOrDefault(x => x.Name.Equals(info.ParameterNames[i]));
                        if (field == null)
                        {
                            ModuleWeaver.LogError($"Parameter '{info.ParameterNames[i]}' is not available on the async state machine. Probably it has been optimized away by the compiler. Please update the format so it excludes this parameter.");

                            yield return(Instruction.Create(OpCodes.Ldnull));
                        }
                        else
                        {
                            yield return(Instruction.Create(OpCodes.Ldarg_0));

                            yield return(Instruction.Create(OpCodes.Ldfld, field));

                            if (field.FieldType.IsBoxingRequired(ModuleWeaver.ModuleDefinition.TypeSystem.Object))
                            {
                                yield return(Instruction.Create(OpCodes.Box, ModuleWeaver.ModuleDefinition.ImportReference(field.FieldType)));
                            }
                        }

                        yield return(Instruction.Create(OpCodes.Stelem_Ref));
                    }

                    yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.StringFormatWithArray));
                }
                else
                {
                    // Load null a string
                    yield return(Instruction.Create(OpCodes.Ldarg_0));

                    yield return(Instruction.Create(OpCodes.Ldnull));
                }

                yield return(Instruction.Create(OpCodes.Stfld, formattedFieldDefinition));
            }

            // Handle call to log method
            yield return(Instruction.Create(OpCodes.Ldtoken, methodDefinition));

            yield return(Instruction.Create(OpCodes.Ldtoken, methodDefinition.DeclaringType));

            yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.GetMethodFromHandle));

            yield return(Instruction.Create(OpCodes.Ldarg_0));

            yield return(Instruction.Create(OpCodes.Ldfld, stopwatchField));

            yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.ElapsedMilliseconds));

            yield return(Instruction.Create(OpCodes.Ldarg_0));

            yield return(Instruction.Create(OpCodes.Ldfld, formattedFieldDefinition));

            yield return(Instruction.Create(OpCodes.Call, logWithMessageMethod));
        }
        else if (logMethod != null)
        {
            yield return(Instruction.Create(OpCodes.Ldtoken, methodDefinition));

            yield return(Instruction.Create(OpCodes.Ldtoken, methodDefinition.DeclaringType));

            yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.GetMethodFromHandle));

            yield return(Instruction.Create(OpCodes.Ldarg_0));

            yield return(Instruction.Create(OpCodes.Ldfld, stopwatchField));

            yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.ElapsedMilliseconds));

            yield return(Instruction.Create(OpCodes.Call, logMethod));
        }
        else
        {
            yield return(Instruction.Create(OpCodes.Ldstr, methodDefinition.MethodName()));

            yield return(Instruction.Create(OpCodes.Ldarg_0));

            yield return(Instruction.Create(OpCodes.Ldfld, stopwatchField));

            yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.ElapsedMilliseconds));

            yield return(Instruction.Create(OpCodes.Box, ModuleWeaver.ModuleDefinition.TypeSystem.Int64));

            yield return(Instruction.Create(OpCodes.Ldstr, "ms"));

            yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.ConcatMethod));

            yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.TraceWriteLineMethod));
        }
    }
示例#6
0
    IEnumerable <Instruction> ProcessTimeAttribute(MethodDefinition methodDefinition, FieldDefinition formattedFieldDefinition)
    {
// Load everything for a string format
        var timeAttribute = methodDefinition.GetTimeAttribute();

        if (timeAttribute != null)
        {
            var value = timeAttribute.ConstructorArguments.FirstOrDefault().Value as string;
            if (!string.IsNullOrWhiteSpace(value))
            {
                // Note: no need to validate, already done in AssemblyProcessor::ProcessMethod
                var info = parameterFormattingProcessor.ParseParameterFormatting(value);

                yield return(Instruction.Create(OpCodes.Ldarg_0));

                yield return(Instruction.Create(OpCodes.Ldstr, info.Format));

                yield return(Instruction.Create(OpCodes.Ldc_I4, info.ParameterNames.Count));

                yield return(Instruction.Create(OpCodes.Newarr, ModuleWeaver.TypeSystem.ObjectReference));

                for (var i = 0; i < info.ParameterNames.Count; i++)
                {
                    var parameterName = info.ParameterNames[i];

                    yield return(Instruction.Create(OpCodes.Dup));

                    yield return(Instruction.Create(OpCodes.Ldc_I4, i));

                    if (string.Equals(parameterName, "this"))
                    {
                        // Field name is <>4__this
                        parameterName = "<>4__this";
                        if (!stateMachineType.Fields.Any(x => x.Name.Equals(parameterName)))
                        {
                            // {this} could be optimized away, let's add it for the user
                            InjectThisIntoStateMachine(methodDefinition);
                        }
                    }

                    var field = stateMachineType.Fields.FirstOrDefault(x => x.Name.Equals(parameterName));
                    if (field is null)
                    {
                        ModuleWeaver.LogError($"Parameter '{parameterName}' is not available on the async state machine. Probably it has been optimized away by the compiler. Please update the format so it excludes this parameter.");
                        yield break;
                    }
                    else
                    {
                        yield return(Instruction.Create(OpCodes.Ldarg_0));

                        yield return(Instruction.Create(OpCodes.Ldfld, field));

                        if (field.FieldType.IsBoxingRequired(ModuleWeaver.TypeSystem.ObjectReference))
                        {
                            yield return(Instruction.Create(OpCodes.Box, ModuleWeaver.ModuleDefinition.ImportReference(field.FieldType)));
                        }
                    }

                    yield return(Instruction.Create(OpCodes.Stelem_Ref));
                }

                yield return(Instruction.Create(OpCodes.Call, ModuleWeaver.StringFormatWithArray));
            }
            else
            {
                // Load null a string
                yield return(Instruction.Create(OpCodes.Ldarg_0));

                yield return(Instruction.Create(OpCodes.Ldnull));
            }

            yield return(Instruction.Create(OpCodes.Stfld, formattedFieldDefinition));
        }
    }