11using System . Collections ;
2- using System . Diagnostics ;
32
43namespace ICSharpCode . CodeConverter . CSharp ;
54
65/// <summary>
76/// Use and add to this class with great care. There is great potential for issues in different VS versions if something private/internal got renamed.
87/// </summary>
98/// <remarks>
10- /// Lots of cases need a method and a backing field in a way that's awkward to wrap into a single object, so I've put them adjacent for easy reference .
9+ /// Each extension block groups extension methods by type, with the cached delegates stored in the containing class .
1110/// I've opted for using the minimal amount of hardcoded internal names (instead getting the runtime type of the argument) in the hope of being resilient against a simple rename.
1211/// However, if extra subclasses are created and there's no common base type containing the property, or the property itself is renamed, this will obviously break.
1312/// It'd be great to run a CI build configuration that updates all nuget packages to the latest prerelease and runs all the tests (this would also catch other breaking API changes before they hit).
1413/// </remarks>
1514internal static class CachedReflectedDelegates
1615{
17- public static bool IsMyGroupCollectionProperty ( this IPropertySymbol declaredSymbol ) =>
18- GetCachedReflectedPropertyDelegate ( declaredSymbol , "IsMyGroupCollectionProperty" , ref _isMyGroupCollectionProperty ) ;
19- private static Func < ISymbol , bool > _isMyGroupCollectionProperty ;
16+ private static CachedReflectedDelegate < ISymbol , bool > IsMyGroupCollectionPropertyDelegate { get ; } =
17+ new CachedReflectedDelegate < ISymbol , bool > ( "IsMyGroupCollectionProperty" ) ;
2018
21- public static ISymbol GetAssociatedField ( this IPropertySymbol declaredSymbol ) =>
22- GetCachedReflectedPropertyDelegate ( declaredSymbol , "AssociatedField" , ref _associatedField ) ;
23- private static Func < ISymbol , ISymbol > _associatedField ;
19+ private static CachedReflectedDelegate < ISymbol , ISymbol > AssociatedFieldDelegate { get ; } =
20+ new CachedReflectedDelegate < ISymbol , ISymbol > ( "AssociatedField" ) ;
2421
25- public static SyntaxTree GetEmbeddedSyntaxTree ( this Location loc ) =>
26- GetCachedReflectedPropertyDelegate ( loc , "PossiblyEmbeddedOrMySourceTree" , ref _possiblyEmbeddedOrMySourceTree ) ;
27- private static Func < Location , SyntaxTree > _possiblyEmbeddedOrMySourceTree ;
28-
29- public static bool GetIsUsing ( this ILocalSymbol l )
22+ extension ( IPropertySymbol declaredSymbol )
3023 {
31- try {
32- return GetCachedReflectedPropertyDelegate ( l , "IsUsing" , ref _isUsing ) ;
33- } catch ( Exception ) {
34- return false ;
35- }
36- }
37-
38- private static Func < ILocalSymbol , bool > _isUsing ;
39-
24+ public bool IsMyGroupCollectionProperty => IsMyGroupCollectionPropertyDelegate . GetValue ( declaredSymbol ) ;
4025
26+ public ISymbol AssociatedField => AssociatedFieldDelegate . GetValue ( declaredSymbol ) ;
27+ }
4128
42- /// <remarks>Unfortunately the roslyn UnassignedVariablesWalker and all useful collections created from it are internal only
43- /// Other attempts using DataFlowsIn on each reference showed that "DataFlowsIn" even from an uninitialized variable (at least in the case of ints)
44- /// https://github.com/dotnet/roslyn/blob/007022c37c6d21ee100728954bd75113e0dfe4bd/src/Compilers/VisualBasic/Portable/Analysis/FlowAnalysis/UnassignedVariablesWalker.vb#L15
45- /// It'd be possible to see the result of the diagnostic analysis, but that would miss out value types, which don't cause a warning in VB
46- /// PERF: Assume we'll only be passed one type of data flow analysis (VisualBasicDataFlowAnalysis)
47- /// </remarks>
48- public static IEnumerable < ISymbol > GetVbUnassignedVariables ( this DataFlowAnalysis methodFlow ) =>
49- GetCachedReflectedPropertyDelegate ( methodFlow , "UnassignedVariables" , ref _vbUnassignedVariables ) . Cast < ISymbol > ( ) ;
50- private static Func < DataFlowAnalysis , IEnumerable > _vbUnassignedVariables ;
29+ private static CachedReflectedDelegate < Location , SyntaxTree > PossiblyEmbeddedOrMySourceTreeDelegate { get ; } =
30+ new CachedReflectedDelegate < Location , SyntaxTree > ( "PossiblyEmbeddedOrMySourceTree" ) ;
5131
52- private static TDesiredTarget GetCachedReflectedPropertyDelegate < TDesiredArg , TDesiredTarget > ( TDesiredArg instance , string propertyToAccess ,
53- ref Func < TDesiredArg , TDesiredTarget > cachedDelegate )
32+ extension ( Location loc )
5433 {
55- if ( cachedDelegate != null ) return cachedDelegate ( instance ) ;
34+ public SyntaxTree EmbeddedSyntaxTree => PossiblyEmbeddedOrMySourceTreeDelegate. GetValue( loc ) ;
35+ }
5636
57- var getDelegate = instance . ReflectedPropertyGetter ( propertyToAccess )
58- ? . CreateOpenInstanceDelegateForcingType < TDesiredArg , TDesiredTarget > ( ) ;
59- if ( getDelegate == null ) {
60- Debug . Fail ( $ "Delegate not found for { instance . GetType ( ) } ") ;
61- return default ;
62- }
37+ private static CachedReflectedDelegate < DataFlowAnalysis , IEnumerable < ISymbol > > VbUnassignedVariablesDelegate { get ; } =
38+ new CachedReflectedDelegate < DataFlowAnalysis , IEnumerable < ISymbol > > ( "UnassignedVariables" ) ;
6339
64- cachedDelegate = getDelegate ;
65- return cachedDelegate ( instance ) ;
40+ extension ( DataFlowAnalysis methodFlow )
41+ {
42+ /// <remarks>Unfortunately the roslyn UnassignedVariablesWalker and all useful collections created from it are internal only
43+ /// Other attempts using DataFlowsIn on each reference showed that "DataFlowsIn" even from an uninitialized variable (at least in the case of ints)
44+ /// https://github.com/dotnet/roslyn/blob/007022c37c6d21ee100728954bd75113e0dfe4bd/src/Compilers/VisualBasic/Portable/Analysis/FlowAnalysis/UnassignedVariablesWalker.vb#L15
45+ /// It'd be possible to see the result of the diagnostic analysis, but that would miss out value types, which don't cause a warning in VB
46+ /// PERF: Assume we'll only be passed one type of data flow analysis (VisualBasicDataFlowAnalysis)
47+ /// </remarks>
48+ public IEnumerable < ISymbol > VbUnassignedVariables =>
49+ VbUnassignedVariablesDelegate. GetValue( methodFlow ) ;
6650 }
67- }
51+ }
0 commit comments