| File: CompilationFailedExceptionFactory.cs | Web Access |
| Project: src\aspnetcore\src\Mvc\Mvc.Razor.RuntimeCompilation\src\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.csproj (Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; namespace Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; internal static class CompilationFailedExceptionFactory { // error CS0234: The type or namespace name 'C' does not exist in the namespace 'N' (are you missing // an assembly reference?) private const string CS0234 = nameof(CS0234); // error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive // or an assembly reference?) private const string CS0246 = nameof(CS0246); public static CompilationFailedException Create( RazorCodeDocument codeDocument, IEnumerable<RazorDiagnostic> diagnostics) { // If a SourceLocation does not specify a file path, assume it is produced from parsing the current file. var messageGroups = diagnostics.GroupBy( razorError => razorError.Span.FilePath ?? codeDocument.Source.FilePath, StringComparer.Ordinal); var failures = new List<CompilationFailure>(); foreach (var group in messageGroups) { var filePath = group.Key; var fileContent = ReadContent(codeDocument, filePath); var compilationFailure = new CompilationFailure( filePath, fileContent, compiledContent: string.Empty, messages: group.Select(parserError => CreateDiagnosticMessage(parserError, filePath))); failures.Add(compilationFailure); } return new CompilationFailedException(failures); } public static CompilationFailedException Create( RazorCodeDocument codeDocument, string compilationContent, string assemblyName, IEnumerable<Diagnostic> diagnostics) { var diagnosticGroups = diagnostics .Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error) .GroupBy(diagnostic => GetFilePath(codeDocument, diagnostic), StringComparer.Ordinal); var failures = new List<CompilationFailure>(); foreach (var group in diagnosticGroups) { var sourceFilePath = group.Key; string sourceFileContent; if (string.Equals(assemblyName, sourceFilePath, StringComparison.Ordinal)) { // The error is in the generated code and does not have a mapping line pragma sourceFileContent = compilationContent; sourceFilePath = Resources.GeneratedCodeFileName; } else { sourceFileContent = ReadContent(codeDocument, sourceFilePath); } string? additionalMessage = null; if (group.Any(g => string.Equals(CS0234, g.Id, StringComparison.OrdinalIgnoreCase) || string.Equals(CS0246, g.Id, StringComparison.OrdinalIgnoreCase))) { additionalMessage = Resources.FormatCompilation_MissingReferences( "CopyRefAssembliesToPublishDirectory"); } var compilationFailure = new CompilationFailure( sourceFilePath, sourceFileContent, compilationContent, group.Select(GetDiagnosticMessage), additionalMessage); failures.Add(compilationFailure); } return new CompilationFailedException(failures); } private static string ReadContent(RazorCodeDocument codeDocument, string filePath) { RazorSourceDocument? sourceDocument; if (string.IsNullOrEmpty(filePath) || string.Equals(codeDocument.Source.FilePath, filePath, StringComparison.Ordinal)) { sourceDocument = codeDocument.Source; } else { sourceDocument = codeDocument.Imports.FirstOrDefault(f => string.Equals(f.FilePath, filePath, StringComparison.Ordinal)); } if (sourceDocument != null) { var contentChars = new char[sourceDocument.Length]; sourceDocument.CopyTo(0, contentChars, 0, sourceDocument.Length); return new string(contentChars); } return string.Empty; } private static DiagnosticMessage GetDiagnosticMessage(Diagnostic diagnostic) { var mappedLineSpan = diagnostic.Location.GetMappedLineSpan(); return new DiagnosticMessage( diagnostic.GetMessage(CultureInfo.CurrentCulture), CSharpDiagnosticFormatter.Instance.Format(diagnostic, CultureInfo.CurrentCulture), mappedLineSpan.Path, mappedLineSpan.StartLinePosition.Line + 1, mappedLineSpan.StartLinePosition.Character + 1, mappedLineSpan.EndLinePosition.Line + 1, mappedLineSpan.EndLinePosition.Character + 1); } private static DiagnosticMessage CreateDiagnosticMessage( RazorDiagnostic razorDiagnostic, string filePath) { var sourceSpan = razorDiagnostic.Span; var message = razorDiagnostic.GetMessage(CultureInfo.CurrentCulture); return new DiagnosticMessage( message: message, formattedMessage: razorDiagnostic.ToString(), filePath: filePath, startLine: sourceSpan.LineIndex + 1, startColumn: sourceSpan.CharacterIndex, endLine: sourceSpan.LineIndex + 1, endColumn: sourceSpan.CharacterIndex + sourceSpan.Length); } private static string GetFilePath(RazorCodeDocument codeDocument, Diagnostic diagnostic) { if (diagnostic.Location == Location.None) { return codeDocument.Source.FilePath; } return diagnostic.Location.GetMappedLineSpan().Path; } }