Skip to content

Commit f12d2de

Browse files
committed
8345212: Since checker should better handle non numeric values
Reviewed-by: liach
1 parent 5ec1aae commit f12d2de

File tree

1 file changed

+52
-21
lines changed

1 file changed

+52
-21
lines changed

test/jdk/tools/sincechecker/SinceChecker.java

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
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.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* 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
102102
that were later generified remain the same.
103103
104104
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.
106111
*/
107112

108113
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));
109119
private final Map<String, Set<String>> LEGACY_PREVIEW_METHODS = new HashMap<>();
110120
private final Map<String, IntroducedIn> classDictionary = new HashMap<>();
111121
private final JavaCompiler tool;
@@ -125,10 +135,16 @@ public static void main(String[] args) throws Exception {
125135
}
126136
String moduleName = args[0];
127137
boolean excludeFlag = false;
138+
boolean ignoreFlag = false;
128139

129140
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])) {
131146
excludeFlag = true;
147+
ignoreFlag = false;
132148
continue;
133149
}
134150

@@ -139,6 +155,14 @@ public static void main(String[] args) throws Exception {
139155
EXCLUDE_LIST.add(args[i]);
140156
}
141157
}
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+
}
142166
}
143167

144168
SinceChecker sinceCheckerTestHelper = new SinceChecker(moduleName);
@@ -152,7 +176,7 @@ private void error(String message) {
152176

153177
private SinceChecker(String moduleName) throws IOException {
154178
tool = ToolProvider.getSystemJavaCompiler();
155-
for (int i = 9; i <= Runtime.version().feature(); i++) {
179+
for (int i = 9; i <= JDK_CURRENT; i++) {
156180
DiagnosticListener<? super JavaFileObject> noErrors = d -> {
157181
if (!d.getCode().equals("compiler.err.module.not.found")) {
158182
error(d.getMessage(null));
@@ -402,7 +426,7 @@ private boolean isNotCommonRecordMethod(TypeElement te, Element element, Types t
402426

403427
private void analyzeClassCheck(TypeElement te, String version, EffectiveSourceSinceHelper javadocHelper,
404428
Types types, Elements elementUtils) {
405-
String currentjdkVersion = String.valueOf(Runtime.version().feature());
429+
String currentjdkVersion = String.valueOf(JDK_CURRENT);
406430
if (!isDocumented(te)) {
407431
return;
408432
}
@@ -452,24 +476,31 @@ private void checkElement(Element explicitOwner, Element element, Types types,
452476
}
453477

454478
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.");
471500
return null;
472501
}
502+
503+
return Version.parse(versionString);
473504
}
474505

475506
private void checkEquals(String prefix, String sinceVersion, String mappedVersion, String name) {

0 commit comments

Comments
 (0)