11using System ;
22using System . Reflection ;
3+ using System . Threading ;
34using Microsoft . CodeAnalysis ;
45
56namespace ICSharpCode . CodeConverter . Shared
67{
78 internal static class RoslynCrashPreventer
89 {
9- private static object _exchangeLock = new object ( ) ;
10+ private static readonly object _exchangeLock = new object ( ) ;
11+ private static volatile int _currentUses ;
12+ private static Action < Exception > _codeAnalysisErrorHandler ;
13+ private static Action < Exception > _errorReportingErrorHandler ;
1014
1115 /// <summary>
1216 /// Use this to stop the library exiting the process without telling us.
@@ -21,33 +25,53 @@ internal static class RoslynCrashPreventer
2125 /// </remarks>
2226 public static IDisposable Create ( Action < Exception > logError )
2327 {
24- var FirstHandlerContainingType = ( typeof ( Compilation ) . Assembly , "Microsoft.CodeAnalysis.FatalError" ) ;
25- var SecondHandlerContainingType = ( typeof ( WorkspaceDiagnostic ) . Assembly , "Microsoft.CodeAnalysis.ErrorReporting.FatalError" ) ;
26-
27- var codeAnalysisErrorHandler = ExchangeFatalErrorHandler ( logError , FirstHandlerContainingType ) ;
28- var codeAnalysisErrorReportingErrorHandler = ExchangeFatalErrorHandler ( logError , SecondHandlerContainingType ) ;
29- return new ActionDisposable ( ( ) => {
30- ExchangeFatalErrorHandler ( codeAnalysisErrorHandler , FirstHandlerContainingType ) ;
31- ExchangeFatalErrorHandler ( codeAnalysisErrorReportingErrorHandler , SecondHandlerContainingType ) ;
32- } ) ;
28+ var codeAnalysisAssembly = ( typeof ( Compilation ) . Assembly , "Microsoft.CodeAnalysis.FatalError" ) ;
29+ var errorReportingAssembly = ( typeof ( WorkspaceDiagnostic ) . Assembly , "Microsoft.CodeAnalysis.ErrorReporting.FatalError" ) ;
30+
31+ TryExchangeHandler ( WrappedCodeAnalysisErrorHandler ( logError ) , codeAnalysisAssembly , ref _codeAnalysisErrorHandler ) ;
32+ TryExchangeHandler ( WrappedErrorReportingHandler ( logError ) , errorReportingAssembly , ref _errorReportingErrorHandler ) ;
33+
34+ Interlocked . Increment ( ref _currentUses ) ;
35+ return new ActionDisposable ( ( ) => Interlocked . Decrement ( ref _currentUses ) ) ;
36+ }
37+
38+ private static void TryExchangeHandler ( Action < Exception > logError , ( Assembly Assembly , string ) handlerContainer , ref Action < Exception > originalHandler )
39+ {
40+ if ( originalHandler != null || logError == null ) return ;
41+ lock ( _exchangeLock ) {
42+ originalHandler ??= ExchangeFatalErrorHandler ( logError , handlerContainer ) ;
43+ }
3344 }
3445
35- private static Action < Exception > ExchangeFatalErrorHandler ( Action < Exception > errorHandler , ( Assembly assembly , string containingType ) container , Action < Exception > errorHanderToReplace = null )
46+ private static Action < Exception > ExchangeFatalErrorHandler ( Action < Exception > errorHandler , ( Assembly assembly , string containingType ) container )
3647 {
37- if ( errorHandler == null ) return null ;
3848 try {
3949 var fataErrorType = container . assembly . GetType ( container . containingType ) ;
4050 var fatalHandlerField = fataErrorType . GetField ( "s_fatalHandler" , BindingFlags . NonPublic | BindingFlags . Static ) ;
41- lock ( _exchangeLock ) {
42- var originalHandler = ( Action < Exception > ) fatalHandlerField . GetValue ( null ) ;
43- if ( originalHandler != null && errorHanderToReplace == null || originalHandler == errorHanderToReplace ) {
44- fatalHandlerField . SetValue ( null , errorHandler ) ;
45- }
46- return originalHandler ;
51+ var originalHandler = ( Action < Exception > ) fatalHandlerField . GetValue ( null ) ;
52+ if ( originalHandler != null ) {
53+ fatalHandlerField . SetValue ( null , errorHandler ) ;
4754 }
55+ return originalHandler ;
4856 } catch ( Exception ) {
4957 return null ;
5058 }
5159 }
60+
61+ private static Action < Exception > WrappedCodeAnalysisErrorHandler ( Action < Exception > errorHandler ) => e => {
62+ if ( _currentUses > 0 ) {
63+ errorHandler ( e ) ;
64+ } else {
65+ _codeAnalysisErrorHandler ( e ) ;
66+ }
67+ } ;
68+
69+ private static Action < Exception > WrappedErrorReportingHandler ( Action < Exception > errorHandler ) => e => {
70+ if ( _currentUses > 0 ) {
71+ errorHandler ( e ) ;
72+ } else {
73+ _errorReportingErrorHandler ( e ) ;
74+ }
75+ } ;
5276 }
5377}
0 commit comments