Пример #1
0
 public void Write(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer)
 {
     foreach (var frame in this)
     {
         frame.GenerateCode(variables, method, writer);
     }
 }
Пример #2
0
        /// <summary>
        /// Generates the code required by this <see cref="Frame"/>, delegating the responsibility to the
        /// abstract method <see cref="Generate" />.
        /// </summary>
        /// <remarks>
        /// This method will store the parameters and the current <see cref="ISourceWriter.IndentationLevel" /> inside
        /// of this <see cref="Frame" /> for later referencing.
        /// </remarks>
        /// <param name="variables">A source of variable for a method, from which to grab any <see cref="Variable"/>s that this
        ///     frame needs but does not create.</param>
        /// <param name="method">The method this <see cref="Frame"/> belongs to.</param>
        /// <param name="writer">Where to write the code to.</param>
        public void GenerateCode(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer)
        {
            this.BlockLevel = writer.IndentationLevel;

            this._variables = variables;
            this._method    = method;
            this._writer    = writer;

            method.RegisterFrame(this);

            this.Generate(new MethodVariableUsageRecorder(variables, this._uses), method, writer, this.Next);
        }
 protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
 {
     writer.WriteLine("return Task.FromResult(5);");
 }
Пример #4
0
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            var context     = variables.FindVariable(typeof(ApiOperationContext));
            var currentSpan = context.GetProperty(nameof(ApiOperationContext.ApmSpan));

            writer.WriteLine($"{currentSpan}?.{nameof(IApmSpan.RecordException)}({this._exceptionVariable});");
        }
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                var stopwatchVariable = variables.FindVariable(typeof(Stopwatch));

                writer.WriteLine($"{stopwatchVariable}.Stop();");

                writer.Write(
                    LogFrame.Information(
                        _operationFinishedLogEvent,
                        "Operation {OperationName} finished in {TotalMilliseconds}ms",
                        ReflectionUtilities.PrettyTypeName(this._operationType),
                        stopwatchVariable.GetProperty(nameof(Stopwatch.Elapsed)).GetProperty(nameof(TimeSpan.TotalMilliseconds))));
            }
Пример #6
0
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            var parameters = this.Ctor.GetParameters();

            for (var i = 0; i < parameters.Length; i++)
            {
                if (this.Parameters[i] == null)
                {
                    var parameter = parameters[i];
                    this.Parameters[i] = variables.FindVariable(parameter.ParameterType);
                }
            }

            foreach (var setter in this.Setters)
            {
                setter.FindVariable(variables);
            }

            switch (this.Mode)
            {
            case ConstructorCallMode.Variable:
                writer.WriteLine(this.Declaration() + ";");
                this.ActivatorFrames.Write(variables, method, writer);

                next();
                break;

            case ConstructorCallMode.ReturnValue:
                if (this.ActivatorFrames.Any())
                {
                    writer.WriteLine(this.Declaration() + ";");
                    this.ActivatorFrames.Write(variables, method, writer);

                    writer.WriteLine($"return {this.Variable};");
                    next();
                }
                else
                {
                    writer.WriteLine($"return {this.Invocation()};");
                    next();
                }

                break;

            case ConstructorCallMode.UsingNestedVariable:
                writer.Using(this.Declaration(), w =>
                {
                    this.ActivatorFrames.Write(variables, method, writer);

                    next();
                });
                break;
            }
        }
Пример #7
0
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            if (this._inner.Count > 1)
            {
                for (var i = 1; i < this._inner.Count; i++)
                {
                    this._inner[i - 1].NextFrame = this._inner[i];
                }
            }

            this.GenerateCode(variables, method, writer, this._inner[0]);

            next();
        }
Пример #8
0
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            // Note that we cannot just get a variable of type IApmSpan as _we_ create one, which causes a loop and failed compilation
            var context     = variables.FindVariable(typeof(ApiOperationContext));
            var currentSpan = context.GetProperty(nameof(ApiOperationContext.ApmSpan));

            writer.WriteLine($"using var {this._spanVariable} = {currentSpan}.{nameof(IApmSpan.StartSpan)}(\"{this._spanKind}\", \"{this._operationName}\", \"{this._type}\");");

            next();
        }
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            var serviceProviderVariable = variables.FindVariable(typeof(IServiceProvider));

            // We import this namespace to allow using extension method invocation, which cleans up the
            // generated code quite a bit for this use case.
            method.GeneratedType.Namespaces.Add(typeof(ServiceProviderServiceExtensions).Namespace);

            writer.WriteLine(
                $"var {this.InstanceVariable} = {serviceProviderVariable}.{nameof(ServiceProviderServiceExtensions.GetRequiredService)}<{this._constructedType.FullNameInCode()}>();");

            next();
        }
Пример #10
0
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            writer.WriteLine(this.ToString());

            next();
        }
Пример #11
0
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            var number = variables.FindVariable(typeof(int));

            writer.WriteLine($"return {number.Usage} + 2;");
        }
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            var context          = variables.FindVariable(typeof(ApiOperationContext));
            var activityVariable = context.GetProperty(nameof(ApiOperationContext.Activity));

            writer.If($"{this._exceptionVariable} is {typeof(ApiException).FullNameInCode()} apiException && apiException.{nameof(ApiException.HttpStatus)} < 500");
            writer.Write(LogFrame.Information(this._exceptionVariable, "A non-critical ApiException has occurred with message {ExceptionMessage}", this._exceptionVariable.GetProperty(nameof(Exception.Message))));
            writer.Write(new ActivityStatusFrame(activityVariable, Status.Ok));
            writer.FinishBlock();

            writer.Else();
            writer.WriteLine($"{typeof(BlueprintActivitySource).FullNameInCode()}.{nameof(BlueprintActivitySource.RecordException)}({activityVariable}, {this._exceptionVariable}, {this._escaped.ToString().ToLowerInvariant()});");
            writer.Write(LogFrame.Error(this._exceptionVariable, "An unhandled exception has occurred with message {ExceptionMessage}", this._exceptionVariable.GetProperty(nameof(Exception.Message))));
            writer.Write(new ActivityStatusFrame(activityVariable, Status.Error));
            writer.FinishBlock();
        }
Пример #13
0
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                writer.Comment(nameof(SourceFrame));

                next();
            }
Пример #14
0
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                var handlerFromSource = variables.FindVariable(typeof(IHandler));

                writer.Comment(nameof(CustomFrame));

                next();
            }
Пример #15
0
        /// <inheritdoc/>
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            if (this._predicate(variables, method))
            {
                foreach (var f in this._childFrames)
                {
                    writer.Write(f);
                }
            }

            next();
        }
Пример #16
0
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            writer.If($"{this._activityVariable} != null");
            writer.WriteLine($"{typeof(ActivityExtensions).FullNameInCode()}.{nameof(ActivityExtensions.SetStatus)}({this._activityVariable}, {this._statusVariableVariable});");
            writer.FinishBlock();

            next();
        }
Пример #17
0
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            writer.BlankLine();

            next();
        }
Пример #18
0
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                writer.WriteLine(
                    $"var {this._operationVariable} = ({this._operationVariable.VariableType.FullNameInCode()}) {this._operationContextVariable.GetProperty(nameof(ApiOperationContext.Operation))};");

                next();
            }
Пример #19
0
 /// <inheritdoc />
 protected override void GenerateCode(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Frame inner)
 {
     writer.Block($"if ({this._condition})");
     inner.GenerateCode(variables, method, writer);
     writer.FinishBlock();
 }
Пример #20
0
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            if (this.ReturnedVariable == null && this._returnType != null)
            {
                this.ReturnedVariable = variables.TryFindVariable(this._returnType);
            }

            if (this.ReturnedVariable == null)
            {
                writer.WriteLine("return;");
            }
            else
            {
                var variableIsTask    = this.ReturnedVariable.VariableType.IsGenericType && this.ReturnedVariable.VariableType.GetGenericTypeDefinition() == typeof(Task <>);
                var methodReturnsTask = method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task <>);

                // This method does not use async/await but _does_ return Task, but the variable to return is _not_ a Task<>, therefore we
                // need to use Task.FromResult to get the correct return type
                if (method.AsyncMode == AsyncMode.None && methodReturnsTask && !variableIsTask)
                {
                    // What type are we expecting to return?
                    var taskValueType = method.ReturnType.GenericTypeArguments[0];

                    writer.WriteLine(
                        $"return {typeof(Task).FullNameInCode()}.{nameof(Task.FromResult)}(({taskValueType.FullNameInCode()}){this.ReturnedVariable});");
                }
                else
                {
                    writer.WriteLine($"return {this.ReturnedVariable};");
                }
            }
        }
Пример #21
0
            /// <inheritdoc />
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                writer.WriteLine($"{this._spanVariable}.{nameof(IApmSpan.Dispose)}();");

                next();
            }
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                var operationResultName = typeof(OperationResult).FullNameInCode();

                if (typeof(OperationResult).IsAssignableFrom(this._resultVariable.VariableType))
                {
                    // If the declared type is already a type of OperationResult we can eliminate the ternary operator check and
                    // immediately assign to the operationResult variable
                    writer.WriteLine($"{operationResultName} {this._operationResultVariable} = {this._resultVariable};");
                }
                else if (this._resultVariable.VariableType.IsAssignableFrom(typeof(OperationResult)))
                {
                    // If the variable type _could_ be an OperationResult then we use a ternary operator to check whether it
                    // actually is, and either use it directly or wrap in an OkResult
                    var okResultName = typeof(OkResult).FullNameInCode();

                    writer.WriteLine($"{operationResultName} {this._operationResultVariable} = {this._resultVariable} is {operationResultName} r ? " +
                                     "r : " +
                                     $"new {okResultName}({this._resultVariable});");
                }
                else
                {
                    // The type is NOT related to OperationResult at all, so we always create a wrapping OkResult
                    var okResultName = typeof(OkResult).FullNameInCode();

                    writer.WriteLine($"{operationResultName} {this._operationResultVariable} = new {okResultName}({this._resultVariable});");
                }

                next();
            }
Пример #23
0
 protected abstract void GenerateCode(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Frame inner);
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                var apiOperationContextVariable = variables.FindVariable(typeof(ApiOperationContext));
                var spanVariable = apiOperationContextVariable.GetProperty(nameof(ApiOperationContext.ApmSpan));

                // It is possible that no span exists
                writer.If($"{spanVariable} != null");

                // We set user data as tags. Individual APM tools may wish to react accordingly to these tags if there is some specific
                // location user details need to be stored.
                writer.WriteLine($"var userContext = {apiOperationContextVariable}.{nameof(ApiOperationContext.UserAuthorisationContext)};");

                writer.If($"userContext != null && userContext.{nameof(IUserAuthorisationContext.IsAnonymous)} == false");
                writer.WriteLine($"{spanVariable}.SetTag(\"user.id\", userContext.{nameof(IUserAuthorisationContext.Id)});");
                writer.WriteLine($"{spanVariable}.SetTag(\"user.account_id\", userContext.{nameof(IUserAuthorisationContext.AccountId)});");
                writer.FinishBlock();

                writer.FinishBlock();
            }
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                writer.WriteLine($"var {this._stopwatchVariable} = {typeof(Stopwatch).FullNameInCode()}.{nameof(Stopwatch.StartNew)}();");

                next();
            }
Пример #26
0
        /// <inheritdoc />
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            writer.Block("try");
            next();
            writer.FinishBlock();

            foreach (var handler in this._context.ExceptionHandlers.OrderBy(k => k.Key, new CatchClauseComparer()))
            {
                writer.Block($"catch ({handler.Key.FullNameInCode()} e)");

                // Key == exception type being caught
                var exceptionVariable = new Variable(handler.Key, "e");
                var allFrames         = handler.Value.SelectMany(v => v(exceptionVariable)).ToList();

                foreach (var frame in allFrames)
                {
                    frame.GenerateCode(variables, method, writer);
                }

                writer.FinishBlock();
            }

            if (this._context.FinallyFrames.Any())
            {
                writer.Block("finally");

                foreach (var frame in this._context.FinallyFrames)
                {
                    frame.GenerateCode(variables, method, writer);
                }

                writer.FinishBlock();
            }
        }
Пример #27
0
        protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
        {
            var one = variables.FindVariable(typeof(int));

            writer.WriteLine($"return {one} * {one};");
        }
            /// <inheritdoc />
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                var apiOperationContextVariable = variables.FindVariable(typeof(ApiOperationContext));
                var activityVariable            = apiOperationContextVariable.GetProperty(nameof(ApiOperationContext.Activity));

                var operationTypeKey = ReflectionUtilities.PrettyTypeName(this._context.Descriptor.OperationType);

                writer.BlankLine();

                // 2. For every property of the operation output a value to the exception.Data dictionary. All properties that are
                // not considered sensitive
                foreach (var prop in this._context.Descriptor.Properties)
                {
                    if (SensitiveProperties.IsSensitive(prop))
                    {
                        continue;
                    }

                    // Only support, for now, primitive values, strings and GUIDs to avoid pushing complex types as tags
                    if (!prop.PropertyType.IsPrimitive &&
                        !prop.PropertyType.IsEnum &&
                        prop.PropertyType.GetNonNullableType() != typeof(string) &&
                        prop.PropertyType.GetNonNullableType() != typeof(Guid))
                    {
                        continue;
                    }

                    writer.WriteLine(
                        $"{activityVariable}?.{nameof(Activity.SetTag)}(\"{operationTypeKey}.{prop.Name}\", {variables.FindVariable(this._context.Descriptor.OperationType)}.{prop.Name});");
                }

                next();
            }
Пример #29
0
            protected override void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next)
            {
                var contextVariable = variables.FindVariable(typeof(ApiOperationContext));

                this.LoopAttributes(
                    variables,
                    writer,
                    $"{nameof(BlueprintValidationAttribute.GetValidationResultAsync)}({this.Property.PropertyValueVariable}, \"{this.Property.PropertyInfoVariable.Property.Name}\", {contextVariable})");

                next();
            }
Пример #30
0
 /// <summary>
 /// Implements the actual generation of the code for this <see cref="Frame" />, writing to
 /// the given <see cref="ISourceWriter" />.
 /// </summary>
 /// <remarks>
 /// <para>
 /// The <see cref="GeneratedMethod" /> given is the same as <see cref="_method" />, but is provided as
 /// a convenience parameter to make it more obvious it's available.
 /// </para>
 /// <para>
 /// The <see cref="ISourceWriter" /> given is the same as <see cref="_writer" />, but is provided as
 /// a convenience parameter to make it more obvious it's available.
 /// </para>
 /// <para>
 /// Frames <em>should</em> typically call <paramref name="next" /> to insert code from the next frame. If they
 /// do not then no further code is executed and this <see cref="Frame" /> therefore becomes the last frame
 /// of the method.
 /// </para>
 /// </remarks>
 /// <param name="variables">A source of variables, used to grab from other frames / <see cref="IVariableSource"/>s the
 ///     variables needed to generate the code.</param>
 /// <param name="method">The method to which this <see cref="Frame" /> belongs.</param>
 /// <param name="writer">The writer to write code to.</param>
 /// <param name="next">The action to call to write the next frame (equivalent to calling <see cref="Next"/> directly).</param>
 protected abstract void Generate(IMethodVariables variables, GeneratedMethod method, IMethodSourceWriter writer, Action next);