@@ -5,6 +5,8 @@ namespace Meziantou.Analyzer.Internals;
55
66internal sealed class CultureSensitiveFormattingContext ( Compilation compilation )
77{
8+ private readonly HashSet < ISymbol > _excludedMethods = CreateExcludedMethods ( compilation ) ;
9+
810 public INamedTypeSymbol ? CultureInsensitiveTypeAttributeSymbol { get ; } = compilation . GetBestTypeByMetadataName ( "Meziantou.Analyzer.Annotations.CultureInsensitiveTypeAttribute" ) ;
911 public INamedTypeSymbol ? FormatProviderSymbol { get ; } = compilation . GetBestTypeByMetadataName ( "System.IFormatProvider" ) ;
1012 public INamedTypeSymbol ? CultureInfoSymbol { get ; } = compilation . GetBestTypeByMetadataName ( "System.Globalization.CultureInfo" ) ;
@@ -24,6 +26,26 @@ internal sealed class CultureSensitiveFormattingContext(Compilation compilation)
2426 public INamedTypeSymbol ? SystemIFormattableSymbol { get ; } = compilation . GetBestTypeByMetadataName ( "System.IFormattable" ) ;
2527 public INamedTypeSymbol ? SystemWindowsFontStretchSymbol { get ; } = compilation . GetBestTypeByMetadataName ( "System.Windows.FontStretch" ) ;
2628 public INamedTypeSymbol ? SystemWindowsMediaBrushSymbol { get ; } = compilation . GetBestTypeByMetadataName ( "System.Windows.Media.Brush" ) ;
29+ public INamedTypeSymbol ? NuGetVersioningSemanticVersionSymbol { get ; } = compilation . GetBestTypeByMetadataName ( "NuGet.Versioning.SemanticVersion" ) ;
30+
31+ private static HashSet < ISymbol > CreateExcludedMethods ( Compilation compilation )
32+ {
33+ var result = new HashSet < ISymbol > ( SymbolEqualityComparer . Default ) ;
34+ AddDocumentationId ( result , compilation , "M:System.Convert.ToChar(System.String)" ) ;
35+ AddDocumentationId ( result , compilation , "M:System.Convert.ToChar(System.Object)" ) ;
36+ AddDocumentationId ( result , compilation , "M:System.Convert.ToBoolean(System.String)" ) ;
37+ AddDocumentationId ( result , compilation , "M:System.Convert.ToBoolean(System.Object)" ) ;
38+ return result ;
39+
40+ static void AddDocumentationId ( HashSet < ISymbol > result , Compilation compilation , string id )
41+ {
42+ foreach ( var item in DocumentationCommentId . GetSymbolsForDeclarationId ( id , compilation ) )
43+ {
44+ result . Add ( item ) ;
45+ }
46+ }
47+ }
48+
2749
2850 private static bool MustUnwrapNullableOfT ( CultureSensitiveOptions options )
2951 {
@@ -40,6 +62,9 @@ public bool IsCultureSensitiveOperation(IOperation operation, CultureSensitiveOp
4062
4163 if ( operation is IInvocationOperation invocation )
4264 {
65+ if ( _excludedMethods . Contains ( invocation . TargetMethod ) )
66+ return false ;
67+
4368 var methodName = invocation . TargetMethod . Name ;
4469 if ( methodName is "ToString" )
4570 {
@@ -49,7 +74,7 @@ public bool IsCultureSensitiveOperation(IOperation operation, CultureSensitiveOp
4974 {
5075 foreach ( var arg in invocation . Arguments )
5176 {
52- if ( arg . Value is { ConstantValue : { HasValue : true , Value : string } } )
77+ if ( arg . Value is { ConstantValue : { HasValue : true , Value : string } } or IConversionOperation { Type . SpecialType : SpecialType . System_String , ConstantValue : { HasValue : true , Value : null } } )
5378 {
5479 if ( format is not null )
5580 {
@@ -252,25 +277,31 @@ private bool IsCultureSensitiveType(ITypeSymbol? typeSymbol, CultureSensitiveOpt
252277 if ( typeSymbol . IsOrInheritFrom ( SystemWindowsMediaBrushSymbol ) )
253278 return false ;
254279
280+ if ( typeSymbol . IsOrInheritFrom ( NuGetVersioningSemanticVersionSymbol ) )
281+ return false ;
282+
255283 if ( ! typeSymbol . Implements ( SystemIFormattableSymbol ) )
256284 return false ;
257285
258- if ( ! IsCultureSensitiveTypeUsingAttribute ( typeSymbol , format : null ) )
286+ if ( ! IsCultureSensitiveTypeUsingAttribute ( typeSymbol , hasFormat : false , format : null ) )
259287 return false ;
260288
261289 return true ;
262290 }
263291
264- private bool IsCultureSensitiveTypeUsingAttribute ( ITypeSymbol typeSymbol , string ? format )
292+ private bool IsCultureSensitiveTypeUsingAttribute ( ITypeSymbol typeSymbol , bool hasFormat , string ? format )
265293 {
266294 var attributes = typeSymbol . GetAttributes ( CultureInsensitiveTypeAttributeSymbol ) ;
267295 foreach ( var attr in attributes )
268296 {
269297 if ( attr . ConstructorArguments . IsEmpty )
270298 return false ; // no format is set, so the type is culture insensitive
271299
272- var attrFormat = attr . ConstructorArguments [ 0 ] . Value ;
273- if ( attrFormat is null || ( attrFormat is string attrFormatValue && ( string . IsNullOrEmpty ( attrFormatValue ) || attrFormatValue == format ) ) )
300+ if ( ! hasFormat )
301+ continue ;
302+
303+ var attrFormat = attr . ConstructorArguments [ 0 ] . Value as string ;
304+ if ( attrFormat == format )
274305 return false ; // no format is set, so the type is culture insensitive
275306 }
276307
@@ -284,8 +315,11 @@ private bool IsCultureSensitiveTypeUsingAttribute(ITypeSymbol typeSymbol, string
284315 if ( attribute . ConstructorArguments . Length == 1 )
285316 return false ;
286317
287- var attrFormat = attribute . ConstructorArguments [ 1 ] . Value ;
288- if ( attrFormat is null || ( attrFormat is string attrFormatValue && ( string . IsNullOrEmpty ( attrFormatValue ) || attrFormatValue == format ) ) )
318+ if ( ! hasFormat )
319+ continue ;
320+
321+ var attrFormat = attribute . ConstructorArguments [ 1 ] . Value as string ;
322+ if ( attrFormat == format )
289323 return false ; // no format is set, so the type is culture insensitive
290324 }
291325 }
@@ -298,6 +332,7 @@ private bool IsCultureSensitiveType(ITypeSymbol? symbol, IOperation? format, IOp
298332 if ( ! IsCultureSensitiveType ( symbol , options ) )
299333 return false ;
300334
335+ var hasFormatString = format is { ConstantValue . HasValue : true } ;
301336 var formatString = format ? . ConstantValue . Value as string ;
302337
303338 if ( instance is not null )
@@ -320,7 +355,7 @@ private bool IsCultureSensitiveType(ITypeSymbol? symbol, IOperation? format, IOp
320355 return false ;
321356 }
322357
323- if ( symbol is not null && ! IsCultureSensitiveTypeUsingAttribute ( symbol , formatString ) )
358+ if ( symbol is not null && ! IsCultureSensitiveTypeUsingAttribute ( symbol , hasFormatString , formatString ) )
324359 return false ;
325360
326361 return true ;
0 commit comments