test/tools/javac/diags/MessageFile.java

Wed, 27 Apr 2016 01:34:52 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:34:52 +0800
changeset 0
959103a6100f
child 2525
2eb010b6cb22
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/langtools/
changeset: 2573:53ca196be1ae
tag: jdk8u25-b17

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 */
aoqi@0 23
aoqi@0 24 import java.io.*;
aoqi@0 25 import java.util.*;
aoqi@0 26 import java.util.regex.Matcher;
aoqi@0 27 import java.util.regex.Pattern;
aoqi@0 28
aoqi@0 29 /**
aoqi@0 30 * Class to facilitate manipulating compiler.properties.
aoqi@0 31 */
aoqi@0 32 class MessageFile {
aoqi@0 33 static final Pattern emptyOrCommentPattern = Pattern.compile("( *#.*)?");
aoqi@0 34 static final Pattern infoPattern = Pattern.compile("# ([0-9]+: [-A-Za-z ]+, )*[0-9]+: [-A-Za-z ]+");
aoqi@0 35
aoqi@0 36 /**
aoqi@0 37 * A line of text within the message file.
aoqi@0 38 * The lines form a doubly linked list for simple navigation.
aoqi@0 39 */
aoqi@0 40 class Line {
aoqi@0 41 String text;
aoqi@0 42 Line prev;
aoqi@0 43 Line next;
aoqi@0 44
aoqi@0 45 Line(String text) {
aoqi@0 46 this.text = text;
aoqi@0 47 }
aoqi@0 48
aoqi@0 49 boolean isEmptyOrComment() {
aoqi@0 50 return emptyOrCommentPattern.matcher(text).matches();
aoqi@0 51 }
aoqi@0 52
aoqi@0 53 boolean isInfo() {
aoqi@0 54 return infoPattern.matcher(text).matches();
aoqi@0 55 }
aoqi@0 56
aoqi@0 57 boolean hasContinuation() {
aoqi@0 58 return (next != null) && text.endsWith("\\");
aoqi@0 59 }
aoqi@0 60
aoqi@0 61 Line insertAfter(String text) {
aoqi@0 62 Line l = new Line(text);
aoqi@0 63 insertAfter(l);
aoqi@0 64 return l;
aoqi@0 65 }
aoqi@0 66
aoqi@0 67 void insertAfter(Line l) {
aoqi@0 68 assert l.prev == null && l.next == null;
aoqi@0 69 l.prev = this;
aoqi@0 70 l.next = next;
aoqi@0 71 if (next == null)
aoqi@0 72 lastLine = l;
aoqi@0 73 else
aoqi@0 74 next.prev = l;
aoqi@0 75 next = l;
aoqi@0 76 }
aoqi@0 77
aoqi@0 78 Line insertBefore(String text) {
aoqi@0 79 Line l = new Line(text);
aoqi@0 80 insertBefore(l);
aoqi@0 81 return l;
aoqi@0 82 }
aoqi@0 83
aoqi@0 84 void insertBefore(Line l) {
aoqi@0 85 assert l.prev == null && l.next == null;
aoqi@0 86 l.prev = prev;
aoqi@0 87 l.next = this;
aoqi@0 88 if (prev == null)
aoqi@0 89 firstLine = l;
aoqi@0 90 else
aoqi@0 91 prev.next = l;
aoqi@0 92 prev = l;
aoqi@0 93 }
aoqi@0 94
aoqi@0 95 void remove() {
aoqi@0 96 if (prev == null)
aoqi@0 97 firstLine = next;
aoqi@0 98 else
aoqi@0 99 prev.next = next;
aoqi@0 100 if (next == null)
aoqi@0 101 lastLine = prev;
aoqi@0 102 else
aoqi@0 103 next.prev = prev;
aoqi@0 104 prev = null;
aoqi@0 105 next = null;
aoqi@0 106 }
aoqi@0 107 }
aoqi@0 108
aoqi@0 109 /**
aoqi@0 110 * A message within the message file.
aoqi@0 111 * A message is a series of lines containing a "name=value" property,
aoqi@0 112 * optionally preceded by a comment describing the use of placeholders
aoqi@0 113 * such as {0}, {1}, etc within the property value.
aoqi@0 114 */
aoqi@0 115 static final class Message {
aoqi@0 116 final Line firstLine;
aoqi@0 117 private Info info;
aoqi@0 118
aoqi@0 119 Message(Line l) {
aoqi@0 120 firstLine = l;
aoqi@0 121 }
aoqi@0 122
aoqi@0 123 boolean needInfo() {
aoqi@0 124 Line l = firstLine;
aoqi@0 125 while (true) {
aoqi@0 126 if (l.text.matches(".*\\{[0-9]+\\}.*"))
aoqi@0 127 return true;
aoqi@0 128 if (!l.hasContinuation())
aoqi@0 129 return false;
aoqi@0 130 l = l.next;
aoqi@0 131 }
aoqi@0 132 }
aoqi@0 133
aoqi@0 134 Set<Integer> getPlaceholders() {
aoqi@0 135 Pattern p = Pattern.compile("\\{([0-9]+)\\}");
aoqi@0 136 Set<Integer> results = new TreeSet<Integer>();
aoqi@0 137 Line l = firstLine;
aoqi@0 138 while (true) {
aoqi@0 139 Matcher m = p.matcher(l.text);
aoqi@0 140 while (m.find())
aoqi@0 141 results.add(Integer.parseInt(m.group(1)));
aoqi@0 142 if (!l.hasContinuation())
aoqi@0 143 return results;
aoqi@0 144 l = l.next;
aoqi@0 145 }
aoqi@0 146 }
aoqi@0 147
aoqi@0 148 /**
aoqi@0 149 * Get the Info object for this message. It may be empty if there
aoqi@0 150 * if no comment preceding the property specification.
aoqi@0 151 */
aoqi@0 152 Info getInfo() {
aoqi@0 153 if (info == null) {
aoqi@0 154 Line l = firstLine.prev;
aoqi@0 155 if (l != null && l.isInfo())
aoqi@0 156 info = new Info(l.text);
aoqi@0 157 else
aoqi@0 158 info = new Info();
aoqi@0 159 }
aoqi@0 160 return info;
aoqi@0 161 }
aoqi@0 162
aoqi@0 163 /**
aoqi@0 164 * Set the Info for this message.
aoqi@0 165 * If there was an info comment preceding the property specification,
aoqi@0 166 * it will be updated; otherwise, one will be inserted.
aoqi@0 167 */
aoqi@0 168 void setInfo(Info info) {
aoqi@0 169 this.info = info;
aoqi@0 170 Line l = firstLine.prev;
aoqi@0 171 if (l != null && l.isInfo())
aoqi@0 172 l.text = info.toComment();
aoqi@0 173 else
aoqi@0 174 firstLine.insertBefore(info.toComment());
aoqi@0 175 }
aoqi@0 176
aoqi@0 177 /**
aoqi@0 178 * Get all the lines pertaining to this message.
aoqi@0 179 */
aoqi@0 180 List<Line> getLines(boolean includeAllPrecedingComments) {
aoqi@0 181 List<Line> lines = new ArrayList<Line>();
aoqi@0 182 Line l = firstLine;
aoqi@0 183 if (includeAllPrecedingComments) {
aoqi@0 184 // scan back to find end of prev message
aoqi@0 185 while (l.prev != null && l.prev.isEmptyOrComment())
aoqi@0 186 l = l.prev;
aoqi@0 187 // skip leading blank lines
aoqi@0 188 while (l.text.isEmpty())
aoqi@0 189 l = l.next;
aoqi@0 190 } else {
aoqi@0 191 if (l.prev != null && l.prev.isInfo())
aoqi@0 192 l = l.prev;
aoqi@0 193 }
aoqi@0 194
aoqi@0 195 // include any preceding lines
aoqi@0 196 for ( ; l != firstLine; l = l.next)
aoqi@0 197 lines.add(l);
aoqi@0 198
aoqi@0 199 // include message lines
aoqi@0 200 for (l = firstLine; l != null && l.hasContinuation(); l = l.next)
aoqi@0 201 lines.add(l);
aoqi@0 202 lines.add(l);
aoqi@0 203
aoqi@0 204 // include trailing blank line if present
aoqi@0 205 l = l.next;
aoqi@0 206 if (l != null && l.text.isEmpty())
aoqi@0 207 lines.add(l);
aoqi@0 208
aoqi@0 209 return lines;
aoqi@0 210 }
aoqi@0 211 }
aoqi@0 212
aoqi@0 213 /**
aoqi@0 214 * An object to represent the comment that may precede the property
aoqi@0 215 * specification in a Message.
aoqi@0 216 * The comment is modelled as a list of fields, where the fields correspond
aoqi@0 217 * to the placeholder values (e.g. {0}, {1}, etc) within the message value.
aoqi@0 218 */
aoqi@0 219 static final class Info {
aoqi@0 220 /**
aoqi@0 221 * An ordered set of descriptions for a placeholder value in a
aoqi@0 222 * message.
aoqi@0 223 */
aoqi@0 224 static class Field {
aoqi@0 225 boolean unused;
aoqi@0 226 Set<String> values;
aoqi@0 227 boolean listOfAny = false;
aoqi@0 228 boolean setOfAny = false;
aoqi@0 229 Field(String s) {
aoqi@0 230 s = s.substring(s.indexOf(": ") + 2);
aoqi@0 231 values = new LinkedHashSet<String>(Arrays.asList(s.split(" or ")));
aoqi@0 232 for (String v: values) {
aoqi@0 233 if (v.startsWith("list of"))
aoqi@0 234 listOfAny = true;
aoqi@0 235 if (v.startsWith("set of"))
aoqi@0 236 setOfAny = true;
aoqi@0 237 }
aoqi@0 238 }
aoqi@0 239
aoqi@0 240 /**
aoqi@0 241 * Return true if this field logically contains all the values of
aoqi@0 242 * another field.
aoqi@0 243 */
aoqi@0 244 boolean contains(Field other) {
aoqi@0 245 if (unused != other.unused)
aoqi@0 246 return false;
aoqi@0 247
aoqi@0 248 for (String v: other.values) {
aoqi@0 249 if (values.contains(v))
aoqi@0 250 continue;
aoqi@0 251 if (v.equals("null") || v.equals("string"))
aoqi@0 252 continue;
aoqi@0 253 if (v.equals("list") && listOfAny)
aoqi@0 254 continue;
aoqi@0 255 if (v.equals("set") && setOfAny)
aoqi@0 256 continue;
aoqi@0 257 return false;
aoqi@0 258 }
aoqi@0 259 return true;
aoqi@0 260 }
aoqi@0 261
aoqi@0 262 /**
aoqi@0 263 * Merge the values of another field into this field.
aoqi@0 264 */
aoqi@0 265 void merge(Field other) {
aoqi@0 266 unused |= other.unused;
aoqi@0 267 values.addAll(other.values);
aoqi@0 268
aoqi@0 269 // cleanup unnecessary entries
aoqi@0 270
aoqi@0 271 if (values.contains("null") && values.size() > 1) {
aoqi@0 272 // "null" is superceded by anything else
aoqi@0 273 values.remove("null");
aoqi@0 274 }
aoqi@0 275
aoqi@0 276 if (values.contains("string") && values.size() > 1) {
aoqi@0 277 // "string" is superceded by anything else
aoqi@0 278 values.remove("string");
aoqi@0 279 }
aoqi@0 280
aoqi@0 281 if (values.contains("list")) {
aoqi@0 282 // list is superceded by "list of ..."
aoqi@0 283 for (String s: values) {
aoqi@0 284 if (s.startsWith("list of ")) {
aoqi@0 285 values.remove("list");
aoqi@0 286 break;
aoqi@0 287 }
aoqi@0 288 }
aoqi@0 289 }
aoqi@0 290
aoqi@0 291 if (values.contains("set")) {
aoqi@0 292 // set is superceded by "set of ..."
aoqi@0 293 for (String s: values) {
aoqi@0 294 if (s.startsWith("set of ")) {
aoqi@0 295 values.remove("set");
aoqi@0 296 break;
aoqi@0 297 }
aoqi@0 298 }
aoqi@0 299 }
aoqi@0 300
aoqi@0 301 if (other.values.contains("unused")) {
aoqi@0 302 values.clear();
aoqi@0 303 values.add("unused");
aoqi@0 304 }
aoqi@0 305 }
aoqi@0 306
aoqi@0 307 void markUnused() {
aoqi@0 308 values = new LinkedHashSet<String>();
aoqi@0 309 values.add("unused");
aoqi@0 310 listOfAny = false;
aoqi@0 311 setOfAny = false;
aoqi@0 312 }
aoqi@0 313
aoqi@0 314 @Override
aoqi@0 315 public String toString() {
aoqi@0 316 return values.toString();
aoqi@0 317 }
aoqi@0 318 }
aoqi@0 319
aoqi@0 320 /** The fields of the Info object. */
aoqi@0 321 List<Field> fields = new ArrayList<Field>();
aoqi@0 322
aoqi@0 323 Info() { }
aoqi@0 324
aoqi@0 325 Info(String text) throws IllegalArgumentException {
aoqi@0 326 if (!text.startsWith("# "))
aoqi@0 327 throw new IllegalArgumentException();
aoqi@0 328 String[] segs = text.substring(2).split(", ");
aoqi@0 329 fields = new ArrayList<Field>();
aoqi@0 330 for (String seg: segs) {
aoqi@0 331 fields.add(new Field(seg));
aoqi@0 332 }
aoqi@0 333 }
aoqi@0 334
aoqi@0 335 Info(Set<String> infos) throws IllegalArgumentException {
aoqi@0 336 for (String s: infos)
aoqi@0 337 merge(new Info(s));
aoqi@0 338 }
aoqi@0 339
aoqi@0 340 boolean isEmpty() {
aoqi@0 341 return fields.isEmpty();
aoqi@0 342 }
aoqi@0 343
aoqi@0 344 boolean contains(Info other) {
aoqi@0 345 if (other.isEmpty())
aoqi@0 346 return true;
aoqi@0 347
aoqi@0 348 if (fields.size() != other.fields.size())
aoqi@0 349 return false;
aoqi@0 350
aoqi@0 351 Iterator<Field> oIter = other.fields.iterator();
aoqi@0 352 for (Field values: fields) {
aoqi@0 353 if (!values.contains(oIter.next()))
aoqi@0 354 return false;
aoqi@0 355 }
aoqi@0 356
aoqi@0 357 return true;
aoqi@0 358 }
aoqi@0 359
aoqi@0 360 void merge(Info other) {
aoqi@0 361 if (fields.isEmpty()) {
aoqi@0 362 fields.addAll(other.fields);
aoqi@0 363 return;
aoqi@0 364 }
aoqi@0 365
aoqi@0 366 if (other.fields.size() != fields.size())
aoqi@0 367 throw new IllegalArgumentException();
aoqi@0 368
aoqi@0 369 Iterator<Field> oIter = other.fields.iterator();
aoqi@0 370 for (Field d: fields) {
aoqi@0 371 d.merge(oIter.next());
aoqi@0 372 }
aoqi@0 373 }
aoqi@0 374
aoqi@0 375 void markUnused(Set<Integer> used) {
aoqi@0 376 for (int i = 0; i < fields.size(); i++) {
aoqi@0 377 if (!used.contains(i))
aoqi@0 378 fields.get(i).markUnused();
aoqi@0 379 }
aoqi@0 380 }
aoqi@0 381
aoqi@0 382 @Override
aoqi@0 383 public String toString() {
aoqi@0 384 return fields.toString();
aoqi@0 385 }
aoqi@0 386
aoqi@0 387 String toComment() {
aoqi@0 388 StringBuilder sb = new StringBuilder();
aoqi@0 389 sb.append("# ");
aoqi@0 390 String sep = "";
aoqi@0 391 int i = 0;
aoqi@0 392 for (Field f: fields) {
aoqi@0 393 sb.append(sep);
aoqi@0 394 sb.append(i++);
aoqi@0 395 sb.append(": ");
aoqi@0 396 sep = "";
aoqi@0 397 for (String s: f.values) {
aoqi@0 398 sb.append(sep);
aoqi@0 399 sb.append(s);
aoqi@0 400 sep = " or ";
aoqi@0 401 }
aoqi@0 402 sep = ", ";
aoqi@0 403 }
aoqi@0 404 return sb.toString();
aoqi@0 405 }
aoqi@0 406 }
aoqi@0 407
aoqi@0 408 Line firstLine;
aoqi@0 409 Line lastLine;
aoqi@0 410 Map<String, Message> messages = new TreeMap<String, Message>();
aoqi@0 411
aoqi@0 412 MessageFile(File file) throws IOException {
aoqi@0 413 Reader in = new FileReader(file);
aoqi@0 414 try {
aoqi@0 415 read(in);
aoqi@0 416 } finally {
aoqi@0 417 in.close();
aoqi@0 418 }
aoqi@0 419 }
aoqi@0 420
aoqi@0 421 MessageFile(Reader in) throws IOException {
aoqi@0 422 read(in);
aoqi@0 423 }
aoqi@0 424
aoqi@0 425 final void read(Reader in) throws IOException {
aoqi@0 426 BufferedReader br = (in instanceof BufferedReader)
aoqi@0 427 ? (BufferedReader) in
aoqi@0 428 : new BufferedReader(in);
aoqi@0 429 String line;
aoqi@0 430 while ((line = br.readLine()) != null) {
aoqi@0 431 Line l;
aoqi@0 432 if (firstLine == null)
aoqi@0 433 l = firstLine = lastLine = new Line(line);
aoqi@0 434 else
aoqi@0 435 l = lastLine.insertAfter(line);
aoqi@0 436 if (line.startsWith("compiler.")) {
aoqi@0 437 int eq = line.indexOf("=");
aoqi@0 438 if (eq > 0)
aoqi@0 439 messages.put(line.substring(0, eq), new Message(l));
aoqi@0 440 }
aoqi@0 441 }
aoqi@0 442 }
aoqi@0 443
aoqi@0 444 void write(File file) throws IOException {
aoqi@0 445 Writer out = new FileWriter(file);
aoqi@0 446 try {
aoqi@0 447 write(out);
aoqi@0 448 } finally {
aoqi@0 449 out.close();
aoqi@0 450 }
aoqi@0 451 }
aoqi@0 452
aoqi@0 453 void write(Writer out) throws IOException {
aoqi@0 454 BufferedWriter bw = (out instanceof BufferedWriter)
aoqi@0 455 ? (BufferedWriter) out
aoqi@0 456 : new BufferedWriter(out);
aoqi@0 457 for (Line l = firstLine; l != null; l = l.next) {
aoqi@0 458 bw.write(l.text);
aoqi@0 459 bw.write("\n"); // always use Unix line endings
aoqi@0 460 }
aoqi@0 461 bw.flush();
aoqi@0 462 }
aoqi@0 463 }

mercurial