44
55using Mono . Cecil ;
66using Mono . Cecil . Cil ;
7+
78using CKAN . Extensions ;
89
910namespace Tests
@@ -74,9 +75,11 @@ protected static IEnumerable<TypeDefinition> GetAllNestedTypes(TypeDefinition td
7475 . Concat ( td . NestedTypes . SelectMany ( GetAllNestedTypes ) ) ;
7576
7677 protected static IEnumerable < MethodCall > FindStartedTasks ( MethodDefinition md )
77- => StartNewCalls ( md ) . Select ( FindStartNewArgument )
78- . OfType < MethodDefinition > ( )
79- . Select ( taskArg => new MethodCall ( ) { md , taskArg } ) ;
78+ => StartNewCalls ( md ) . SelectMany ( sn =>
79+ sn . Operand is MethodReference snMethod
80+ && FindStartNewArgument ( sn ) is MethodDefinition taskArg
81+ ? Enumerable . Repeat ( new MethodCall ( ) { md , snMethod . Resolve ( ) , taskArg , } , 1 )
82+ : Enumerable . Empty < MethodCall > ( ) ) ;
8083
8184 private static IEnumerable < Instruction > StartNewCalls ( MethodDefinition md )
8285 => md . Body ? . Instructions . Where ( instr => callOpCodes . Contains ( instr . OpCode . Name )
@@ -85,16 +88,48 @@ private static IEnumerable<Instruction> StartNewCalls(MethodDefinition md)
8588 ?? Enumerable . Empty < Instruction > ( ) ;
8689
8790 private static bool isStartNew ( MethodReference mr )
88- => ( mr . DeclaringType . Namespace == "System.Threading.Tasks"
89- && mr . DeclaringType . Name == "TaskFactory"
90- && mr . Name == "StartNew" )
91- || ( mr . DeclaringType . Namespace == "System.Threading.Tasks"
92- && mr . DeclaringType . Name == "Task"
93- && mr . Name == "Run" ) ;
91+ => mr is
92+ {
93+ DeclaringType : { Namespace : "System.Threading.Tasks" , Name : "TaskFactory" } ,
94+ Name : "StartNew" ,
95+ }
96+ or
97+ {
98+ DeclaringType : { Namespace : "System.Threading.Tasks" , Name : "Task" } ,
99+ Name : "Run" ,
100+ } ;
94101
95102 private static MethodDefinition ? FindStartNewArgument ( Instruction instr )
96- => instr . OpCode . Name == "ldftn" ? instr . Operand as MethodDefinition
97- : FindStartNewArgument ( instr . Previous ) ;
103+ => FindFuncArguments ( instr ) . FirstOrDefault ( ) ;
104+
105+ protected static IEnumerable < MethodCall > FindDebouncedTasks ( MethodDefinition md )
106+ => DebounceCalls ( md ) . SelectMany ( db =>
107+ db . Operand is MethodReference dbMethod
108+ ? FindDebounceArguments ( db )
109+ . Select ( dbArg => new MethodCall ( ) { md , dbMethod . Resolve ( ) , dbArg , } )
110+ : Enumerable . Empty < MethodCall > ( ) ) ;
111+
112+ private static IEnumerable < Instruction > DebounceCalls ( MethodDefinition md )
113+ => md . Body ? . Instructions . Where ( instr => callOpCodes . Contains ( instr . OpCode . Name )
114+ && instr . Operand is MethodReference mr
115+ && isDebounce ( mr ) )
116+ ?? Enumerable . Empty < Instruction > ( ) ;
117+
118+ private static bool isDebounce ( MethodReference mr )
119+ => mr is
120+ {
121+ DeclaringType : { Namespace : "CKAN.GUI" , Name : "Util" } ,
122+ Name : "Debounce" ,
123+ } ;
124+
125+ private static IEnumerable < MethodDefinition > FindDebounceArguments ( Instruction instr )
126+ => FindFuncArguments ( instr ) . Take ( 4 ) ;
127+
128+ private static IEnumerable < MethodDefinition > FindFuncArguments ( Instruction instr )
129+ => instr . TraverseNodes ( i => i . Previous )
130+ . Where ( i => i . OpCode . Name == "ldftn" )
131+ . Select ( i => i . Operand )
132+ . OfType < MethodDefinition > ( ) ;
98133
99134 private static readonly HashSet < string > callOpCodes = new HashSet < string >
100135 {
0 commit comments