mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
7013272: Automatically generate info about how compiler resource keys are used
Reviewed-by: mcimadamore
This commit is contained in:
parent
a184b53cec
commit
de3bde6688
8 changed files with 1859 additions and 65 deletions
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
|
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
|
||||||
This code is free software; you can redistribute it and/or modify it
|
This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -331,7 +331,7 @@
|
||||||
executable="${dist.bin.dir}/javac"
|
executable="${dist.bin.dir}/javac"
|
||||||
srcdir="test/tools/javac/diags"
|
srcdir="test/tools/javac/diags"
|
||||||
destdir="${build.dir}/diag-examples/classes"
|
destdir="${build.dir}/diag-examples/classes"
|
||||||
includes="Example.java,FileManager.java,HTMLWriter.java,RunExamples.java"
|
includes="ArgTypeCompilerFactory.java,Example.java,FileManager.java,HTMLWriter.java,RunExamples.java"
|
||||||
sourcepath=""
|
sourcepath=""
|
||||||
classpath="${dist.lib.dir}/javac.jar"
|
classpath="${dist.lib.dir}/javac.jar"
|
||||||
includeAntRuntime="no"
|
includeAntRuntime="no"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -106,7 +106,7 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * Get a localized string represenation for all the symbols in the input list.
|
* * Get a localized string representation for all the symbols in the input list.
|
||||||
*
|
*
|
||||||
* @param ts symbols to be displayed
|
* @param ts symbols to be displayed
|
||||||
* @param locale the locale in which the string is to be rendered
|
* @param locale the locale in which the string is to be rendered
|
||||||
|
|
File diff suppressed because it is too large
Load diff
346
langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java
Normal file
346
langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.tools.*;
|
||||||
|
|
||||||
|
import com.sun.tools.javac.api.*;
|
||||||
|
import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart;
|
||||||
|
import com.sun.tools.javac.api.Formattable.LocalizedString;
|
||||||
|
import com.sun.tools.javac.code.Flags.Flag;
|
||||||
|
import com.sun.tools.javac.code.Kinds.KindName;
|
||||||
|
import com.sun.tools.javac.code.*;
|
||||||
|
import com.sun.tools.javac.file.*;
|
||||||
|
import com.sun.tools.javac.main.Main;
|
||||||
|
import com.sun.tools.javac.parser.Token;
|
||||||
|
import com.sun.tools.javac.util.*;
|
||||||
|
import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
|
||||||
|
import javax.lang.model.SourceVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiler factory for instances of Example.Compiler that use custom
|
||||||
|
* DiagnosticFormatter and Messages objects to track the types of args
|
||||||
|
* when when localizing diagnostics.
|
||||||
|
* The compiler objects only support "output" mode, not "check" mode.
|
||||||
|
*/
|
||||||
|
class ArgTypeCompilerFactory implements Example.Compiler.Factory {
|
||||||
|
// Same code as Example.Compiler.DefaultFactory, but the names resolve differently
|
||||||
|
public Example.Compiler getCompiler(List<String> opts, boolean verbose) {
|
||||||
|
String first;
|
||||||
|
String[] rest;
|
||||||
|
if (opts == null || opts.isEmpty()) {
|
||||||
|
first = null;
|
||||||
|
rest = new String[0];
|
||||||
|
} else {
|
||||||
|
first = opts.get(0);
|
||||||
|
rest = opts.subList(1, opts.size()).toArray(new String[opts.size() - 1]);
|
||||||
|
}
|
||||||
|
if (first == null || first.equals("jsr199"))
|
||||||
|
return new Jsr199Compiler(verbose, rest);
|
||||||
|
else if (first.equals("simple"))
|
||||||
|
return new SimpleCompiler(verbose);
|
||||||
|
else if (first.equals("backdoor"))
|
||||||
|
return new BackdoorCompiler(verbose);
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException(first);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile using the JSR 199 API. The diagnostics generated are
|
||||||
|
* scanned for resource keys. Not all diagnostic keys are generated
|
||||||
|
* via the JSR 199 API -- for example, rich diagnostics are not directly
|
||||||
|
* accessible, and some diagnostics generated by the file manager may
|
||||||
|
* not be generated (for example, the JSR 199 file manager does not see
|
||||||
|
* -Xlint:path).
|
||||||
|
*/
|
||||||
|
static class Jsr199Compiler extends Example.Compiler {
|
||||||
|
List<String> fmOpts;
|
||||||
|
|
||||||
|
Jsr199Compiler(boolean verbose, String... args) {
|
||||||
|
super(verbose);
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
String arg = args[i];
|
||||||
|
if (arg.equals("-filemanager") && (i + 1 < args.length)) {
|
||||||
|
fmOpts = Arrays.asList(args[++i].split(","));
|
||||||
|
} else
|
||||||
|
throw new IllegalArgumentException(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
|
||||||
|
assert out != null && keys == null;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("run_jsr199: " + opts + " " + files);
|
||||||
|
|
||||||
|
JavacTool tool = JavacTool.create();
|
||||||
|
|
||||||
|
StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);
|
||||||
|
if (fmOpts != null)
|
||||||
|
fm = new FileManager(fm, fmOpts);
|
||||||
|
|
||||||
|
Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
|
||||||
|
|
||||||
|
JavacTaskImpl t = (JavacTaskImpl) tool.getTask(out, fm, null, opts, null, fos);
|
||||||
|
Context c = t.getContext();
|
||||||
|
ArgTypeMessages.preRegister(c);
|
||||||
|
Options options = Options.instance(c);
|
||||||
|
Log.instance(c).setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options));
|
||||||
|
Boolean ok = t.call();
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the test using the standard simple entry point.
|
||||||
|
*/
|
||||||
|
static class SimpleCompiler extends Example.Compiler {
|
||||||
|
SimpleCompiler(boolean verbose) {
|
||||||
|
super(verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
|
||||||
|
assert out != null && keys == null;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("run_simple: " + opts + " " + files);
|
||||||
|
|
||||||
|
List<String> args = new ArrayList<String>();
|
||||||
|
|
||||||
|
args.addAll(opts);
|
||||||
|
for (File f: files)
|
||||||
|
args.add(f.getPath());
|
||||||
|
|
||||||
|
Main main = new Main("javac", out);
|
||||||
|
Context c = new Context() {
|
||||||
|
@Override public void clear() {
|
||||||
|
((JavacFileManager) get(JavaFileManager.class)).close();
|
||||||
|
super.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
JavacFileManager.preRegister(c); // can't create it until Log has been set up
|
||||||
|
ArgTypeDiagnosticFormatter.preRegister(c);
|
||||||
|
ArgTypeMessages.preRegister(c);
|
||||||
|
int result = main.compile(args.toArray(new String[args.size()]), c);
|
||||||
|
|
||||||
|
return (result == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BackdoorCompiler extends Example.Compiler {
|
||||||
|
BackdoorCompiler(boolean verbose) {
|
||||||
|
super(verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
|
||||||
|
assert out != null && keys == null;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("run_simple: " + opts + " " + files);
|
||||||
|
|
||||||
|
List<String> args = new ArrayList<String>(opts);
|
||||||
|
for (File f: files)
|
||||||
|
args.add(f.getPath());
|
||||||
|
|
||||||
|
Context c = new Context();
|
||||||
|
JavacFileManager.preRegister(c); // can't create it until Log has been set up
|
||||||
|
ArgTypeDiagnosticFormatter.preRegister(c);
|
||||||
|
ArgTypeMessages.preRegister(c);
|
||||||
|
com.sun.tools.javac.main.Main m = new com.sun.tools.javac.main.Main("javac", out);
|
||||||
|
int rc = m.compile(args.toArray(new String[args.size()]), c);
|
||||||
|
|
||||||
|
return (rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Custom Javac components">
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diagnostic formatter which reports formats a diag as a series of lines
|
||||||
|
* containing a key, and a possibly empty set of descriptive strings for the
|
||||||
|
* arg types.
|
||||||
|
*/
|
||||||
|
static class ArgTypeDiagnosticFormatter extends AbstractDiagnosticFormatter {
|
||||||
|
static void preRegister(final Context context) {
|
||||||
|
context.put(Log.logKey, new Context.Factory<Log>() {
|
||||||
|
public Log make() {
|
||||||
|
Log log = new Log(context) { };
|
||||||
|
Options options = Options.instance(context);
|
||||||
|
log.setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options));
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgTypeDiagnosticFormatter(Options options) {
|
||||||
|
super(null, new SimpleConfiguration(options,
|
||||||
|
EnumSet.of(DiagnosticPart.SUMMARY,
|
||||||
|
DiagnosticPart.DETAILS,
|
||||||
|
DiagnosticPart.SUBDIAGNOSTICS)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String formatDiagnostic(JCDiagnostic d, Locale locale) {
|
||||||
|
return formatMessage(d, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatMessage(JCDiagnostic d, Locale l) {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
formatMessage(d, buf);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatMessage(JCDiagnostic d, StringBuilder buf) {
|
||||||
|
String key = d.getCode();
|
||||||
|
Object[] args = d.getArgs();
|
||||||
|
// report the primary arg types, without recursing into diag fragments
|
||||||
|
buf.append(getKeyArgsString(key, args));
|
||||||
|
// report details for any diagnostic fragments
|
||||||
|
for (Object arg: args) {
|
||||||
|
if (arg instanceof JCDiagnostic) {
|
||||||
|
buf.append("\n");
|
||||||
|
formatMessage((JCDiagnostic) arg, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// report details for any subdiagnostics
|
||||||
|
for (String s: formatSubdiagnostics(d, null)) {
|
||||||
|
buf.append("\n");
|
||||||
|
buf.append(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRaw() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diagnostic formatter which "localizes" a message as a line
|
||||||
|
* containing a key, and a possibly empty set of descriptive strings for the
|
||||||
|
* arg types.
|
||||||
|
*/
|
||||||
|
static class ArgTypeMessages extends JavacMessages {
|
||||||
|
static void preRegister(final Context c) {
|
||||||
|
c.put(JavacMessages.messagesKey, new Context.Factory<JavacMessages>() {
|
||||||
|
public JavacMessages make() {
|
||||||
|
return new ArgTypeMessages(c) {
|
||||||
|
@Override
|
||||||
|
public String getLocalizedString(Locale l, String key, Object... args) {
|
||||||
|
return getKeyArgsString(key, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgTypeMessages(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to generate a string for key and args
|
||||||
|
*/
|
||||||
|
static String getKeyArgsString(String key, Object... args) {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append(key);
|
||||||
|
String sep = ": ";
|
||||||
|
for (Object o : args) {
|
||||||
|
buf.append(sep);
|
||||||
|
buf.append(getArgTypeOrStringValue(o));
|
||||||
|
sep = ", ";
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean showStringValues = false;
|
||||||
|
|
||||||
|
static String getArgTypeOrStringValue(Object o) {
|
||||||
|
if (showStringValues && o instanceof String)
|
||||||
|
return "\"" + o + "\"";
|
||||||
|
return getArgType(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getArgType(Object o) {
|
||||||
|
if (o == null)
|
||||||
|
return "null";
|
||||||
|
if (o instanceof Name)
|
||||||
|
return "name";
|
||||||
|
if (o instanceof Boolean)
|
||||||
|
return "boolean";
|
||||||
|
if (o instanceof Integer)
|
||||||
|
return "number";
|
||||||
|
if (o instanceof String)
|
||||||
|
return "string";
|
||||||
|
if (o instanceof Flag)
|
||||||
|
return "modifier";
|
||||||
|
if (o instanceof KindName)
|
||||||
|
return "symbol kind";
|
||||||
|
if (o instanceof Token)
|
||||||
|
return "token";
|
||||||
|
if (o instanceof Symbol)
|
||||||
|
return "symbol";
|
||||||
|
if (o instanceof Type)
|
||||||
|
return "type";
|
||||||
|
if (o instanceof List) {
|
||||||
|
List<?> l = (List<?>) o;
|
||||||
|
if (l.isEmpty())
|
||||||
|
return "list";
|
||||||
|
else
|
||||||
|
return "list of " + getArgType(l.get(0));
|
||||||
|
}
|
||||||
|
if (o instanceof ListBuffer)
|
||||||
|
return getArgType(((ListBuffer) o).toList());
|
||||||
|
if (o instanceof Set) {
|
||||||
|
Set<?> s = (Set<?>) o;
|
||||||
|
if (s.isEmpty())
|
||||||
|
return "set";
|
||||||
|
else
|
||||||
|
return "set of " + getArgType(s.iterator().next());
|
||||||
|
}
|
||||||
|
if (o instanceof SourceVersion)
|
||||||
|
return "source version";
|
||||||
|
if (o instanceof FileObject || o instanceof File)
|
||||||
|
return "file name";
|
||||||
|
if (o instanceof JCDiagnostic)
|
||||||
|
return "message segment";
|
||||||
|
if (o instanceof LocalizedString)
|
||||||
|
return "message segment"; // only instance is "no arguments"
|
||||||
|
String s = o.getClass().getSimpleName();
|
||||||
|
return (s.isEmpty() ? o.getClass().getName() : s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// </editor-fold>
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -168,7 +168,7 @@ class Example implements Comparable<Example> {
|
||||||
try {
|
try {
|
||||||
run(null, keys, true, verbose);
|
run(null, keys, true, verbose);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace(System.err);
|
||||||
}
|
}
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
@ -293,10 +293,15 @@ class Example implements Comparable<Example> {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract static class Compiler {
|
abstract static class Compiler {
|
||||||
static Compiler getCompiler(List<String> opts, boolean verbose) {
|
interface Factory {
|
||||||
|
Compiler getCompiler(List<String> opts, boolean verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DefaultFactory implements Factory {
|
||||||
|
public Compiler getCompiler(List<String> opts, boolean verbose) {
|
||||||
String first;
|
String first;
|
||||||
String[] rest;
|
String[] rest;
|
||||||
if (opts == null || opts.size() == 0) {
|
if (opts == null || opts.isEmpty()) {
|
||||||
first = null;
|
first = null;
|
||||||
rest = new String[0];
|
rest = new String[0];
|
||||||
} else {
|
} else {
|
||||||
|
@ -312,6 +317,16 @@ class Example implements Comparable<Example> {
|
||||||
else
|
else
|
||||||
throw new IllegalArgumentException(first);
|
throw new IllegalArgumentException(first);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Factory factory;
|
||||||
|
|
||||||
|
static Compiler getCompiler(List<String> opts, boolean verbose) {
|
||||||
|
if (factory == null)
|
||||||
|
factory = new DefaultFactory();
|
||||||
|
|
||||||
|
return factory.getCompiler(opts, verbose);
|
||||||
|
}
|
||||||
|
|
||||||
protected Compiler(boolean verbose) {
|
protected Compiler(boolean verbose) {
|
||||||
this.verbose = verbose;
|
this.verbose = verbose;
|
||||||
|
|
463
langtools/test/tools/javac/diags/MessageFile.java
Normal file
463
langtools/test/tools/javac/diags/MessageFile.java
Normal file
|
@ -0,0 +1,463 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to facilitate manipulating compiler.properties.
|
||||||
|
*/
|
||||||
|
class MessageFile {
|
||||||
|
static final Pattern emptyOrCommentPattern = Pattern.compile("( *#.*)?");
|
||||||
|
static final Pattern infoPattern = Pattern.compile("# ([0-9]+: [-A-Za-z ]+, )*[0-9]+: [-A-Za-z ]+");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A line of text within the message file.
|
||||||
|
* The lines form a doubly linked list for simple navigation.
|
||||||
|
*/
|
||||||
|
class Line {
|
||||||
|
String text;
|
||||||
|
Line prev;
|
||||||
|
Line next;
|
||||||
|
|
||||||
|
Line(String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isEmptyOrComment() {
|
||||||
|
return emptyOrCommentPattern.matcher(text).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isInfo() {
|
||||||
|
return infoPattern.matcher(text).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasContinuation() {
|
||||||
|
return (next != null) && text.endsWith("\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
Line insertAfter(String text) {
|
||||||
|
Line l = new Line(text);
|
||||||
|
insertAfter(l);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertAfter(Line l) {
|
||||||
|
assert prev == null && next == null;
|
||||||
|
l.prev = this;
|
||||||
|
l.next = next;
|
||||||
|
if (next == null)
|
||||||
|
lastLine = l;
|
||||||
|
else
|
||||||
|
next.prev = l;
|
||||||
|
next = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
Line insertBefore(String text) {
|
||||||
|
Line l = new Line(text);
|
||||||
|
insertBefore(l);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertBefore(Line l) {
|
||||||
|
assert prev == null && next == null;
|
||||||
|
l.prev = prev;
|
||||||
|
l.next = this;
|
||||||
|
if (prev == null)
|
||||||
|
firstLine = l;
|
||||||
|
else
|
||||||
|
prev.next = l;
|
||||||
|
prev = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove() {
|
||||||
|
if (prev == null)
|
||||||
|
firstLine = next;
|
||||||
|
else
|
||||||
|
prev.next = next;
|
||||||
|
if (next == null)
|
||||||
|
lastLine = prev;
|
||||||
|
else
|
||||||
|
next.prev = prev;
|
||||||
|
prev = null;
|
||||||
|
next = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message within the message file.
|
||||||
|
* A message is a series of lines containing a "name=value" property,
|
||||||
|
* optionally preceded by a comment describing the use of placeholders
|
||||||
|
* such as {0}, {1}, etc within the property value.
|
||||||
|
*/
|
||||||
|
static final class Message {
|
||||||
|
final Line firstLine;
|
||||||
|
private Info info;
|
||||||
|
|
||||||
|
Message(Line l) {
|
||||||
|
firstLine = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean needInfo() {
|
||||||
|
Line l = firstLine;
|
||||||
|
while (true) {
|
||||||
|
if (l.text.matches(".*\\{[0-9]+\\}.*"))
|
||||||
|
return true;
|
||||||
|
if (!l.hasContinuation())
|
||||||
|
return false;
|
||||||
|
l = l.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Integer> getPlaceholders() {
|
||||||
|
Pattern p = Pattern.compile("\\{([0-9]+)\\}");
|
||||||
|
Set<Integer> results = new TreeSet<Integer>();
|
||||||
|
Line l = firstLine;
|
||||||
|
while (true) {
|
||||||
|
Matcher m = p.matcher(l.text);
|
||||||
|
while (m.find())
|
||||||
|
results.add(Integer.parseInt(m.group(1)));
|
||||||
|
if (!l.hasContinuation())
|
||||||
|
return results;
|
||||||
|
l = l.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Info object for this message. It may be empty if there
|
||||||
|
* if no comment preceding the property specification.
|
||||||
|
*/
|
||||||
|
Info getInfo() {
|
||||||
|
if (info == null) {
|
||||||
|
Line l = firstLine.prev;
|
||||||
|
if (l != null && l.isInfo())
|
||||||
|
info = new Info(l.text);
|
||||||
|
else
|
||||||
|
info = new Info();
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Info for this message.
|
||||||
|
* If there was an info comment preceding the property specification,
|
||||||
|
* it will be updated; otherwise, one will be inserted.
|
||||||
|
*/
|
||||||
|
void setInfo(Info info) {
|
||||||
|
this.info = info;
|
||||||
|
Line l = firstLine.prev;
|
||||||
|
if (l != null && l.isInfo())
|
||||||
|
l.text = info.toComment();
|
||||||
|
else
|
||||||
|
firstLine.insertBefore(info.toComment());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the lines pertaining to this message.
|
||||||
|
*/
|
||||||
|
List<Line> getLines(boolean includeAllPrecedingComments) {
|
||||||
|
List<Line> lines = new ArrayList<Line>();
|
||||||
|
Line l = firstLine;
|
||||||
|
if (includeAllPrecedingComments) {
|
||||||
|
// scan back to find end of prev message
|
||||||
|
while (l.prev != null && l.prev.isEmptyOrComment())
|
||||||
|
l = l.prev;
|
||||||
|
// skip leading blank lines
|
||||||
|
while (l.text.isEmpty())
|
||||||
|
l = l.next;
|
||||||
|
} else {
|
||||||
|
if (l.prev != null && l.prev.isInfo())
|
||||||
|
l = l.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// include any preceding lines
|
||||||
|
for ( ; l != firstLine; l = l.next)
|
||||||
|
lines.add(l);
|
||||||
|
|
||||||
|
// include message lines
|
||||||
|
for (l = firstLine; l != null && l.hasContinuation(); l = l.next)
|
||||||
|
lines.add(l);
|
||||||
|
lines.add(l);
|
||||||
|
|
||||||
|
// include trailing blank line if present
|
||||||
|
l = l.next;
|
||||||
|
if (l != null && l.text.isEmpty())
|
||||||
|
lines.add(l);
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to represent the comment that may precede the property
|
||||||
|
* specification in a Message.
|
||||||
|
* The comment is modelled as a list of fields, where the fields correspond
|
||||||
|
* to the placeholder values (e.g. {0}, {1}, etc) within the message value.
|
||||||
|
*/
|
||||||
|
static final class Info {
|
||||||
|
/**
|
||||||
|
* An ordered set of descriptions for a placeholder value in a
|
||||||
|
* message.
|
||||||
|
*/
|
||||||
|
static class Field {
|
||||||
|
boolean unused;
|
||||||
|
Set<String> values;
|
||||||
|
boolean listOfAny = false;
|
||||||
|
boolean setOfAny = false;
|
||||||
|
Field(String s) {
|
||||||
|
s = s.substring(s.indexOf(": ") + 2);
|
||||||
|
values = new LinkedHashSet<String>(Arrays.asList(s.split(" or ")));
|
||||||
|
for (String v: values) {
|
||||||
|
if (v.startsWith("list of"))
|
||||||
|
listOfAny = true;
|
||||||
|
if (v.startsWith("set of"))
|
||||||
|
setOfAny = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this field logically contains all the values of
|
||||||
|
* another field.
|
||||||
|
*/
|
||||||
|
boolean contains(Field other) {
|
||||||
|
if (unused != other.unused)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (String v: other.values) {
|
||||||
|
if (values.contains(v))
|
||||||
|
continue;
|
||||||
|
if (v.equals("null") || v.equals("string"))
|
||||||
|
continue;
|
||||||
|
if (v.equals("list") && listOfAny)
|
||||||
|
continue;
|
||||||
|
if (v.equals("set") && setOfAny)
|
||||||
|
continue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge the values of another field into this field.
|
||||||
|
*/
|
||||||
|
void merge(Field other) {
|
||||||
|
unused |= other.unused;
|
||||||
|
values.addAll(other.values);
|
||||||
|
|
||||||
|
// cleanup unnecessary entries
|
||||||
|
|
||||||
|
if (values.contains("null") && values.size() > 1) {
|
||||||
|
// "null" is superceded by anything else
|
||||||
|
values.remove("null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.contains("string") && values.size() > 1) {
|
||||||
|
// "string" is superceded by anything else
|
||||||
|
values.remove("string");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.contains("list")) {
|
||||||
|
// list is superceded by "list of ..."
|
||||||
|
for (String s: values) {
|
||||||
|
if (s.startsWith("list of ")) {
|
||||||
|
values.remove("list");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.contains("set")) {
|
||||||
|
// set is superceded by "set of ..."
|
||||||
|
for (String s: values) {
|
||||||
|
if (s.startsWith("set of ")) {
|
||||||
|
values.remove("set");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other.values.contains("unused")) {
|
||||||
|
values.clear();
|
||||||
|
values.add("unused");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void markUnused() {
|
||||||
|
values = new LinkedHashSet<String>();
|
||||||
|
values.add("unused");
|
||||||
|
listOfAny = false;
|
||||||
|
setOfAny = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return values.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The fields of the Info object. */
|
||||||
|
List<Field> fields = new ArrayList<Field>();
|
||||||
|
|
||||||
|
Info() { }
|
||||||
|
|
||||||
|
Info(String text) throws IllegalArgumentException {
|
||||||
|
if (!text.startsWith("# "))
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
String[] segs = text.substring(2).split(", ");
|
||||||
|
fields = new ArrayList<Field>();
|
||||||
|
for (String seg: segs) {
|
||||||
|
fields.add(new Field(seg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Info(Set<String> infos) throws IllegalArgumentException {
|
||||||
|
for (String s: infos)
|
||||||
|
merge(new Info(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isEmpty() {
|
||||||
|
return fields.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean contains(Info other) {
|
||||||
|
if (other.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (fields.size() != other.fields.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Iterator<Field> oIter = other.fields.iterator();
|
||||||
|
for (Field values: fields) {
|
||||||
|
if (!values.contains(oIter.next()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge(Info other) {
|
||||||
|
if (fields.isEmpty()) {
|
||||||
|
fields.addAll(other.fields);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other.fields.size() != fields.size())
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
|
||||||
|
Iterator<Field> oIter = other.fields.iterator();
|
||||||
|
for (Field d: fields) {
|
||||||
|
d.merge(oIter.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void markUnused(Set<Integer> used) {
|
||||||
|
for (int i = 0; i < fields.size(); i++) {
|
||||||
|
if (!used.contains(i))
|
||||||
|
fields.get(i).markUnused();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return fields.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String toComment() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("# ");
|
||||||
|
String sep = "";
|
||||||
|
int i = 0;
|
||||||
|
for (Field f: fields) {
|
||||||
|
sb.append(sep);
|
||||||
|
sb.append(i++);
|
||||||
|
sb.append(": ");
|
||||||
|
sep = "";
|
||||||
|
for (String s: f.values) {
|
||||||
|
sb.append(sep);
|
||||||
|
sb.append(s);
|
||||||
|
sep = " or ";
|
||||||
|
}
|
||||||
|
sep = ", ";
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Line firstLine;
|
||||||
|
Line lastLine;
|
||||||
|
Map<String, Message> messages = new TreeMap<String, Message>();
|
||||||
|
|
||||||
|
MessageFile(File file) throws IOException {
|
||||||
|
Reader in = new FileReader(file);
|
||||||
|
try {
|
||||||
|
read(in);
|
||||||
|
} finally {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFile(Reader in) throws IOException {
|
||||||
|
read(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
final void read(Reader in) throws IOException {
|
||||||
|
BufferedReader br = (in instanceof BufferedReader)
|
||||||
|
? (BufferedReader) in
|
||||||
|
: new BufferedReader(in);
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
Line l;
|
||||||
|
if (firstLine == null)
|
||||||
|
l = firstLine = lastLine = new Line(line);
|
||||||
|
else
|
||||||
|
l = lastLine.insertAfter(line);
|
||||||
|
if (line.startsWith("compiler.")) {
|
||||||
|
int eq = line.indexOf("=");
|
||||||
|
if (eq > 0)
|
||||||
|
messages.put(line.substring(0, eq), new Message(l));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(File file) throws IOException {
|
||||||
|
Writer out = new FileWriter(file);
|
||||||
|
try {
|
||||||
|
write(out);
|
||||||
|
} finally {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(Writer out) throws IOException {
|
||||||
|
BufferedWriter bw = (out instanceof BufferedWriter)
|
||||||
|
? (BufferedWriter) out
|
||||||
|
: new BufferedWriter(out);
|
||||||
|
for (Line l = firstLine; l != null; l = l.next) {
|
||||||
|
bw.write(l.text);
|
||||||
|
bw.write("\n"); // always use Unix line endings
|
||||||
|
}
|
||||||
|
bw.flush();
|
||||||
|
}
|
||||||
|
}
|
406
langtools/test/tools/javac/diags/MessageInfo.java
Normal file
406
langtools/test/tools/javac/diags/MessageInfo.java
Normal file
|
@ -0,0 +1,406 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 7013272
|
||||||
|
* @summary Automatically generate info about how compiler resource keys are used
|
||||||
|
* @build Example ArgTypeCompilerFactory MessageFile MessageInfo
|
||||||
|
* @run main MessageInfo
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to manipulate compiler.properties, and suggest info comments based
|
||||||
|
* on information derived from running examples.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
* -examples dir location of examples directory
|
||||||
|
* -o file output file
|
||||||
|
* -check just check message file
|
||||||
|
* -ensureNewlines ensure newline after each entry
|
||||||
|
* -fixIndent fix indentation of continuation lines
|
||||||
|
* -sort sort messages
|
||||||
|
* -verbose verbose output
|
||||||
|
* -replace replace comments instead of merging comments
|
||||||
|
* file javac compiler.properties file
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MessageInfo {
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
jtreg = (System.getProperty("test.src") != null);
|
||||||
|
File tmpDir;
|
||||||
|
if (jtreg) {
|
||||||
|
// use standard jtreg scratch directory: the current directory
|
||||||
|
tmpDir = new File(System.getProperty("user.dir"));
|
||||||
|
} else {
|
||||||
|
tmpDir = new File(System.getProperty("java.io.tmpdir"),
|
||||||
|
MessageInfo.class.getName()
|
||||||
|
+ (new SimpleDateFormat("yyMMddHHmmss")).format(new Date()));
|
||||||
|
}
|
||||||
|
Example.setTempDir(tmpDir);
|
||||||
|
Example.Compiler.factory = new ArgTypeCompilerFactory();
|
||||||
|
|
||||||
|
MessageInfo mi = new MessageInfo();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (mi.run(args))
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
/* VERY IMPORTANT NOTE. In jtreg mode, tmpDir is set to the
|
||||||
|
* jtreg scratch directory, which is the current directory.
|
||||||
|
* In case someone is faking jtreg mode, make sure to only
|
||||||
|
* clean tmpDir when it is reasonable to do so.
|
||||||
|
*/
|
||||||
|
if (tmpDir.isDirectory() &&
|
||||||
|
tmpDir.getName().startsWith(MessageInfo.class.getName())) {
|
||||||
|
if (clean(tmpDir))
|
||||||
|
tmpDir.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jtreg)
|
||||||
|
throw new Exception(mi.errors + " errors occurred");
|
||||||
|
else
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage() {
|
||||||
|
System.out.println("Usage:");
|
||||||
|
System.out.println(" java MessageInfo [options] [file]");
|
||||||
|
System.out.println("where options include");
|
||||||
|
System.out.println(" -examples dir location of examples directory");
|
||||||
|
System.out.println(" -o file output file");
|
||||||
|
System.out.println(" -check just check message file");
|
||||||
|
System.out.println(" -ensureNewlines ensure newline after each entry");
|
||||||
|
System.out.println(" -fixIndent fix indentation of continuation lines");
|
||||||
|
System.out.println(" -sort sort messages");
|
||||||
|
System.out.println(" -verbose verbose output");
|
||||||
|
System.out.println(" -replace replace comments instead of merging comments");
|
||||||
|
System.out.println(" file javac compiler.properties file");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean run(String... args) {
|
||||||
|
File testSrc = new File(System.getProperty("test.src", "."));
|
||||||
|
File examplesDir = new File(testSrc, "examples");
|
||||||
|
File notYetFile = null;
|
||||||
|
File msgFile = null;
|
||||||
|
File outFile = null;
|
||||||
|
boolean verbose = false;
|
||||||
|
boolean ensureNewlines = false;
|
||||||
|
boolean fixIndent = false;
|
||||||
|
boolean sort = false;
|
||||||
|
boolean replace = false;
|
||||||
|
boolean check = jtreg; // default true in jtreg mode
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
String arg = args[i];
|
||||||
|
if (arg.equals("-examples") && (i + 1) < args.length)
|
||||||
|
examplesDir = new File(args[++i]);
|
||||||
|
else if(arg.equals("-notyet") && (i + 1) < args.length)
|
||||||
|
notYetFile = new File(args[++i]);
|
||||||
|
else if (arg.equals("-ensureNewlines"))
|
||||||
|
ensureNewlines = true;
|
||||||
|
else if (arg.equals("-fixIndent"))
|
||||||
|
fixIndent = true;
|
||||||
|
else if (arg.equals("-sort"))
|
||||||
|
sort = true;
|
||||||
|
else if (arg.equals("-verbose"))
|
||||||
|
verbose = true;
|
||||||
|
else if (arg.equals("-replace"))
|
||||||
|
replace = true;
|
||||||
|
else if (arg.equals("-check"))
|
||||||
|
check = true;
|
||||||
|
else if (arg.equals("-o") && (i + 1) < args.length)
|
||||||
|
outFile = new File(args[++i]);
|
||||||
|
else if (arg.startsWith("-")) {
|
||||||
|
error("unknown option: " + arg);
|
||||||
|
return false;
|
||||||
|
} else if (i == args.length - 1) {
|
||||||
|
msgFile = new File(arg);
|
||||||
|
} else {
|
||||||
|
error("unknown arg: " + arg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check && outFile == null) {
|
||||||
|
usage();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ensureNewlines || fixIndent || sort) && outFile == null) {
|
||||||
|
error("must set output file for these options");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notYetFile == null) {
|
||||||
|
notYetFile = new File(examplesDir.getParentFile(), "examples.not-yet.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msgFile == null) {
|
||||||
|
for (File d = testSrc; d != null; d = d.getParentFile()) {
|
||||||
|
if (new File(d, "TEST.ROOT").exists()) {
|
||||||
|
d = d.getParentFile();
|
||||||
|
File f = new File(d, "src/share/classes/com/sun/tools/javac/resources/compiler.properties");
|
||||||
|
if (f.exists()) {
|
||||||
|
msgFile = f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (msgFile == null) {
|
||||||
|
error("no message file available");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFile mf;
|
||||||
|
try {
|
||||||
|
mf = new MessageFile(msgFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
error("problem reading message file: " + e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Set<String>> msgInfo = runExamples(examplesDir, verbose);
|
||||||
|
|
||||||
|
if (ensureNewlines)
|
||||||
|
ensureNewlines(mf);
|
||||||
|
|
||||||
|
if (fixIndent)
|
||||||
|
fixIndent(mf);
|
||||||
|
|
||||||
|
if (sort)
|
||||||
|
sort(mf, true);
|
||||||
|
|
||||||
|
for (Map.Entry<String, Set<String>> e: msgInfo.entrySet()) {
|
||||||
|
String k = e.getKey();
|
||||||
|
Set<String> suggestions = e.getValue();
|
||||||
|
MessageFile.Message m = mf.messages.get(k);
|
||||||
|
if (m == null) {
|
||||||
|
error("Can't find message for " + k + " in message file");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFile.Info info = m.getInfo();
|
||||||
|
Set<Integer> placeholders = m.getPlaceholders();
|
||||||
|
MessageFile.Info suggestedInfo = new MessageFile.Info(suggestions);
|
||||||
|
suggestedInfo.markUnused(placeholders);
|
||||||
|
|
||||||
|
if (!info.isEmpty()) {
|
||||||
|
if (info.contains(suggestedInfo))
|
||||||
|
continue;
|
||||||
|
if (!replace) {
|
||||||
|
if (info.fields.size() != suggestedInfo.fields.size())
|
||||||
|
error("Cannot merge info for " + k);
|
||||||
|
else
|
||||||
|
suggestedInfo.merge(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outFile == null) {
|
||||||
|
System.err.println("suggest for " + k);
|
||||||
|
System.err.println(suggestedInfo.toComment());
|
||||||
|
} else
|
||||||
|
m.setInfo(suggestedInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check)
|
||||||
|
check(mf, notYetFile);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (outFile != null)
|
||||||
|
mf.write(outFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
error("problem writing file: " + e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (errors == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void check(MessageFile mf, File notYetFile) {
|
||||||
|
Set<String> notYetList = null;
|
||||||
|
for (Map.Entry<String, MessageFile.Message> e: mf.messages.entrySet()) {
|
||||||
|
String key = e.getKey();
|
||||||
|
MessageFile.Message m = e.getValue();
|
||||||
|
if (m.needInfo() && m.getInfo().isEmpty()) {
|
||||||
|
if (notYetList == null)
|
||||||
|
notYetList = getNotYetList(notYetFile);
|
||||||
|
if (notYetList.contains(key))
|
||||||
|
System.err.println("Warning: no info for " + key);
|
||||||
|
else
|
||||||
|
error("no info for " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensureNewlines(MessageFile mf) {
|
||||||
|
for (MessageFile.Message m: mf.messages.values()) {
|
||||||
|
MessageFile.Line l = m.firstLine;
|
||||||
|
while (l.text.endsWith("\\"))
|
||||||
|
l = l.next;
|
||||||
|
if (l.next != null && !l.next.text.isEmpty())
|
||||||
|
l.insertAfter("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixIndent(MessageFile mf) {
|
||||||
|
for (MessageFile.Message m: mf.messages.values()) {
|
||||||
|
MessageFile.Line l = m.firstLine;
|
||||||
|
while (l.text.endsWith("\\") && l.next != null) {
|
||||||
|
if (!l.next.text.matches("^ \\S.*"))
|
||||||
|
l.next.text = " " + l.next.text.trim();
|
||||||
|
l = l.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sort(MessageFile mf, boolean includePrecedingNewlines) {
|
||||||
|
for (MessageFile.Message m: mf.messages.values()) {
|
||||||
|
for (MessageFile.Line l: m.getLines(includePrecedingNewlines)) {
|
||||||
|
l.remove();
|
||||||
|
mf.lastLine.insertAfter(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Set<String>> runExamples(File examplesDir, boolean verbose) {
|
||||||
|
Map<String, Set<String>> map = new TreeMap<String, Set<String>>();
|
||||||
|
for (Example e: getExamples(examplesDir)) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
e.run(pw, true, verbose);
|
||||||
|
pw.close();
|
||||||
|
String[] lines = sw.toString().split("\n");
|
||||||
|
for (String line: lines) {
|
||||||
|
if (!line.startsWith("compiler."))
|
||||||
|
continue;
|
||||||
|
int colon = line.indexOf(":");
|
||||||
|
if (colon == -1)
|
||||||
|
continue;
|
||||||
|
String key = line.substring(0, colon);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("# ");
|
||||||
|
int i = 0;
|
||||||
|
String[] descs = line.substring(colon + 1).split(", *");
|
||||||
|
for (String desc: descs) {
|
||||||
|
if (i > 0) sb.append(", ");
|
||||||
|
sb.append(i++);
|
||||||
|
sb.append(": ");
|
||||||
|
sb.append(desc.trim());
|
||||||
|
}
|
||||||
|
Set<String> set = map.get(key);
|
||||||
|
if (set == null)
|
||||||
|
map.put(key, set = new TreeSet<String>());
|
||||||
|
set.add(sb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the complete set of examples to be checked.
|
||||||
|
*/
|
||||||
|
Set<Example> getExamples(File examplesDir) {
|
||||||
|
Set<Example> results = new TreeSet<Example>();
|
||||||
|
for (File f: examplesDir.listFiles()) {
|
||||||
|
if (isValidExample(f))
|
||||||
|
results.add(new Example(f));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isValidExample(File f) {
|
||||||
|
return (f.isDirectory() && (!jtreg || f.list().length > 0)) ||
|
||||||
|
(f.isFile() && f.getName().endsWith(".java"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the contents of the "not-yet" list.
|
||||||
|
*/
|
||||||
|
Set<String> getNotYetList(File file) {
|
||||||
|
Set<String> results = new TreeSet<String>();
|
||||||
|
try {
|
||||||
|
String[] lines = read(file).split("[\r\n]");
|
||||||
|
for (String line: lines) {
|
||||||
|
int hash = line.indexOf("#");
|
||||||
|
if (hash != -1)
|
||||||
|
line = line.substring(0, hash).trim();
|
||||||
|
if (line.matches("[A-Za-z0-9-_.]+"))
|
||||||
|
results.add(line);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the contents of a file.
|
||||||
|
*/
|
||||||
|
String read(File f) throws IOException {
|
||||||
|
byte[] bytes = new byte[(int) f.length()];
|
||||||
|
DataInputStream in = new DataInputStream(new FileInputStream(f));
|
||||||
|
try {
|
||||||
|
in.readFully(bytes);
|
||||||
|
} finally {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
return new String(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report an error.
|
||||||
|
*/
|
||||||
|
void error(String msg) {
|
||||||
|
System.err.println("Error: " + msg);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean jtreg;
|
||||||
|
|
||||||
|
int errors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean the contents of a directory.
|
||||||
|
*/
|
||||||
|
static boolean clean(File dir) {
|
||||||
|
boolean ok = true;
|
||||||
|
for (File f: dir.listFiles()) {
|
||||||
|
if (f.isDirectory())
|
||||||
|
ok &= clean(f);
|
||||||
|
ok &= f.delete();
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
* @test
|
* @test
|
||||||
* @bug 6968063
|
* @bug 6968063
|
||||||
* @summary provide examples of code that generate diagnostics
|
* @summary provide examples of code that generate diagnostics
|
||||||
* @build Example HTMLWriter RunExamples
|
* @build ArgTypeCompilerFactory Example HTMLWriter RunExamples
|
||||||
* @run main RunExamples
|
* @run main RunExamples
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -97,6 +97,7 @@ public class RunExamples {
|
||||||
boolean raw = false;
|
boolean raw = false;
|
||||||
boolean showFiles = false;
|
boolean showFiles = false;
|
||||||
boolean verbose = false;
|
boolean verbose = false;
|
||||||
|
boolean argTypes = false;
|
||||||
String title = null;
|
String title = null;
|
||||||
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
@ -115,6 +116,8 @@ public class RunExamples {
|
||||||
outFile = new File(args[++i]);
|
outFile = new File(args[++i]);
|
||||||
else if (arg.equals("-title") && (i + 1) < args.length)
|
else if (arg.equals("-title") && (i + 1) < args.length)
|
||||||
title = args[++i];
|
title = args[++i];
|
||||||
|
else if (arg.equals("-argtypes"))
|
||||||
|
argTypes = true;
|
||||||
else if (arg.startsWith("-")) {
|
else if (arg.startsWith("-")) {
|
||||||
error("unknown option: " + arg);
|
error("unknown option: " + arg);
|
||||||
return false;
|
return false;
|
||||||
|
@ -127,6 +130,11 @@ public class RunExamples {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// special mode to show message keys and the types of the args that
|
||||||
|
// are used.
|
||||||
|
if (argTypes)
|
||||||
|
Example.Compiler.factory = new ArgTypeCompilerFactory();
|
||||||
|
|
||||||
if (selectedKeys.size() > 0) {
|
if (selectedKeys.size() > 0) {
|
||||||
Set<Example> examples = getExamples(examplesDir);
|
Set<Example> examples = getExamples(examplesDir);
|
||||||
nextKey:
|
nextKey:
|
||||||
|
@ -138,7 +146,7 @@ public class RunExamples {
|
||||||
error("Key " + k + ": no examples found");
|
error("Key " + k + ": no examples found");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (selectedExamples.size() == 0)
|
if (selectedExamples.isEmpty())
|
||||||
selectedExamples = getExamples(examplesDir);
|
selectedExamples = getExamples(examplesDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue