Пример #1
0
        public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
        {
            if (this.ProjectDirectory == null && context.Node is ClassDeclarationSyntax)
            {
                var templateFinder = new CloudFormationTemplateFinder(_fileManager, _directoryManager);
                this.ProjectDirectory = templateFinder.DetermineProjectRootDirectory(context.Node.SyntaxTree.FilePath);
            }

            // any method with at least one attribute is a candidate of function generation
            if (context.Node is MethodDeclarationSyntax methodDeclarationSyntax && methodDeclarationSyntax.AttributeLists.Count > 0)
            {
                // Get the symbol being declared by the method, and keep it if its annotated
                var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclarationSyntax);
                if (methodSymbol.GetAttributes().Any(attr => attr.AttributeClass.Name == nameof(LambdaFunctionAttribute)))
                {
                    LambdaMethods.Add(methodDeclarationSyntax);
                }
            }

            // any class with at least one attribute is a candidate of Startup class
            if (context.Node is ClassDeclarationSyntax classDeclarationSyntax && classDeclarationSyntax.AttributeLists.Count > 0)
            {
                // Get the symbol being declared by the class, and keep it if its annotated
                var methodSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax);
                if (methodSymbol.GetAttributes().Any(attr => attr.AttributeClass.Name == nameof(LambdaStartupAttribute)))
                {
                    StartupClasses.Add(classDeclarationSyntax);
                }
            }
        }
Пример #2
0
        public void Execute(GeneratorExecutionContext context)
        {
            var diagnosticReporter = new DiagnosticReporter(context);

            try
            {
                // retrieve the populated receiver
                if (!(context.SyntaxContextReceiver is SyntaxReceiver receiver))
                {
                    return;
                }

                // If no project directory was detected then skip the generator.
                // This is most likely to happen when the project is empty and doesn't have any classes in it yet.
                if (string.IsNullOrEmpty(receiver.ProjectDirectory))
                {
                    return;
                }

                var semanticModelProvider = new SemanticModelProvider(context);
                if (receiver.StartupClasses.Count > 1)
                {
                    foreach (var startup in receiver.StartupClasses)
                    {
                        // If there are more than one startup class, report them as errors
                        diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.MultipleStartupNotAllowed,
                                                                    Location.Create(startup.SyntaxTree, startup.Span),
                                                                    startup.SyntaxTree.FilePath));
                    }
                }

                var configureMethodModel = semanticModelProvider.GetConfigureMethodModel(receiver.StartupClasses.FirstOrDefault());

                var annotationReport = new AnnotationReport();

                var templateFinder = new CloudFormationTemplateFinder(_fileManager, _directoryManager);

                foreach (var lambdaMethod in receiver.LambdaMethods)
                {
                    var lambdaMethodModel = semanticModelProvider.GetMethodSemanticModel(lambdaMethod);

                    // Check for necessary references
                    if (lambdaMethodModel.HasAttribute(context, TypeFullNames.RestApiAttribute) ||
                        lambdaMethodModel.HasAttribute(context, TypeFullNames.HttpApiAttribute))
                    {
                        // Check for arbitrary type from "Amazon.Lambda.APIGatewayEvents"
                        if (context.Compilation.ReferencedAssemblyNames.FirstOrDefault(x => x.Name == "Amazon.Lambda.APIGatewayEvents") == null)
                        {
                            diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.MissingDependencies,
                                                                        lambdaMethod.GetLocation(),
                                                                        "Amazon.Lambda.APIGatewayEvents"));
                        }
                    }

                    var model = LambdaFunctionModelBuilder.Build(lambdaMethodModel, configureMethodModel, context);

                    // If there are more than one event, report them as errors
                    if (model.LambdaMethod.Events.Count > 1)
                    {
                        foreach (var attribute in lambdaMethodModel.GetAttributes().Where(attribute => TypeFullNames.Events.Contains(attribute.AttributeClass.ToDisplayString())))
                        {
                            diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.MultipleEventsNotSupported,
                                                                        Location.Create(attribute.ApplicationSyntaxReference.SyntaxTree, attribute.ApplicationSyntaxReference.Span),
                                                                        DiagnosticSeverity.Error));
                        }

                        // Skip multi-event lambda method from processing and check remaining lambda methods for diagnostics
                        continue;
                    }

                    var template   = new LambdaFunctionTemplate(model);
                    var sourceText = template.TransformText().ToEnvironmentLineEndings();
                    context.AddSource($"{model.GeneratedMethod.ContainingType.Name}.g.cs", SourceText.From(sourceText, Encoding.UTF8, SourceHashAlgorithm.Sha256));

                    // report every generated file to build output
                    diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.CodeGeneration, Location.None, $"{model.GeneratedMethod.ContainingType.Name}.g.cs", sourceText));

                    annotationReport.LambdaFunctions.Add(model);
                }

                // Run the CloudFormation sync if any LambdaMethods exists. Also run if no LambdaMethods exists but there is a
                // CloudFormation template in case orphaned functions in the template need to be removed.
                // Both checks are required because if there is no template but there are LambdaMethods the CF template the template will be created.
                if (receiver.LambdaMethods.Any() || templateFinder.DoesCloudFormationTemplateExist(receiver.ProjectDirectory))
                {
                    annotationReport.CloudFormationTemplatePath = templateFinder.FindCloudFormationTemplate(receiver.ProjectDirectory);
                    annotationReport.ProjectRootDirectory       = receiver.ProjectDirectory;
                    var cloudFormationJsonWriter = new CloudFormationJsonWriter(_fileManager, _directoryManager, _jsonWriter, diagnosticReporter);
                    cloudFormationJsonWriter.ApplyReport(annotationReport);
                }
            }
            catch (Exception e)
            {
                // this is a generator failure, report this as error
                diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.UnhandledException, Location.None, e.PrettyPrint()));
#if DEBUG
                throw;
#endif
            }
        }