1- namespace BitMono . Core . Analyzing ;
1+ using System . Text . RegularExpressions ;
2+
3+ namespace BitMono . Core . Analyzing ;
24
3- [ SuppressMessage ( "ReSharper" , "InvertIf" ) ]
45public class CriticalBaseTypesCriticalAnalyzer : ICriticalAnalyzer < TypeDefinition >
56{
67 private readonly CriticalsSettings _criticalsSettings ;
@@ -12,19 +13,68 @@ public CriticalBaseTypesCriticalAnalyzer(IOptions<CriticalsSettings> criticals)
1213
1314 public bool NotCriticalToMakeChanges ( TypeDefinition type )
1415 {
15- if ( _criticalsSettings . UseCriticalBaseTypes == false )
16+ if ( ! _criticalsSettings . UseCriticalBaseTypes )
1617 {
1718 return true ;
1819 }
19- if ( type . HasBaseType ( ) )
20+ foreach ( string ancestorFullName in YieldAncestors ( type ) )
2021 {
21- var criticalBaseTypes = _criticalsSettings . CriticalBaseTypes ! ;
22- var typeBaseTypeName = type . BaseType ? . Name ? . Value . Split ( '`' ) [ 0 ] ?? string . Empty ;
23- if ( criticalBaseTypes . FirstOrDefault ( c => c . StartsWith ( typeBaseTypeName ) ) != null )
22+ if ( IsCriticalBaseType ( ancestorFullName ) )
2423 {
2524 return false ;
2625 }
2726 }
2827 return true ;
2928 }
29+
30+ private bool IsCriticalBaseType ( string ancestorFullName )
31+ {
32+ ancestorFullName = StripGenerics ( ancestorFullName ) ;
33+ foreach ( string criticalBaseType in _criticalsSettings . CriticalBaseTypes )
34+ {
35+ bool matches ;
36+ if ( criticalBaseType . Contains ( '*' ) )
37+ {
38+ string regex = "^" + Regex . Escape ( criticalBaseType ) . Replace ( @"\*" , ".*" ) + "$" ;
39+ matches = Regex . IsMatch ( ancestorFullName , regex ) ;
40+ }
41+ else
42+ {
43+ matches = criticalBaseType == ancestorFullName ;
44+ }
45+ if ( matches )
46+ {
47+ return true ;
48+ }
49+ }
50+ return false ;
51+ }
52+
53+ private static string StripGenerics ( string fullName )
54+ {
55+ int genericDelimeterIndex = fullName . IndexOf ( '`' ) ;
56+ if ( genericDelimeterIndex == - 1 )
57+ {
58+ return fullName ;
59+ }
60+ return fullName [ ..genericDelimeterIndex ] ;
61+ }
62+
63+ /// <summary>
64+ /// Yields the full class names of all ancestors across the inheritence chain of <paramref name="current"/>, including itself.
65+ /// </summary>
66+ private static IEnumerable < string > YieldAncestors ( TypeDefinition ? current )
67+ {
68+ while ( current != null )
69+ {
70+ yield return current . FullName ;
71+ ITypeDefOrRef ? baseType = current . BaseType ;
72+ current = baseType ? . Resolve ( ) ;
73+ if ( current == null && baseType != null )
74+ {
75+ //Type is in an unresolved dependency assembly, stop the search but yield the type name
76+ yield return baseType . FullName ;
77+ }
78+ }
79+ }
3080}
0 commit comments