From 853ba76b02466f672fc6a59fb10aea9e0c2cf9ae Mon Sep 17 00:00:00 2001 From: Heejae Chang Date: Tue, 10 Nov 2015 16:35:44 -0800 Subject: [PATCH] made more analyzer exception to include inner exceptions --- .../AnalyzerDriver/AnalyzerDriver.projitems | 1 + .../AnalyzerExceptionDescriptionBuilder.cs | 49 ++++++++++++++ .../Core/Portable/CodeAnalysis.csproj | 7 +- .../DiagnosticAnalyzer/AnalyzerExecutor.cs | 5 +- src/Compilers/Shared/CoreClrShim.cs | 4 +- src/Compilers/Shared/DesktopShim.cs | 26 ++++++++ .../Portable/Diagnostics/AnalyzerHelper.cs | 64 ++----------------- src/Features/Core/Portable/Features.csproj | 3 + 8 files changed, 93 insertions(+), 66 deletions(-) create mode 100644 src/Compilers/Core/AnalyzerDriver/AnalyzerExceptionDescriptionBuilder.cs create mode 100644 src/Compilers/Shared/DesktopShim.cs diff --git a/src/Compilers/Core/AnalyzerDriver/AnalyzerDriver.projitems b/src/Compilers/Core/AnalyzerDriver/AnalyzerDriver.projitems index 9dd0d4298e2..d0770e2fb56 100644 --- a/src/Compilers/Core/AnalyzerDriver/AnalyzerDriver.projitems +++ b/src/Compilers/Core/AnalyzerDriver/AnalyzerDriver.projitems @@ -9,6 +9,7 @@ AnalyzerDriver + diff --git a/src/Compilers/Core/AnalyzerDriver/AnalyzerExceptionDescriptionBuilder.cs b/src/Compilers/Core/AnalyzerDriver/AnalyzerExceptionDescriptionBuilder.cs new file mode 100644 index 00000000000..d1d5549927e --- /dev/null +++ b/src/Compilers/Core/AnalyzerDriver/AnalyzerExceptionDescriptionBuilder.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Diagnostics +{ + internal static class AnalyzerExceptionDescriptionBuilder + { + // Description separator + private static readonly string Separator = Environment.NewLine + "-----" + Environment.NewLine; + + public static string CreateDiagnosticDescription(this Exception exception) + { + var aggregateException = exception as AggregateException; + if (aggregateException != null) + { + var flattened = aggregateException.Flatten(); + return string.Join(Separator, flattened.InnerExceptions.Select(e => GetExceptionMessage(e))); + } + + if (exception != null) + { + return string.Join(Separator, GetExceptionMessage(exception), CreateDiagnosticDescription(exception.InnerException)); + } + + return string.Empty; + } + + private static string GetExceptionMessage(Exception exception) + { + var fileNotFoundException = exception as FileNotFoundException; + if (fileNotFoundException == null) + { + return exception.Message; + } + + var fusionLog = DesktopShim.FileNotFoundException.TryGetFusionLog(fileNotFoundException); + if (fusionLog == null) + { + return exception.Message; + } + + return string.Join(Separator, fileNotFoundException.Message, fusionLog); + } + } +} diff --git a/src/Compilers/Core/Portable/CodeAnalysis.csproj b/src/Compilers/Core/Portable/CodeAnalysis.csproj index 5a20f3445d9..7c246d69b22 100644 --- a/src/Compilers/Core/Portable/CodeAnalysis.csproj +++ b/src/Compilers/Core/Portable/CodeAnalysis.csproj @@ -41,7 +41,7 @@ pdbonly x64 prompt - + PreserveNewest @@ -56,6 +56,9 @@ CoreClrShim.cs + + DesktopShim.cs + @@ -761,4 +764,4 @@ - + \ No newline at end of file diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs index 2e691dbc1d9..2ce3caf1ccf 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs @@ -16,6 +16,7 @@ using CodeBlockAnalyzerStateData = Microsoft.CodeAnalysis.Diagnostics.AnalysisState.CodeBlockAnalyzerStateData; using DeclarationAnalyzerStateData = Microsoft.CodeAnalysis.Diagnostics.AnalysisState.DeclarationAnalyzerStateData; + namespace Microsoft.CodeAnalysis.Diagnostics { /// @@ -776,7 +777,7 @@ internal static Diagnostic CreateAnalyzerExceptionDiagnostic(DiagnosticAnalyzer var title = CodeAnalysisResources.CompilerAnalyzerFailure; var messageFormat = CodeAnalysisResources.CompilerAnalyzerThrows; var messageArguments = new[] { analyzerName, e.GetType().ToString(), e.Message }; - var description = string.Format(CodeAnalysisResources.CompilerAnalyzerThrowsDescription, analyzerName, e.ToString()); + var description = string.Format(CodeAnalysisResources.CompilerAnalyzerThrowsDescription, analyzerName, e.CreateDiagnosticDescription()); var descriptor = GetAnalyzerExceptionDiagnosticDescriptor(AnalyzerExceptionDiagnosticId, title, description, messageFormat); return Diagnostic.Create(descriptor, Location.None, messageArguments); } @@ -786,7 +787,7 @@ internal static Diagnostic CreateDriverExceptionDiagnostic(Exception e) var title = CodeAnalysisResources.AnalyzerDriverFailure; var messageFormat = CodeAnalysisResources.AnalyzerDriverThrows; var messageArguments = new[] { e.GetType().ToString(), e.Message }; - var description = string.Format(CodeAnalysisResources.AnalyzerDriverThrowsDescription, e.ToString()); + var description = string.Format(CodeAnalysisResources.AnalyzerDriverThrowsDescription, e.CreateDiagnosticDescription()); var descriptor = GetAnalyzerExceptionDiagnosticDescriptor(AnalyzerDriverExceptionDiagnosticId, title, description, messageFormat); return Diagnostic.Create(descriptor, Location.None, messageArguments); } diff --git a/src/Compilers/Shared/CoreClrShim.cs b/src/Compilers/Shared/CoreClrShim.cs index 8cacb35aa95..dae54abc965 100644 --- a/src/Compilers/Shared/CoreClrShim.cs +++ b/src/Compilers/Shared/CoreClrShim.cs @@ -13,13 +13,13 @@ namespace Roslyn.Utilities /// internal static class CoreClrShim { - + internal static class AssemblyLoadContext { internal static readonly Type Type = ReflectionUtilities.TryGetType( "System.Runtime.Loader.AssemblyLoadContext, System.Runtime.Loader, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); } - + internal static class CodePagesEncodingProvider { internal static readonly Type Type = ReflectionUtilities.TryGetType( diff --git a/src/Compilers/Shared/DesktopShim.cs b/src/Compilers/Shared/DesktopShim.cs new file mode 100644 index 00000000000..23ac20c2d8d --- /dev/null +++ b/src/Compilers/Shared/DesktopShim.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Reflection; +using System.Runtime.ExceptionServices; + +namespace Roslyn.Utilities +{ + /// + /// This is a bridge for APIs that are only available on CoreCLR or .NET 4.6 + /// and NOT on .NET 4.5. The compiler currently targets .NET 4.5 and CoreCLR + /// so this shim is necessary for switching on the dependent behavior. + /// + internal static class DesktopShim + { + internal static class FileNotFoundException + { + internal static readonly Type Type = ReflectionUtilities.TryGetType( + "System.IO.FileNotFoundException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); + + private static PropertyInfo s_fusionLog = Type?.GetTypeInfo().GetDeclaredProperty("FusionLog"); + + internal static string TryGetFusionLog(object obj) => s_fusionLog.GetValue(obj) as string; + } + } +} diff --git a/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs b/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs index fda759ecf52..5c5b48b23ec 100644 --- a/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs +++ b/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.IO; -using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis.ErrorReporting; using Roslyn.Utilities; @@ -35,9 +33,6 @@ internal static class AnalyzerHelper private const string AnalyzerExceptionDiagnosticCategory = "Intellisense"; - // Description separator - private static readonly string Separator = Environment.NewLine + "-----" + Environment.NewLine; - public static bool IsBuiltInAnalyzer(this DiagnosticAnalyzer analyzer) { return analyzer is IBuiltInAnalyzer || analyzer is DocumentDiagnosticAnalyzer || analyzer is ProjectDiagnosticAnalyzer || analyzer.IsCompilerAnalyzer(); @@ -127,7 +122,7 @@ internal static Diagnostic CreateAnalyzerExceptionDiagnostic(DiagnosticAnalyzer var descriptor = new DiagnosticDescriptor(AnalyzerExceptionDiagnosticId, title: FeaturesResources.UserDiagnosticAnalyzerFailure, messageFormat: FeaturesResources.UserDiagnosticAnalyzerThrows, - description: string.Format(FeaturesResources.UserDiagnosticAnalyzerThrowsDescription, analyzerName, e.ToString()), + description: string.Format(FeaturesResources.UserDiagnosticAnalyzerThrowsDescription, analyzerName, e.CreateDiagnosticDescription()), category: AnalyzerExceptionDiagnosticCategory, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, @@ -183,19 +178,19 @@ public static DiagnosticData CreateAnalyzerLoadFailureDiagnostic(string fullPath id = Choose(language, WRN_UnableToLoadAnalyzerId, WRN_UnableToLoadAnalyzerIdCS, WRN_UnableToLoadAnalyzerIdVB); messageFormat = FeaturesResources.WRN_UnableToLoadAnalyzer; message = string.Format(FeaturesResources.WRN_UnableToLoadAnalyzer, fullPath, e.Message); - description = CreateDescription(e.Exception); + description = e.Exception.CreateDiagnosticDescription(); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.UnableToCreateAnalyzer: id = Choose(language, WRN_AnalyzerCannotBeCreatedId, WRN_AnalyzerCannotBeCreatedIdCS, WRN_AnalyzerCannotBeCreatedIdVB); messageFormat = FeaturesResources.WRN_AnalyzerCannotBeCreated; message = string.Format(FeaturesResources.WRN_AnalyzerCannotBeCreated, e.TypeName, fullPath, e.Message); - description = CreateDescription(e.Exception); + description = e.Exception.CreateDiagnosticDescription(); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.NoAnalyzers: id = Choose(language, WRN_NoAnalyzerInAssemblyId, WRN_NoAnalyzerInAssemblyIdCS, WRN_NoAnalyzerInAssemblyIdVB); messageFormat = FeaturesResources.WRN_NoAnalyzerInAssembly; message = string.Format(FeaturesResources.WRN_NoAnalyzerInAssembly, fullPath); - description = CreateDescription(e.Exception); + description = e.Exception.CreateDiagnosticDescription(); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.None: default: @@ -209,57 +204,6 @@ public static DiagnosticData CreateAnalyzerLoadFailureDiagnostic(string fullPath return true; } - private static string CreateDescription(Exception exception) - { - var aggregateException = exception as AggregateException; - if (aggregateException != null) - { - var flattened = aggregateException.Flatten(); - return string.Join(Separator, flattened.InnerExceptions.Select(e => GetExceptionMessage(e))); - } - - if (exception != null) - { - return string.Join(Separator, GetExceptionMessage(exception), CreateDescription(exception.InnerException)); - } - - return string.Empty; - } - - private static string GetExceptionMessage(Exception exception) - { - var fileNotFoundException = exception as FileNotFoundException; - if (fileNotFoundException == null) - { - return exception.Message; - } - - var fusionLog = GetFusionLogIfPossible(fileNotFoundException); - if (fusionLog == null) - { - return exception.Message; - } - - return string.Join(Separator, fileNotFoundException.Message, fusionLog); - } - - private static string GetFusionLogIfPossible(FileNotFoundException exception) - { - try - { - // since Feature is in portable layer, I am using reflection here. so that we can get - // most detail info on desktop when analyzer is failed to load. otherwise, we either - // don't put this information or need to do quite complex plumbing for quite simple thing - // that is not in hot path. - var info = exception.GetType().GetRuntimeProperty("FusionLog"); - return info.GetValue(exception) as string; - } - catch - { - return null; - } - } - private static string Choose(string language, string noLanguageMessage, string csharpMessage, string vbMessage) { if (language == null) diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index b21080663d4..feffa8bfcdd 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -71,6 +71,9 @@ + + Shared\Utilities\DesktopShim.cs + -- GitLab