-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCheck.java
More file actions
4320 lines (3701 loc) · 247 KB
/
Check.java
File metadata and controls
4320 lines (3701 loc) · 247 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import java.io.File;
import java.io.PrintStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Set;
import java.util.Arrays;
import java.util.TreeMap;
import java.util.ArrayList;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Member; // for Modifiers for Methods, Constructors and Fields
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable; // Executable is the shared superclass for the common functionality of Method and Constructor.
import java.lang.reflect.AccessibleObject; // AccessibleObject is the shared superclass for the common functionality of Field, Method, and Constructor.
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Repeatable;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.FutureTask; // A cancellable asynchronous computation... task.get(timeout, TimeUnit.MILLISECONDS);
import java.util.concurrent.TimeUnit; // We use only milliseconds here
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// General lessons learned:
// - An Object[] can not store primitives, it will store their wrappers!
// => We can not distinguish bewteen e.g. Double and double in a parameter array without further hints!
// => Such a hint could come from refSol.getParameterTypes() and/or stuSol.getParameterTypes()
// -
// ---------------------------------------- from RefSolClass ----------------------------------------------------
// java.lang.reflect.Modifier.PUBLIC; // 1
// java.lang.reflect.Modifier.PRIVATE; // 2
// java.lang.reflect.Modifier.PROTECTED; // 4
// java.lang.reflect.Modifier.STATIC; // 8
// see https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.6.1
@Retention(RetentionPolicy.RUNTIME)
@interface CheckIt {
}
@Retention(RetentionPolicy.RUNTIME)
@Deprecated
@interface MethodVariants {
@Deprecated
Class[] otherReturnTypes() default {};
// an array of all the (in general) allowed return types for this method
// NOTE: if for a certain reason a certain alternative type is problematic,
// then it must be "directly" tested in a separate test method (@Test),
// example: int sumFromTo(int a, int b) may be ok but long is the better return type
// => use long as return type in the reference solution and list int in otherReturnTypes + use at least one test with a large result
String[] modifierChecks() default {}; // e.g. {"public|protected:true", "static:false"} for an object method which must be public or protected
}
@Retention(RetentionPolicy.RUNTIME)
@interface Variants {
Class[] otherTypes() default {};
// an array of all the (in general) allowed return types for this method
// NOTE: if for a certain reason a certain alternative type is problematic,
// then it must be "directly" tested in a separate test method (@Test),
// example: int sumFromTo(int a, int b) may be ok but long is the better return type
// => use long as return type in the reference solution and list int in otherReturnTypes + use at least one test with a large result
String[] modifierChecks() default {}; // e.g. {"public|protected:true", "static:false"} for an object method which must be public or protected
}
@Retention(RetentionPolicy.RUNTIME)
@interface TimeOutMs {
int value() default 400;
}
// @Retention(RetentionPolicy.RUNTIME)
// //@Repeatable(TestParams.class) // see e.g. here??? https://www.javatpoint.com/java-8-type-annotations-and-repeating-annotations
// https://www.javabrahman.com/java-8/java-8-repeating-annotations-tutorial/
// https://dzone.com/articles/repeatable-annotations-in-java-8-1
// @interface TestParams {
// String[] chkIds() default {}; // ids of the checks where these test parameters shall be applied
// String[] values() default {};
// String[] ranges() default {};
// }
// TestParamSet
// - There can be different sets of test parameters -> each set can be applied to certain scopes
// - Values: A list of certain parameter lists which are to be tested
// - Ranges: A list of parameter lists where each single parameter is described by a range.
// An optional number per parameter list defines the number of random tests with this paramter list.
// - Fields: A list of "parameter lists" for field initialisation before calling a method.
// The first String is a name list showing the used fields and their order.
// Further parameters will be interpreted as values for the parameter list.
// For java examples see e.g.:
// https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html
// https://www.javatpoint.com/java-8-type-annotations-and-repeating-annotations
// https://www.javabrahman.com/java-8/java-8-repeating-annotations-tutorial/
// https://dzone.com/articles/repeatable-annotations-in-java-8-1
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TestParamSets.class)
@interface TestParamSet {
String[] scopes() default {}; // IDs of the scopes where the parameters can be applied
String[] values() default {};
String[] ranges() default {};
String[] fields() default {};
}
@Retention(RetentionPolicy.RUNTIME)
@interface TestParamSets {
TestParamSet[] value();
}
//////////////////////////////////////////////
@Retention(RetentionPolicy.RUNTIME)
@interface TestParamsList {
}
class RefSolClass { // base class for all our reference solutions
// aims: 1. can check in "common" code if the testees solution is derived
// from this class -> not allowed!
}
// ---------------------------------------- from ModifierCheck ----------------------------------------------------
class ModifierCheck {
int mask;
boolean isNot0;
String def;
public static Pattern pat_modif = Pattern.compile("(public|protected|private|static)");
public static Pattern pat_result = Pattern.compile("(true|false)");
public ModifierCheck(int m, boolean v, String s){
this.mask = m;
this.isNot0 = v;
this.def = s;
}
public boolean ok(int modif){
return ((modif & mask) != 0) == isNot0;
}
public String shouldBeDe(){
return (isNot0 ? "" : "nicht ")+toStr(mask, "oder");
}
public String isDe(int modif){
return toStr(modif&expand(mask), "und");
}
public static String isDeStatic(int m, int o){
int x=m^o; // mask: the bits which differ
String sep=" und ";
String s = "";
if (( x&java.lang.reflect.Modifier.STATIC ) != 0) s = ((m&java.lang.reflect.Modifier.STATIC )==0 ? "nicht ": "") + "static";
String v = "";
if ((m&x&java.lang.reflect.Modifier.PUBLIC ) != 0) v = ((m&java.lang.reflect.Modifier.PUBLIC )==0 ? "nicht ": "") + "public";
if ((m&x&java.lang.reflect.Modifier.PRIVATE ) != 0) v = ((m&java.lang.reflect.Modifier.PRIVATE )==0 ? "nicht ": "") + "private";
if ((m&x&java.lang.reflect.Modifier.PROTECTED) != 0) v = ((m&java.lang.reflect.Modifier.PROTECTED)==0 ? "nicht ": "") + "protected";
return v+(v.length()>0 && s.length()>0 ? sep : "")+s;
}
public static String isDeStatic(int m){
String sep=" und ";
String s=((m&java.lang.reflect.Modifier.STATIC ) == 0) ? "nicht static" : "static";
String r="";
if ((m&java.lang.reflect.Modifier.PUBLIC ) != 0) r+=(r.length()==0 ? "":sep) + "public";
if ((m&java.lang.reflect.Modifier.PRIVATE ) != 0) r+=(r.length()==0 ? "":sep) + "private";
if ((m&java.lang.reflect.Modifier.PROTECTED) != 0) r+=(r.length()==0 ? "":sep) + "protected";
if (r.length()==0)
return s+sep+"nicht public, nicht private und auch nicht protected";
return r+sep+s;
}
public static int expand(int m){
int vis = java.lang.reflect.Modifier.PUBLIC
| java.lang.reflect.Modifier.PRIVATE
| java.lang.reflect.Modifier.PROTECTED;
return m | ((m&vis)==0 ? 0 : vis);
}
public static String toStr(int m){
return toStr(m, " ");
}
public static String toStr(int m, String sep){
String r="";
if ((m&java.lang.reflect.Modifier.PUBLIC ) != 0) r+=(r.length()==0 ? "":sep) + "public";
if ((m&java.lang.reflect.Modifier.PRIVATE ) != 0) r+=(r.length()==0 ? "":sep) + "private";
if ((m&java.lang.reflect.Modifier.PROTECTED) != 0) r+=(r.length()==0 ? "":sep) + "protected";
if ((m&java.lang.reflect.Modifier.STATIC ) != 0) r+=(r.length()==0 ? "":sep) + "static";
return r;
}
public static ModifierCheck[] parse(String[] mChkStrArr){
int numOk=0;
ModifierCheck[] mca = new ModifierCheck[mChkStrArr.length];
for (String mChkStr:mChkStrArr){
String[] parts = mChkStr.split(":");
if (parts.length!=2){
sopl("ERROR, there is no : in the ModifierCheck definition "+mChkStr);
continue;
}
int mask=0;
boolean mOk=true;
for (String s:parts[0].split("\\|")){
Matcher m = pat_modif.matcher(s.trim().toLowerCase());
if (!m.matches()){
sopl("ERROR, unknown modifier "+s+" found in the ModifierCheck definition "+mChkStr);
mOk = false;
break;
}
switch (m.group(1)){ // see e.g. https://docs.oracle.com/javase/8/docs/api/constant-values.html#java.lang.reflect.Modifier.PUBLIC etc
case "public" : mask |= java.lang.reflect.Modifier.PUBLIC ; break; // 1
case "private" : mask |= java.lang.reflect.Modifier.PRIVATE ; break; // 2
case "protected" : mask |= java.lang.reflect.Modifier.PROTECTED; break; // 4
case "static" : mask |= java.lang.reflect.Modifier.STATIC ; break; // 8
}
}
if (!mOk)
continue;
Matcher m = pat_result.matcher(parts[1].trim().toLowerCase());
if (!m.matches()){
sopl("ERROR, unknown result "+parts[1]+" found in the ModifierCheck definition "+mChkStr+" (should be true or false)");
continue;
}
mca[numOk++] = new ModifierCheck( mask, m.group(1).equals("true"), mChkStr);
}
ModifierCheck[] ret = new ModifierCheck[numOk];
for (int i=0; i<numOk; i++)
ret[i] = mca[i];
return ret;
}
public String toString(){
return "mask:"+mask+" isNot0:"+isNot0+" def:"+def;
}
public static void sopl(String s){
System.out.println(s);
}
public static void main(String[] a){
String[] defs1 = {"public|protected:true", "static:false"}; // for an object method which must be public or protected
ModifierCheck[] mca1 = parse(defs1);
for (ModifierCheck mc : mca1)
sopl(""+mc);
}
}
// ---------------------------------------- from Range ----------------------------------------------------
class Range {
abstract class R { // this is the base for all typed range data where we will store the typed begin and end values (2 values per range), see e.g. classes Rb or RB
abstract Object v(); // this will return a random value from the range (equal probability for all values)
abstract boolean isValue();
}
public static int defNumPerRange = 7; // usually there is a number how many (parameter) values are used per range, if not we use defNumPerRange values
// random values in the range b..e
public static byte r(byte b, byte e){ return (byte )(b+(byte )((e-b+1)*Math.random())); }
public static short r(short b, short e){ return (short )(b+(short )((e-b+1)*Math.random())); }
public static int r(int b, int e){ return (int )(b+(int )((e-b+1)*Math.random())); }
public static long r(long b, long e){ return (long )(b+(long )((e-b+1)*Math.random())); }
public static float r(float b, float e){ return (float )(b+(float )((e-b )*Math.random())); }
public static double r(double b, double e){ return (double)(b+(double)((e-b )*Math.random())); }
public static char r(char b, char e){ return (char )(b+(char )((e-b+1)*Math.random())); }
public static boolean r(boolean b, boolean e){ return b==e ? b : (0.5 < Math.random() ); }
// rounding to a certain number of digits for floating point values
public static float r2(float b, float e){ return round(r(b, e), 2); }
public static double r2(double b, double e){ return round(r(b, e), 2); }
public static float rn(float b, float e, int n){ return round(r(b, e), n); }
public static double rn(double b, double e, int n){ return round(r(b, e), n); }
public static float round(float v, int n){ float f=(float)Math.pow(10, n); return ((long)(v*f+(v<0?-.5:.5)))/f; }
public static double round(double v, int n){ double f= Math.pow(10, n); return ((long)(v*f+(v<0?-.5:.5)))/f; }
// parsing given Strings to the supported primitive types
public static byte pB(String s) { return Byte .parseByte (s.replaceAll("_", "")); }
public static short pS(String s) { return Short .parseShort (s.replaceAll("_", "")); }
public static int pI(String s) { return Integer.parseInt (s.replaceAll("_", "")); }
public static long pL(String s) { return Long .parseLong (s.replaceAll("_", "")); }
public static float pF(String s) { return Float .parseFloat (s ); }
public static double pD(String s) { return Double .parseDouble(s ); }
public static char pC(String s) { return s.charAt(0) ; }
public static boolean pT(String s) { // s=s.toLowerCase(); // note: Boolean.parseBoolean does not fit our needs
if (s.equals("true" )) return true;
if (s.equals("false")) return false;
throw new NumberFormatException(); } // ok, in fact it is no number, but can be seen as 0 vs 1;-)
// parsers for wrapped primitive values -> null is supported here; BUT: NOTE that null is not supported in our "low level" ranges!!!
public static Byte p_B(String s) { return s==null || s.equals("null") ? null : pB(s); }
public static Short p_S(String s) { return s==null || s.equals("null") ? null : pS(s); }
public static Integer p_I(String s) { return s==null || s.equals("null") ? null : pI(s); }
public static Long p_L(String s) { return s==null || s.equals("null") ? null : pL(s); }
public static Float p_F(String s) { return s==null || s.equals("null") ? null : pF(s); }
public static Double p_D(String s) { return s==null || s.equals("null") ? null : pD(s); }
public static Character p_C(String s) { return s==null || s.equals("null") ? null : pC(s); }
public static Boolean p_T(String s) { return s==null || s.equals("null") ? null : pT(s); }
// constructors for ranges of primitive values; ensuring that b<=e is especially important for calculating random of integer values or char values; floats only theoretically...
class Rb extends R{ byte b,e; Rb(String x, String y){ b=pB(x); e=pB(y); if(e<b){byte h=e;e=b;b=h;}} Object v(){ return r (b,e); } boolean isValue(){return b==e;}}
class Rs extends R{ short b,e; Rs(String x, String y){ b=pS(x); e=pS(y); if(e<b){short h=e;e=b;b=h;}} Object v(){ return r (b,e); } boolean isValue(){return b==e;}}
class Ri extends R{ int b,e; Ri(String x, String y){ b=pI(x); e=pI(y); if(e<b){int h=e;e=b;b=h;}} Object v(){ return r (b,e); } boolean isValue(){return b==e;}}
class Rl extends R{ long b,e; Rl(String x, String y){ b=pL(x); e=pL(y); if(e<b){long h=e;e=b;b=h;}} Object v(){ return r (b,e); } boolean isValue(){return b==e;}}
class Rf extends R{ float b,e; Rf(String x, String y){ b=pF(x); e=pF(y); if(e<b){float h=e;e=b;b=h;}} Object v(){ return r2(b,e); } boolean isValue(){return b==e;}}
class Rd extends R{ double b,e; Rd(String x, String y){ b=pD(x); e=pD(y); if(e<b){double h=e;e=b;b=h;}} Object v(){ return r2(b,e); } boolean isValue(){return b==e;}}
class Rc extends R{ char b,e; Rc(String x, String y){ b=pC(x); e=pC(y); if(e<b){char h=e;e=b;b=h;}} Object v(){ return r (b,e); } boolean isValue(){return b==e;}}
class Rt extends R{ boolean b,e; Rt(String x, String y){ b=pT(x); e=pT(y); } Object v(){ return r (b,e); } boolean isValue(){return b==e;}}
// constructors for ranges of wrapped primitive values; ensuring that b<=e is especially important for calculating random of integer values or char values; floats only theoretically...
class RB extends R{ Byte b,e; RB(String x, String y){ b=pB(x); e=pB(y); if(e<b){byte h=e;e=b;b=h;}} Object v(){ return Byte .valueOf(r (b,e)); } boolean isValue(){return b==e;}}
class RS extends R{ Short b,e; RS(String x, String y){ b=pS(x); e=pS(y); if(e<b){short h=e;e=b;b=h;}} Object v(){ return Short .valueOf(r (b,e)); } boolean isValue(){return b==e;}}
class RI extends R{ Integer b,e; RI(String x, String y){ b=pI(x); e=pI(y); if(e<b){int h=e;e=b;b=h;}} Object v(){ return Integer .valueOf(r (b,e)); } boolean isValue(){return b==e;}}
class RL extends R{ Long b,e; RL(String x, String y){ b=pL(x); e=pL(y); if(e<b){long h=e;e=b;b=h;}} Object v(){ return Long .valueOf(r (b,e)); } boolean isValue(){return b==e;}}
class RF extends R{ Float b,e; RF(String x, String y){ b=pF(x); e=pF(y); if(e<b){float h=e;e=b;b=h;}} Object v(){ return Float .valueOf(r2(b,e)); } boolean isValue(){return b==e;}}
class RD extends R{ Double b,e; RD(String x, String y){ b=pD(x); e=pD(y); if(e<b){double h=e;e=b;b=h;}} Object v(){ return Double .valueOf(r2(b,e)); } boolean isValue(){return b==e;}}
class RC extends R{ Character b,e; RC(String x, String y){ b=pC(x); e=pC(y); if(e<b){char h=e;e=b;b=h;}} Object v(){ return Character.valueOf(r (b,e)); } boolean isValue(){return b==e;}}
class RT extends R{ Boolean b,e; RT(String x, String y){ b=pT(x); e=pT(y); } Object v(){ return Boolean .valueOf(r (b,e)); } boolean isValue(){return b==e;}}
Class typ; // type of the value for which we define this Range
String def; // the definition text we have parsed to initialize this Range
String err; // here we store an error hint, if some was found during parsing
R range; // stores the begin and end value and can return typed random values via method v()
int num; // the number of parameters we shall generate for this range in the tests
public static String patSt_cnt = "([_0-9]+)";
public static String patSt_int = "([-+]?[_0-9]+)";
public static String patSt_val = "([-+]?[_0-9]+(?:\\.[0-9])?|'(.)')";
public static String patSt_valR = patSt_val + "\\s*\\.\\.\\.\\s*" + patSt_val; // -17...42.3 -> general numbers, no 1e-10 (todo???)
public static String patSt_lenR = "\\[\\s*"+patSt_int + "\\s*\\.\\.\\.\\s*" + patSt_int+"\\s*\\]"; // [ -1...17 ] -> integers only (neg. allowd, e.g. for -1 == null)
public static String patSt_cntV = "(?:"+patSt_cnt+"\\s*:|)"; // 3: -> an optional count value (no neg. values!)
// public static Pattern pat_rangePri = Pattern.compile(patSt_cntV +"\\s*"+ patSt_priR); // "n:v0...ve" or "v0..ve" for number or char values
// note: To support n-dimensional arrays we have to take into account that working with groups is not trivial if the number of groups is not clear
// Here we could try to use quantifiers like * or + for patSt_lenR, BUT we would only get the begin and end of the last range!!!
// See tests in main-method near the comment with the URL https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#groupname
// => Therefore we use non-capturing versions to get all array size ranges (1 per dimension) at once.
public static String patSt_someInt = "(?:[-+]?[_0-9]+)"; // same as patSt_int (an optionally signed integer number) but as a non-capturing group
public static String patSt_arrLenR = "\\[\\s*"+patSt_someInt+"\\s*\\.\\.\\.\\s*"+patSt_someInt+"\\s*\\]"; // similar to patSt_lenR but non-capturing
public static String patSt_nArrLenR = "((?:"+patSt_arrLenR+")*)";
public static Pattern pat_rangeValA = Pattern.compile(patSt_cntV +"\\s*"+ patSt_nArrLenR +"\\s*"+ patSt_valR); // "n:[-1...10]v0...ve" or "[-1...10]v0..ve" for prim. arrays
// or more than 1 dimesion, e.g. "n:[-1...10][-1..3]v0...ve" or "[-1...2][0..7]v0..ve"
public static Pattern pat_rangeLen = Pattern.compile("("+patSt_lenR+")"); // matches a single length range
// TODO: - may be we shold find a way to have ranges for the first array elements (1st 2nd 3rd)
// BUT: note that separation by comma may collide with camma in param lists!
// may be we should put array element panges into curly brakets
// -> would also allow to unify values() and ranges() ???
class A extends R { // data for an array definition with ranges for number of elements and element values
Class<?> eTy;
Ri nr; // int range for number of elements
R er; // typed range for element values (note: for arrays with more than 1 dimension this may be an array too!)
A (String nb, String ne, Class<?> elemType, R elemRange){
eTy= elemType;
nr = new Ri(nb, ne);
er = elemRange;
}
int n(){
return r(nr.b, nr.e);
}
Object v(){
int len=n();
if (len<0)
return null;
Object ret = Array.newInstance(eTy, len);
for (int i=0; i<len; i++)
Array.set(ret, i, er.v());
return ret;
}
boolean isValue(){
return nr.isValue() && er.isValue(); // array length must be a fix value as well as each element (implies that all have the same value:-()
}
}
boolean isValue(){
return range.isValue(); // our wrapped "primitive" range must be fixed
}
public R fromType(Class typ, String a, String b, String e){
if (typ.isArray()){
Matcher m = pat_rangeLen.matcher(a);
if (!m.find()){
sopl("RANGE typ:"+typ+" does not matche range length definition="+a);
return null;
}
Class<?> eTy = typ.getComponentType();
return new A(m.group(2), m.group(3), eTy, fromType(eTy, a.substring(m.end(1)), b, e));
}
else if (typ == byte .class) return new Rb(b, e);
else if (typ == short .class) return new Rs(b, e);
else if (typ == int .class) return new Ri(b, e);
else if (typ == long .class) return new Rl(b, e);
else if (typ == float .class) return new Rf(b, e);
else if (typ == double .class) return new Rd(b, e);
else if (typ == char .class) return new Rc(b, e);
else if (typ == boolean .class) return new Rt(b, e);
else if (typ == Byte .class) return new RB(b, e);
else if (typ == Short .class) return new RS(b, e);
else if (typ == Integer .class) return new RI(b, e);
else if (typ == Long .class) return new RL(b, e);
else if (typ == Float .class) return new RF(b, e);
else if (typ == Double .class) return new RD(b, e);
else if (typ == Character .class) return new RC(b, e);
else if (typ == Boolean .class) return new RT(b, e);
else {
sopl("UNKNOWN RANGE typ:"+typ+", def="+def);
return null;
}
}
public Range(Class typ, String def){
this.typ = typ;
this.def = def;
Matcher m = pat_rangeValA.matcher(def); // the array matcher also accepts "no array"-info => group 2 will be null
// sopl("RangeConstructor("+typ+", "+def+") -> "+m);
if (m.matches()){
String n = m.group(1);
String a = m.group(2); // specal array info: the range length for all the dimensions, may be null
String b = m.group(m.group(4)==null ? 3 : 4); // example: "'v'" has grp3=="'v'" and grp4="v" BUT "1" has grp3=="1" and grp4=null
String e = m.group(m.group(6)==null ? 5 : 6); // similar for the range end
this.num = n==null ? defNumPerRange : pI(n);
try {
this.range = fromType(typ, a, b, e);
// NOTE: the inner range may stay null if fromType can not handle typ -> the allAreValid() method should detect this
} catch (Exception x){
this.err = "BAD RANGE for typ:"+typ+", def="+def+" exept:"+x;
sopl(err);
}
}
else {
this.err = "BAD RANGE Pattern for typ:"+typ+", def="+def;
sopl(err);
}
}
Object getSomeValue(){
return range==null ? null : range.v();
}
String getSomeValueAsString(Check chk){
return chk==null ? Check.asStringStatic(getSomeValue())
: chk.asString(getSomeValue());
}
public static Range[] rangeArrFromStr(Class[] paT, String rangesStr){
Range[] ra = new Range[paT.length];
String[] rsa = rangesStr.split(",");
for (int i=0; i<ra.length && i<rsa.length; i++)
ra[i] = new Range(paT[i], rsa[i].trim());
return ra;
}
public static void checkRangeArray(Class[] tyArr, Range[] a){
if (a==null)
throw new NumberFormatException("ERROR in checkRangeArray() : array of ranges does not exist!");
if (tyArr.length!=a.length)
throw new NumberFormatException("ERROR in checkRangeArray() : array has length="+a.length+" but should have length="+tyArr.length);
int i=0;
for (Range r:a){
if (r==null)
throw new NumberFormatException("ERROR in checkRangeArray() at index "+i+": does not exist");
if (r.err!=null)
throw new NumberFormatException("ERROR in checkRangeArray() at index "+i+": "+r.err);
if (r.range==null)
throw new NumberFormatException("ERROR in checkRangeArray() at index "+i+": has no inner range R with typed begin and end value");
i++;
}
}
public static boolean allAreValid(Range[] a){ // weak test, generates only the info: ok or not
if (a==null)
return false;
for (Range r:a)
if (r==null || r.range==null) // note: the "abstract" range r must have a certain type specific inner range r.range!!!
return false;
return true;
}
public static String toParamsStr(Range[] a, Check chk){
if (a==null)
return "";
String s="";
for (int i=0; i<a.length; i++)
if (a[i]!=null)
s+=(i==0?"":", ")+a[i].getSomeValueAsString(chk);
return s;
}
public String dbgStr(){
return dbgStr((Check)null);
}
public String dbgStr(Check chk){
return "t:"+(""+typ).replaceAll("class java.lang.", "")+" d:"+def+" n:"+num+" v:"+getSomeValueAsString(chk);
}
public static String dbgStr(Range[] a){
return dbgStr(a, null);
}
public static String dbgStr(Range[] a, Check chk){
String ret="[";
for (Range r:a)
ret += r==null ? null : " {"+r.dbgStr(chk)+"} ";
return ret+"]";
}
public static void sopl(String s){
System.out.println(s);
}
public static void main(String[] a){
Range rB = new Range(byte .class, "5...127" ); sopl("rB : "+rB.dbgStr());
Range rS = new Range(short .class, "5...12" ); sopl("rS : "+rS.dbgStr());
Range rI = new Range(int .class, "-5...12" ); sopl("rI : "+rI.dbgStr());
Range rL = new Range(long .class, "-1...+1" ); sopl("rL : "+rL.dbgStr());
Range rF = new Range(float .class, "5...12" ); sopl("rF : "+rF.dbgStr());
Range rD = new Range(double.class, "5...12" ); sopl("rD : "+rD.dbgStr());
Range rC = new Range(char .class, "'a'...'e'" ); sopl("rC : "+rC.dbgStr());
Range rBn = new Range(byte .class, "3:5...127" ); sopl("rBn : "+rBn.dbgStr());
Range rSn = new Range(short .class, "17:5...12" ); sopl("rSn : "+rSn.dbgStr());
Range rIn = new Range(int .class, "2:-5...12" ); sopl("rIn : "+rIn.dbgStr());
Range rLn = new Range(long .class, "1:-1...+1" ); sopl("rLn : "+rLn.dbgStr());
Range rFn = new Range(float .class, "9:5...12" ); sopl("rFn : "+rFn.dbgStr());
Range rDn = new Range(double.class, "99:5...12" ); sopl("rDn : "+rDn.dbgStr());
Range rCn = new Range(char .class, "3:'a'...'e'" ); sopl("rCn : "+rCn.dbgStr());
Object[] oa = { 1, Integer.valueOf(2) };
for (Object o:oa)
sopl(""+o.getClass()+" -> "+o);
sopl(""+int.class);
sopl(""+Integer.class);
}
}
// --------------- from CancellableExecution.java (and other) -----------------------------------------------------------------------------------------------
interface Code {
public void execNow() throws Throwable;
public String getHint();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class TimedOutException extends RuntimeException {
private final long timeoutMs;
public TimedOutException(long toutMs, Thread t) {
super("Forced timeout after "+toutMs+"ms");
timeoutMs = toutMs;
setStackTrace(getStackTrace(t)); // provide the stacktrace -> what is it good for? -> Hint generation!
}
public long getTimeoutInMs() {
return timeoutMs;
}
// Simple helper method to handle null + ignore SecurityExceptions during Thread.getStackTrace()
public static StackTraceElement[] getStackTrace(Thread t) {
if (t!=null)
try{ StackTraceElement[] x = t.getStackTrace();
if (x!=null)
return x;
}
catch (SecurityException e){}
return new StackTraceElement[0]; // no thread -> empty stack trace
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CancellableExecution {
protected static long serNo = 0;
protected Code theCode;
protected final long timeout;
protected final long timeoutMax = 1000*10; // e.g. 10 seconds
protected final long timeoutMin = 1 ; // e.g. 1 milliseconds
protected long nDoExec = 0;
public boolean locDbg = false;
public Throwable catchedThrowable;
public RuntimeException catchedRuntimeException;
protected CancellableExecution(long tout, Code code) {
serNo++;
theCode = code;
timeout = Math.min(timeoutMax, Math.max(timeoutMin, tout));
}
private class MyCodeWrapper implements Callable<Throwable> {
// https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Callable.html#call()
public Throwable call() throws Exception { // Computes a result, or throws an exception if unable to do so.
try { theCode.execNow(); }
catch (Exception e) { throw e; }
catch (Throwable e) { return e; }
return null;
}
}
public void doExec() {
doExec(locDbg);
}
public void doExec(boolean dbg) {
if (dbg)
System.out.println("\n---------------------------------------------------------------------------------\n");
nDoExec++;
ThreadGroup threadGrp = new ThreadGroup("TGrp_CancellableExecution_"+serNo+"_"+nDoExec);
// threadGrp.setDaemon(true);
FutureTask<Throwable> task = new FutureTask<Throwable>(new MyCodeWrapper());
// Make a daemon thread, a user thread will not stop on timeout!
Thread thread = new Thread(threadGrp, task, "ThreadCancellableExecution_"+serNo+"_"+nDoExec);
thread.setDaemon(true); // https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#setDaemon(boolean) -> daemon vs. user
thread.start(); // setDaemon() must be before start()!! NOTE: will call the method MyCodeWrapper.call() (see above, which calls theCode.execNow())
catchedThrowable = getResult(task, thread);
if (catchedThrowable instanceof InvocationTargetException && ((InvocationTargetException)catchedThrowable).getTargetException()!=null)
catchedThrowable = ((InvocationTargetException)catchedThrowable).getTargetException();
if (catchedThrowable instanceof RuntimeException)
catchedRuntimeException = (RuntimeException)catchedThrowable;
if (dbg){
if (catchedThrowable != null)
System.out.println("doExec["+theCode.getHint()+"] catched: " + catchedThrowable+" --> is RuntimeException?: "+(catchedRuntimeException!=null));
else
System.out.println("doExec["+theCode.getHint()+"] catched nothing -------------------------------------------------");
}
thread.setPriority(Thread.MIN_PRIORITY);
if (dbg)
threadGrp.list();
// For timeouts we get true calling task.cancel(true), else false, see
// System.out.println("######### "+theCode.getHint()+" ####"+task.cancel(true)); // https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/FutureTask.html#cancel(boolean)
// but nevertheless the thread will not stop!
// following was not necessary under openjdk version "17.0.6" 2023-01-17
// -> hopefully destroy() is not needed as it seemed to be in former times...
// 2023 with the jdk version shown above computing time for the thread changed from 100% to 0 (thread was killed, i.e. its pid was not in list of ps aux)
try {
// threadGrp.destroy(); // warning: [removal] destroy() in ThreadGroup has been deprecated and marked for removal
} catch (IllegalThreadStateException e){
System.out.println("#### DESTROY ##### "+theCode.getHint()+" ####"+e);
}
}
private Throwable getResult(FutureTask<Throwable> task, Thread thread) {
try { return task.get(timeout, TimeUnit.MILLISECONDS); } // Ok, we had no exec problems
catch (InterruptedException e) { return e; } // if the current thread was interrupted while waiting
catch (ExecutionException e) { return e.getCause(); } // if the computation threw an exception, we are only interested in the reason -> return it
catch (TimeoutException e) { return new TimedOutException(timeout, thread); } // if the wait timed out -> that is what we are interested in... :-)
finally { if (locDbg) System.out.println("CancellableExecution is finished now by calling thread.interrupt() for "+theCode.getHint());
thread.interrupt(); }
}
// // Simple test and/or execution examples
// public static void t1(){
// System.out.println("CancellableExecution.t1(): Starting to test errors for CancellableExecution");
//
// boolean x = true;
// int toms = 100;
// new CancellableExecution( 5 , new CodeErrGen(CodeErrGen.Error.NoError )).doExec(x); // todo: why does it run soooo long ???
//
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.BadArrayIdx_tooBig )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.BadArrayIdx_tooLow )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.ArithmExept_divBy0 )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.StackOverflow )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.TimeOut )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.AssertionError )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.NullPointerAccess )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.NegArraySize )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.OutOfMemo_heapSpace )).doExec(x); // may have to use memory via: java -Xmx1000m
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.OutOfMemo_sizeVMLim )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.NoClassDefFound )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.BadStringIdx_tooBig )).doExec(x);
// new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.BadStringIdx_tooLow )).doExec(x);
//
// // new CancellableExecution( toms, new CodeErrGen(CodeErrGen.Error.ForbiddenClassUsage )).doExec(x);
//
// new CancellableExecution( 5 , new CodeErrGen(CodeErrGen.Error.NoError )).doExec(x); // todo: why does it stop so fast???
// System.out.println("CancellableExecution.t1(): Finished to test errors for CancellableExecution");
// }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class MethodCallWrapper extends CancellableExecution implements Code {
Check theCheck;
Executable exec;
Object thisObj;
Object[] params;
Object returnValue;
boolean execIsStarted = false;
boolean execNormalEnd = false;
boolean locDbg;
public MethodCallWrapper(Executable x, Object o, Object[] p, boolean dbg, long timeOutInMs, Check chk){
super(timeOutInMs, null);
exec=x; thisObj=o; params=p; locDbg=dbg;
theCode = this;
theCheck = chk;
}
public void execNow() throws Throwable {
// try {
execIsStarted = true;
returnValue = (exec instanceof Method) ? ((Method )exec).invoke(thisObj, params)
: ((Constructor)exec).newInstance (params);
execNormalEnd = true;
// } catch (Throwable e){
// if (locDbg){
// Check.sopl(getHint()+"\n -> catched "+e+"\n -> e.getCause() is :"+e.getCause()+"\n");
// // if (e.getCause()!=null)
// // e.getCause().printStackTrace();
// }
// throw(e); // re-throw the exception now
// }
}
public String toString(){
return getHint();
}
public String getHint(){
return "MethodCallWrapper("+Check.calcSignature(exec, true)+", "+thisObj+", "+theCheck.asString(params)+") execIsStarted:"+execIsStarted+" execNormalEnd:"+execNormalEnd;
}
public Object doExecMethod(){
doExec();
if (catchedRuntimeException!=null)
throw catchedRuntimeException;
return returnValue;
}
}
// --------------------------------------------------------------------------------------------------------------
class RTFunc {
Process p = null;
String result = "";
static public String exec(String cmd)
{
return exec(cmd, false, false);
}
static public String exec(String cmd, boolean inShell)
{
return exec(cmd, inShell, false);
}
static public String exec(String cmd, boolean inShell, boolean dbg){
return new RTFunc().execP(cmd, inShell, dbg);
}
public String execP(String cmd, boolean inShell, boolean dbg)
{
if (dbg)
System.out.println(cmd);
String ret = "";
try {
p = null;
if (inShell){
String sh = "/bin/sh";
String cop = "-c";
String[] cis = new String[] {sh, cop, cmd};
p = Runtime.getRuntime().exec(cis);
}
else
p = Runtime.getRuntime().exec(new String[] {cmd}); // fixes warning: [deprecation] exec(String) in Runtime... p = Runtime.getRuntime().exec(cmd);
BufferedReader inE = new BufferedReader( new InputStreamReader(p.getErrorStream()) );
BufferedReader inO = new BufferedReader( new InputStreamReader(p.getInputStream()) );
// p.waitFor();
for (;;){
String sE = inE.readLine(); if (sE!=null) ret+=sE+"\n";
String sO = inO.readLine(); if (sO!=null) ret+=sO+"\n";
if (sE==null && sO==null)
break;
}
}
catch (Exception e) { ret = "Problem calling: "+cmd+
"\n until here we got :"+ ret; }
p=null;
if (dbg)
System.out.println("FINISHED "+cmd);
return ret;
}
static public ArrayList<String> readLines(String fn){
try {
return Files.lines(Paths.get(fn)).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
catch (Exception e){
return new ArrayList<String>();
}
}
static public String readLinesToStr(String fn){
StringBuilder ret = new StringBuilder();
for (String s:readLines(fn))
ret.append(ret.length()==0?"":"\n").append(s);
return ret.toString();
}
}
// --------------------------------------------------------------------------------------------------------------
class CodeAnalyser {
public static Pattern methDataPat = Pattern.compile(" (.+?);\n descriptor:(.+?)\n flags:(.*?)\n" // flags: (.+?) -> flags: (.*?) because of older javap on CO-server
+" Code:\n stack=([0-9]+), locals=([0-9]+), args_size=([0-9]+)\n"
+"((?:\\s*[0-9]+: .*?\n)*?) LineNumberTable:\n((?:\\s*line [0-9]+: [0-9]+\n)*)");
public static Pattern lineNumbPat = Pattern.compile("^\\s*line ([0-9]+): ([0-9]+)\\s*$");
public static Pattern codeLinePat = Pattern.compile("^\\s*([0-9]+): ([^\\s]+?)(?:|\\s+(.*?)(|//(.*?)))$");
public static String[] operationsWithFloats = {"dmul", "dadd", "ddiv", "dsub", "i2d", "d2i", "dload"
,"fmul", "fadd", "fdiv", "fsub", "i2f", "f2i", "fload"};
// for details about Java bytecode see e.g.: https://en.wikipedia.org/w/index.php?title=Java_bytecode&oldid=1144728510
class ByteCodeEntry {
int bcIndex;
int javaLineNo;
String op;
String args;
String comment;
Integer arg1Val;
ByteCodeEntry(int i, String o, String a, String c){
bcIndex=i; op=o; args=a; comment=c;
}
Integer loopsTo(){ // for & while use "goto"; a doWhile has a conditional jump at the end (if_***, e.g. if_icmple)
return arg1Val!=null && arg1Val<bcIndex && (op.equals("goto") || op.startsWith("if_")) ? arg1Val : null;
}
}
class MethDat {
Integer lineNoBeg;
Integer lineNoEnd;
String methByteCodeDataStr;
String sourceCodeStr;
String signatureStr;
String signatureMin;
String descriptor;
String flags;
String stack;
String locals;
String args_size;
String byteCodeStr;
String lineNoTable;
ArrayList<ByteCodeEntry> bcList = new ArrayList<ByteCodeEntry>();
TreeMap<Integer, ByteCodeEntry> bcMap_idx2bce = new TreeMap<Integer, ByteCodeEntry>();
TreeMap<Integer, Integer> javaLn2bcIdx = new TreeMap<Integer, Integer>();
TreeMap<Integer, Integer> bcIdx2javaLn = new TreeMap<Integer, Integer>();
}
TreeMap<String, MethDat> dat = new TreeMap<String, MethDat>();
String clsNam;
String classByteCodeDataStr;
ArrayList<String> javaCodeLines;
String[] javaCodeLinesWithoutComments;
static boolean dbg = false;
CodeAnalyser(String className){
clsNam = className;
}
// 1=optMod 2=retType 3=name 4=params 5=rest
static public Pattern pat_javapSignature = Pattern.compile("^(?:(.*?)\\s|\\s*)([^\\s]+)\\s+([^\\s]+)\\(([^)]*)\\)(.*)$");
static public String javapSignatureToMinSignature(String s){
if (dbg)
Check.sopl("javapSignatureToMinSignature("+s+")");
boolean tmpDbg = s.indexOf("xxxxxxxxxxxxxxsum_rec")>=0;
if (tmpDbg)
Check.sopl("\n-----------------------------\nstarted javapSignatureToMinSignature("+s+")");
Matcher m = pat_javapSignature.matcher(s);
if (!m.matches())
return s;
if (dbg||tmpDbg)
Check.sopl("javapSignatureToMinSignature("+s+"):\n 1:"+m.group(1)+"\n 2:"+m.group(2)+"\n 3:"+m.group(3)+"\n 4:"+m.group(4)+"\n 5:"+m.group(5));
String[] paStrs = m.group(4).split(","); // when errors occure we could also use Check.splitValueList
String ret="";
for (String paStr:paStrs)
ret+=(ret.length()==0?"":",")+Check.signatureParamTypeTrafo_java2human(paStr).trim();
return m.group(3)+"("+ret+")";
}
// static public String javapSignatureToHumanMin_withModifiersAndRettype(String s){
// if (dbg)
// Check.sopl("javapSignatureToHumanMin("+s+")");
// Matcher m = pat_javapSignature.matcher(s);
// if (!m.matches())
// return s;
//
// if (dbg)
// Check.sopl("javapSignatureToHumanMin("+s+"):\n "+m.group(1)+"\n "+m.group(2)+"\n "+m.group(3)+"\n "+m.group(4)+"\n "+m.group(5));
//
// String[] paStrs = m.group(4).split(","); // when errors occure we could also use Check.splitValueList
// String ret="";
// for (String paStr:paStrs)
// ret+=(ret.length()==0?"":",")+Check.signatureParamTypeTrafo_java2human(paStr).trim();
// return m.group(3)+"("+ret+")";
// }
MethDat getDatBySignature(String s){
if (dat.size()==0){ // lazy initialization (only started if it is realy needed;-)
// 1. get the output of javap for the class
RTFunc.exec("javap -v -c -p -l "+clsNam+".class >bc.txt", true, false);
classByteCodeDataStr = RTFunc.readLinesToStr("bc.txt");
javaCodeLines = RTFunc.readLines(clsNam+".java");
javaCodeLinesWithoutComments = Check.stripJavaComments(String.join("\n", javaCodeLines), true).split("\n");
if (false){
for (int i=0; i<javaCodeLinesWithoutComments.length; i++){
String ln=i+1+""; while (ln.length()<3) ln=" "+ln; ln+=" : ";
Check.sopl(ln+javaCodeLinesWithoutComments[i]);
}
}
// 2. separate info for the single methods
Matcher m=methDataPat.matcher(classByteCodeDataStr);
while (m.find()){
if (dbg)
Check.sopl("fnd "
// +"\n---------\n"+m.group(0)+"\n------------\n"
+"\n si:"+m.group(1)
+"\n de:"+m.group(2)
+"\n fl:"+m.group(3)
+"\n st:"+m.group(4)
+"\n lo:"+m.group(5)
+"\n as:"+m.group(6)
);
// 1. parse the basic method data parts
MethDat md = new MethDat();
md.methByteCodeDataStr = m.group(0);
md.signatureStr = m.group(1).trim();
md.descriptor = m.group(2).trim();
md.flags = m.group(3).trim();
md.stack = m.group(4).trim();
md.locals = m.group(5).trim();
md.args_size = m.group(6).trim();
md.byteCodeStr = m.group(7).trim();
md.lineNoTable = m.group(8).trim();
md.signatureMin = javapSignatureToMinSignature(md.signatureStr);
dat.put(md.signatureMin, md);
// 2. extract begin and end line numbers, fill mappings for both directions (javaLn2bcIdx and bcIdx2javaLn)
Integer min=null, max=null;
for (String tabLine:md.lineNoTable.split("\n")){ // e.g. >>> line 34: 30<<<