public bool TryGetLoaderFromProjectPath(string projectFilePath, DiagnosticReportingMode mode, out IProjectFileLoader loader) { using (_dataGuard.DisposableWait()) { var extension = Path.GetExtension(projectFilePath); if (extension.Length > 0 && extension[0] == '.') { extension = extension.Substring(1); } if (_extensionToLanguageMap.TryGetValue(extension, out var language)) { if (_workspace.Services.SupportedLanguages.Contains(language)) { loader = _workspace.Services.GetLanguageServices(language).GetService <IProjectFileLoader>(); } else { loader = null; _diagnosticReporter.Report(mode, string.Format(WorkspacesResources.Cannot_open_project_0_because_the_language_1_is_not_supported, projectFilePath, language)); return(false); } } else { loader = ProjectFileLoader.GetLoaderForProjectFileExtension(_workspace, extension); if (loader == null) { _diagnosticReporter.Report(mode, string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projectFilePath, Path.GetExtension(projectFilePath))); return(false); } } // since we have both C# and VB loaders in this same library, it no longer indicates whether we have full language support available. if (loader != null) { language = loader.Language; // check for command line parser existing... if not then error. var commandLineParser = _workspace.Services .GetLanguageServices(language) .GetService <ICommandLineParserService>(); if (commandLineParser == null) { loader = null; _diagnosticReporter.Report(mode, string.Format(WorkspacesResources.Cannot_open_project_0_because_the_language_1_is_not_supported, projectFilePath, language)); return(false); } } return(loader != null); } }
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 } }