1
1
/*
2
- * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
@@ -102,10 +102,20 @@ of its enclosing class or interface, whether direct or inherited
102
102
that were later generified remain the same.
103
103
104
104
usage: the checker is run from a module specific test
105
- `@run main SinceChecker <moduleName> [--exclude package1,package2 | --exclude package1 package2]`
105
+ `@run main SinceChecker <moduleName> [--ignoreSince <string1>,<string2>] [--exclude package1,package2 | --exclude package1 package2]`
106
+
107
+ To help long running projects still in development, that do not have a fixed version number that conforms
108
+ to the OpenJDK release cycle, one may want to use token name instead of continuely updating the current version since tags.
109
+ For example, `@since LongRunningProjectName`. The option `--ignoreSince` maybe used to
110
+ ignore these tags (`-ignoreSince LongRunningProjectName`). Maybe be specified multiple times.
106
111
*/
107
112
108
113
public class SinceChecker {
114
+ private static final int JDK_CURRENT = Runtime .version ().feature ();
115
+ // Ignored since tags
116
+ private static final Set <String > IGNORE_LIST = new HashSet <>();
117
+ // Simply replace ignored since tags with the latest version
118
+ private static final Version IGNORE_VERSION = Version .parse (Integer .toString (JDK_CURRENT ));
109
119
private final Map <String , Set <String >> LEGACY_PREVIEW_METHODS = new HashMap <>();
110
120
private final Map <String , IntroducedIn > classDictionary = new HashMap <>();
111
121
private final JavaCompiler tool ;
@@ -125,10 +135,16 @@ public static void main(String[] args) throws Exception {
125
135
}
126
136
String moduleName = args [0 ];
127
137
boolean excludeFlag = false ;
138
+ boolean ignoreFlag = false ;
128
139
129
140
for (int i = 1 ; i < args .length ; i ++) {
130
- if ("--exclude" .equals (args [i ])) {
141
+ if ("--ignoreSince" .equals (args [i ])) {
142
+ ignoreFlag = true ;
143
+ excludeFlag = false ;
144
+ continue ;
145
+ } else if ("--exclude" .equals (args [i ])) {
131
146
excludeFlag = true ;
147
+ ignoreFlag = false ;
132
148
continue ;
133
149
}
134
150
@@ -139,6 +155,14 @@ public static void main(String[] args) throws Exception {
139
155
EXCLUDE_LIST .add (args [i ]);
140
156
}
141
157
}
158
+
159
+ if (ignoreFlag ) {
160
+ if (args [i ].contains ("," )) {
161
+ IGNORE_LIST .addAll (Arrays .asList (args [i ].split ("," )));
162
+ } else {
163
+ IGNORE_LIST .add (args [i ]);
164
+ }
165
+ }
142
166
}
143
167
144
168
SinceChecker sinceCheckerTestHelper = new SinceChecker (moduleName );
@@ -152,7 +176,7 @@ private void error(String message) {
152
176
153
177
private SinceChecker (String moduleName ) throws IOException {
154
178
tool = ToolProvider .getSystemJavaCompiler ();
155
- for (int i = 9 ; i <= Runtime . version (). feature () ; i ++) {
179
+ for (int i = 9 ; i <= JDK_CURRENT ; i ++) {
156
180
DiagnosticListener <? super JavaFileObject > noErrors = d -> {
157
181
if (!d .getCode ().equals ("compiler.err.module.not.found" )) {
158
182
error (d .getMessage (null ));
@@ -402,7 +426,7 @@ private boolean isNotCommonRecordMethod(TypeElement te, Element element, Types t
402
426
403
427
private void analyzeClassCheck (TypeElement te , String version , EffectiveSourceSinceHelper javadocHelper ,
404
428
Types types , Elements elementUtils ) {
405
- String currentjdkVersion = String .valueOf (Runtime . version (). feature () );
429
+ String currentjdkVersion = String .valueOf (JDK_CURRENT );
406
430
if (!isDocumented (te )) {
407
431
return ;
408
432
}
@@ -452,24 +476,31 @@ private void checkElement(Element explicitOwner, Element element, Types types,
452
476
}
453
477
454
478
private Version extractSinceVersionFromText (String documentation ) {
455
- Pattern pattern = Pattern .compile ("@since\\ s+(\\ d+(?:\\ .\\ d+)?)" );
456
- Matcher matcher = pattern .matcher (documentation );
457
- if (matcher .find ()) {
458
- String versionString = matcher .group (1 );
459
- try {
460
- if (versionString .equals ("1.0" )) {
461
- versionString = "1" ; //ended up being necessary
462
- } else if (versionString .startsWith ("1." )) {
463
- versionString = versionString .substring (2 );
464
- }
465
- return Version .parse (versionString );
466
- } catch (NumberFormatException ex ) {
467
- error ("`@since` value that cannot be parsed: " + versionString );
468
- return null ;
469
- }
470
- } else {
479
+ Matcher matcher = Pattern .compile ("@since\\ s+(\\ S+)" ).matcher (documentation );
480
+ if (!matcher .find ()) {
481
+ return null ;
482
+ }
483
+
484
+ String versionString = matcher .group (1 );
485
+ if (IGNORE_LIST .contains (versionString )) {
486
+ return IGNORE_VERSION ;
487
+ }
488
+
489
+ versionString = switch (versionString ) {
490
+ case "1.0" -> "1" ;
491
+ case String v when v .matches ("1\\ .\\ d+\\ .\\ d+" ) -> "1" ; // `1.x.x` -> `1`
492
+ case String v when v .startsWith ("1." ) -> v .substring (2 ); // `1.x` -> `x`
493
+ case String v when v .contains ("u" ) -> v .substring (0 , v .indexOf ('u' )); // 6u25 -> 6
494
+ default -> versionString ;
495
+ };
496
+
497
+ if (!versionString .matches ("\\ d+(?:\\ .\\ d+)?" )) {
498
+ error ("Non-numeric `@since` value encountered: '" + versionString +
499
+ "'; If this is intentional, consider using the --ignoreSince option." );
471
500
return null ;
472
501
}
502
+
503
+ return Version .parse (versionString );
473
504
}
474
505
475
506
private void checkEquals (String prefix , String sinceVersion , String mappedVersion , String name ) {
0 commit comments