|
24 | 24 | */
|
25 | 25 | package jdk.graal.compiler.options.processor;
|
26 | 26 |
|
27 |
| -import java.io.BufferedReader; |
28 | 27 | import java.io.IOException;
|
29 |
| -import java.io.InputStreamReader; |
| 28 | +import java.io.InputStream; |
30 | 29 | import java.io.PrintWriter;
|
| 30 | +import java.nio.charset.StandardCharsets; |
31 | 31 | import java.util.ArrayList;
|
32 | 32 | import java.util.Collections;
|
33 | 33 | import java.util.HashMap;
|
@@ -185,72 +185,81 @@ private void processElement(Element element, OptionsDeclarer optionsDeclarer) {
|
185 | 185 | processingEnv.getMessager().printMessage(Kind.ERROR, "Option field cannot be declared in the unnamed package", element);
|
186 | 186 | return;
|
187 | 187 | }
|
188 |
| - List<String> helpValue = getAnnotationValueList(annotation, "help", String.class); |
189 |
| - String help = ""; |
190 |
| - List<String> extraHelp = new ArrayList<>(); |
191 |
| - |
192 |
| - if (helpValue.size() == 1) { |
193 |
| - help = helpValue.getFirst(); |
194 |
| - if (help.startsWith("file:")) { |
195 |
| - String path = help.substring("file:".length()); |
196 |
| - Filer filer = processingEnv.getFiler(); |
| 188 | + |
| 189 | + String help = getAnnotationValue(annotation, "help", String.class); |
| 190 | + List<String> helpLines; |
| 191 | + if (help.startsWith("file:")) { |
| 192 | + String path = help.substring("file:".length()); |
| 193 | + Filer filer = processingEnv.getFiler(); |
| 194 | + try { |
| 195 | + FileObject file; |
197 | 196 | try {
|
198 |
| - FileObject file; |
199 |
| - try { |
200 |
| - file = filer.getResource(StandardLocation.SOURCE_PATH, enclosingPackage.getQualifiedName(), path); |
201 |
| - } catch (IllegalArgumentException | IOException e) { |
202 |
| - // Handle the case when a compiler doesn't support the SOURCE_PATH location |
203 |
| - file = filer.getResource(StandardLocation.CLASS_OUTPUT, enclosingPackage.getQualifiedName(), path); |
204 |
| - } |
205 |
| - try (BufferedReader br = new BufferedReader(new InputStreamReader(file.openInputStream()))) { |
206 |
| - help = br.readLine(); |
207 |
| - if (help == null) { |
208 |
| - help = ""; |
209 |
| - } |
210 |
| - String line = br.readLine(); |
211 |
| - while (line != null) { |
212 |
| - extraHelp.add(line); |
213 |
| - line = br.readLine(); |
214 |
| - } |
215 |
| - } |
216 |
| - } catch (IOException e) { |
217 |
| - String msg = String.format("Error reading %s containing the help text for option field: %s", path, e); |
218 |
| - processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); |
219 |
| - return; |
| 197 | + file = filer.getResource(StandardLocation.SOURCE_PATH, enclosingPackage.getQualifiedName(), path); |
| 198 | + } catch (IllegalArgumentException | IOException e) { |
| 199 | + // Handle the case when a compiler doesn't support the SOURCE_PATH location |
| 200 | + file = filer.getResource(StandardLocation.CLASS_OUTPUT, enclosingPackage.getQualifiedName(), path); |
| 201 | + } |
| 202 | + try (InputStream in = file.openInputStream()) { |
| 203 | + help = new String(in.readAllBytes(), StandardCharsets.UTF_8); |
| 204 | + helpLines = List.of(help.split(System.lineSeparator())); |
220 | 205 | }
|
| 206 | + } catch (IOException e) { |
| 207 | + String msg = String.format("Error reading %s containing the help text for option field: %s", path, e); |
| 208 | + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); |
| 209 | + return; |
221 | 210 | }
|
222 |
| - } else if (helpValue.size() > 1) { |
223 |
| - help = helpValue.getFirst(); |
224 |
| - extraHelp = helpValue.subList(1, helpValue.size()); |
| 211 | + } else { |
| 212 | + helpLines = List.of(help.split("\\n")); |
225 | 213 | }
|
226 |
| - if (!help.isEmpty()) { |
227 |
| - char firstChar = help.charAt(0); |
| 214 | + |
| 215 | + String briefHelp = helpLines.getFirst(); |
| 216 | + List<String> extraHelp; |
| 217 | + if (briefHelp.isEmpty()) { |
| 218 | + if (helpLines.size() > 1) { |
| 219 | + processingEnv.getMessager().printMessage(Kind.ERROR, "First line of multi-line help text cannot be empty", element); |
| 220 | + return; |
| 221 | + } |
| 222 | + extraHelp = List.of(); |
| 223 | + } else { |
| 224 | + if (helpLines.size() > 1) { |
| 225 | + if (briefHelp.charAt(briefHelp.length() - 1) != '.' && !helpLines.get(1).isBlank()) { |
| 226 | + processingEnv.getMessager().printMessage(Kind.ERROR, |
| 227 | + "First line of multi-line help text must end with a period or be followed by a blank line", element); |
| 228 | + return; |
| 229 | + } |
| 230 | + } |
| 231 | + char firstChar = briefHelp.charAt(0); |
228 | 232 | if (!Character.isUpperCase(firstChar)) {
|
229 | 233 | processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with an upper case letter", element);
|
230 | 234 | return;
|
231 | 235 | }
|
| 236 | + extraHelp = helpLines.subList(1, helpLines.size()); |
232 | 237 | }
|
233 | 238 |
|
234 | 239 | String stability = getAnnotationValue(annotation, "stability", VariableElement.class).getSimpleName().toString();
|
235 | 240 | if (stability.equals("STABLE")) {
|
236 |
| - if (help.isEmpty()) { |
| 241 | + if (briefHelp.isEmpty()) { |
237 | 242 | processingEnv.getMessager().printMessage(Kind.ERROR, "A stable option must have non-empty help text", element);
|
238 | 243 | return;
|
239 | 244 | }
|
240 | 245 | }
|
241 | 246 |
|
242 | 247 | String optionTypeName = getAnnotationValue(annotation, "type", VariableElement.class).getSimpleName().toString();
|
243 | 248 | if (!optionTypeName.equals("Debug")) {
|
244 |
| - if (help.isEmpty()) { |
| 249 | + if (briefHelp.isEmpty()) { |
245 | 250 | processingEnv.getMessager().printMessage(Kind.ERROR, "Non debug options must always have a option help text " + optionName);
|
246 | 251 | }
|
247 | 252 | }
|
248 | 253 | boolean deprecated = getAnnotationValue(annotation, "deprecated", Boolean.class);
|
249 | 254 | String deprecationMessage = getAnnotationValue(annotation, "deprecationMessage", String.class);
|
250 |
| - OptionInfo info = new OptionInfo(optionName, optionTypeName, help, extraHelp, optionType, declaringClass, fieldName, stability, deprecated, deprecationMessage); |
| 255 | + OptionInfo info = new OptionInfo(optionName, optionTypeName, briefHelp, extraHelp, optionType, declaringClass, fieldName, stability, deprecated, deprecationMessage); |
251 | 256 | optionsDeclarer.options.add(info);
|
252 | 257 | }
|
253 | 258 |
|
| 259 | + private static String literal(String help) { |
| 260 | + return "\"" + help.replace("\\", "\\\\").replace("\"", "\\\"") + "\""; |
| 261 | + } |
| 262 | + |
254 | 263 | static void createOptionsDescriptorsFile(ProcessingEnvironment processingEnv, OptionsDeclarer optionsDeclarer) {
|
255 | 264 | Element[] originatingElements = optionsDeclarer.originatingElements.toArray(new Element[0]);
|
256 | 265 | String optionsDescriptorsClassName = optionsDeclarer.getOptionDescriptorsClassName();
|
@@ -310,11 +319,11 @@ static void createOptionsDescriptorsFile(ProcessingEnvironment processingEnv, Op
|
310 | 319 | out.printf(" /*name*/ \"%s\",\n", name);
|
311 | 320 | out.printf(" /*optionType*/ %s.%s,\n", getSimpleName(OPTION_TYPE_CLASS_NAME), optionType);
|
312 | 321 | out.printf(" /*optionValueType*/ %s.class,\n", type);
|
313 |
| - out.printf(" /*help*/ \"%s\",\n", help.replace("\\", "\\\\").replace("\"", "\\\"")); |
| 322 | + out.printf(" /*help*/ %s,\n", literal(help)); |
314 | 323 | if (!extraHelp.isEmpty()) {
|
315 | 324 | out.printf(" /*extraHelp*/ new String[] {\n");
|
316 | 325 | for (String line : extraHelp) {
|
317 |
| - out.printf(" \"%s\",\n", line.replace("\\", "\\\\").replace("\"", "\\\"")); |
| 326 | + out.printf(" %s,\n", literal(line)); |
318 | 327 | }
|
319 | 328 | out.printf(" },\n");
|
320 | 329 | }
|
|
0 commit comments