feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 1999, 2005, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/** Throwing an instance of
* this class causes (silent) termination of the main compiler method.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Abort extends Error {
private static final long serialVersionUID = 0;
public Abort(Throwable cause) {
super(cause);
}
public Abort() {
super();
}
}

View File

@@ -0,0 +1,533 @@
/*
* Copyright (c) 2008, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.api.DiagnosticFormatter;
import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart;
import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.MultilineLimit;
import com.sun.tools.javac.api.DiagnosticFormatter.PositionKind;
import com.sun.tools.javac.api.Formattable;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Printer;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.CapturedType;
import com.sun.tools.javac.file.BaseFileObject;
import com.sun.tools.javac.jvm.Profile;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.Pretty;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
/**
* This abstract class provides a basic implementation of the functionalities that should be provided
* by any formatter used by javac. Among the main features provided by AbstractDiagnosticFormatter are:
*
* <ul>
* <li> Provides a standard implementation of the visitor-like methods defined in the interface DiagnisticFormatter.
* Those implementations are specifically targeting JCDiagnostic objects.
* <li> Provides basic support for i18n and a method for executing all locale-dependent conversions
* <li> Provides the formatting logic for rendering the arguments of a JCDiagnostic object.
* <ul>
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter<JCDiagnostic> {
/**
* JavacMessages object used by this formatter for i18n.
*/
protected JavacMessages messages;
/**
* Configuration object used by this formatter
*/
private SimpleConfiguration config;
/**
* Current depth level of the disgnostic being formatted
* (!= 0 for subdiagnostics)
*/
protected int depth = 0;
/**
* All captured types that have been encountered during diagnostic formatting.
* This info is used by the FormatterPrinter in order to print friendly unique
* ids for captured types
*/
private List<Type> allCaptured = List.nil();
/**
* Initialize an AbstractDiagnosticFormatter by setting its JavacMessages object.
* @param messages
*/
protected AbstractDiagnosticFormatter(JavacMessages messages, SimpleConfiguration config) {
this.messages = messages;
this.config = config;
}
public String formatKind(JCDiagnostic d, Locale l) {
switch (d.getType()) {
case FRAGMENT: return "";
case NOTE: return localize(l, "compiler.note.note");
case WARNING: return localize(l, "compiler.warn.warning");
case ERROR: return localize(l, "compiler.err.error");
default:
throw new AssertionError("Unknown diagnostic type: " + d.getType());
}
}
@Override
public String format(JCDiagnostic d, Locale locale) {
allCaptured = List.nil();
return formatDiagnostic(d, locale);
}
protected abstract String formatDiagnostic(JCDiagnostic d, Locale locale);
public String formatPosition(JCDiagnostic d, PositionKind pk,Locale l) {
Assert.check(d.getPosition() != Position.NOPOS);
return String.valueOf(getPosition(d, pk));
}
//where
private long getPosition(JCDiagnostic d, PositionKind pk) {
switch (pk) {
case START: return d.getIntStartPosition();
case END: return d.getIntEndPosition();
case LINE: return d.getLineNumber();
case COLUMN: return d.getColumnNumber();
case OFFSET: return d.getIntPosition();
default:
throw new AssertionError("Unknown diagnostic position: " + pk);
}
}
public String formatSource(JCDiagnostic d, boolean fullname, Locale l) {
JavaFileObject fo = d.getSource();
if (fo == null)
throw new IllegalArgumentException(); // d should have source set
if (fullname)
return fo.getName();
else if (fo instanceof BaseFileObject)
return ((BaseFileObject) fo).getShortName();
else
return BaseFileObject.getSimpleName(fo);
}
/**
* Format the arguments of a given diagnostic.
*
* @param d diagnostic whose arguments are to be formatted
* @param l locale object to be used for i18n
* @return a Collection whose elements are the formatted arguments of the diagnostic
*/
protected Collection<String> formatArguments(JCDiagnostic d, Locale l) {
ListBuffer<String> buf = new ListBuffer<String>();
for (Object o : d.getArgs()) {
buf.append(formatArgument(d, o, l));
}
return buf.toList();
}
/**
* Format a single argument of a given diagnostic.
*
* @param d diagnostic whose argument is to be formatted
* @param arg argument to be formatted
* @param l locale object to be used for i18n
* @return string representation of the diagnostic argument
*/
protected String formatArgument(JCDiagnostic d, Object arg, Locale l) {
if (arg instanceof JCDiagnostic) {
String s = null;
depth++;
try {
s = formatMessage((JCDiagnostic)arg, l);
}
finally {
depth--;
}
return s;
}
else if (arg instanceof JCExpression) {
return expr2String((JCExpression)arg);
}
else if (arg instanceof Iterable<?>) {
return formatIterable(d, (Iterable<?>)arg, l);
}
else if (arg instanceof Type) {
return printer.visit((Type)arg, l);
}
else if (arg instanceof Symbol) {
return printer.visit((Symbol)arg, l);
}
else if (arg instanceof JavaFileObject) {
return ((JavaFileObject)arg).getName();
}
else if (arg instanceof Profile) {
return ((Profile)arg).name;
}
else if (arg instanceof Formattable) {
return ((Formattable)arg).toString(l, messages);
}
else {
return String.valueOf(arg);
}
}
//where
private String expr2String(JCExpression tree) {
switch(tree.getTag()) {
case PARENS:
return expr2String(((JCParens)tree).expr);
case LAMBDA:
case REFERENCE:
case CONDEXPR:
return Pretty.toSimpleString(tree);
default:
Assert.error("unexpected tree kind " + tree.getKind());
return null;
}
}
/**
* Format an iterable argument of a given diagnostic.
*
* @param d diagnostic whose argument is to be formatted
* @param it iterable argument to be formatted
* @param l locale object to be used for i18n
* @return string representation of the diagnostic iterable argument
*/
protected String formatIterable(JCDiagnostic d, Iterable<?> it, Locale l) {
StringBuilder sbuf = new StringBuilder();
String sep = "";
for (Object o : it) {
sbuf.append(sep);
sbuf.append(formatArgument(d, o, l));
sep = ",";
}
return sbuf.toString();
}
/**
* Format all the subdiagnostics attached to a given diagnostic.
*
* @param d diagnostic whose subdiagnostics are to be formatted
* @param l locale object to be used for i18n
* @return list of all string representations of the subdiagnostics
*/
protected List<String> formatSubdiagnostics(JCDiagnostic d, Locale l) {
List<String> subdiagnostics = List.nil();
int maxDepth = config.getMultilineLimit(MultilineLimit.DEPTH);
if (maxDepth == -1 || depth < maxDepth) {
depth++;
try {
int maxCount = config.getMultilineLimit(MultilineLimit.LENGTH);
int count = 0;
for (JCDiagnostic d2 : d.getSubdiagnostics()) {
if (maxCount == -1 || count < maxCount) {
subdiagnostics = subdiagnostics.append(formatSubdiagnostic(d, d2, l));
count++;
}
else
break;
}
}
finally {
depth--;
}
}
return subdiagnostics;
}
/**
* Format a subdiagnostics attached to a given diagnostic.
*
* @param parent multiline diagnostic whose subdiagnostics is to be formatted
* @param sub subdiagnostic to be formatted
* @param l locale object to be used for i18n
* @return string representation of the subdiagnostics
*/
protected String formatSubdiagnostic(JCDiagnostic parent, JCDiagnostic sub, Locale l) {
return formatMessage(sub, l);
}
/** Format the faulty source code line and point to the error.
* @param d The diagnostic for which the error line should be printed
*/
protected String formatSourceLine(JCDiagnostic d, int nSpaces) {
StringBuilder buf = new StringBuilder();
DiagnosticSource source = d.getDiagnosticSource();
int pos = d.getIntPosition();
if (d.getIntPosition() == Position.NOPOS)
throw new AssertionError();
String line = (source == null ? null : source.getLine(pos));
if (line == null)
return "";
buf.append(indent(line, nSpaces));
int col = source.getColumnNumber(pos, false);
if (config.isCaretEnabled()) {
buf.append("\n");
for (int i = 0; i < col - 1; i++) {
buf.append((line.charAt(i) == '\t') ? "\t" : " ");
}
buf.append(indent("^", nSpaces));
}
return buf.toString();
}
protected String formatLintCategory(JCDiagnostic d, Locale l) {
LintCategory lc = d.getLintCategory();
if (lc == null)
return "";
return localize(l, "compiler.warn.lintOption", lc.option);
}
/**
* Converts a String into a locale-dependent representation accordingly to a given locale.
*
* @param l locale object to be used for i18n
* @param key locale-independent key used for looking up in a resource file
* @param args localization arguments
* @return a locale-dependent string
*/
protected String localize(Locale l, String key, Object... args) {
return messages.getLocalizedString(l, key, args);
}
public boolean displaySource(JCDiagnostic d) {
return config.getVisible().contains(DiagnosticPart.SOURCE) &&
d.getType() != FRAGMENT &&
d.getIntPosition() != Position.NOPOS;
}
public boolean isRaw() {
return false;
}
/**
* Creates a string with a given amount of empty spaces. Useful for
* indenting the text of a diagnostic message.
*
* @param nSpaces the amount of spaces to be added to the result string
* @return the indentation string
*/
protected String indentString(int nSpaces) {
String spaces = " ";
if (nSpaces <= spaces.length())
return spaces.substring(0, nSpaces);
else {
StringBuilder buf = new StringBuilder();
for (int i = 0 ; i < nSpaces ; i++)
buf.append(" ");
return buf.toString();
}
}
/**
* Indent a string by prepending a given amount of empty spaces to each line
* of the string.
*
* @param s the string to be indented
* @param nSpaces the amount of spaces that should be prepended to each line
* of the string
* @return an indented string
*/
protected String indent(String s, int nSpaces) {
String indent = indentString(nSpaces);
StringBuilder buf = new StringBuilder();
String nl = "";
for (String line : s.split("\n")) {
buf.append(nl);
buf.append(indent + line);
nl = "\n";
}
return buf.toString();
}
public SimpleConfiguration getConfiguration() {
return config;
}
static public class SimpleConfiguration implements Configuration {
protected Map<MultilineLimit, Integer> multilineLimits;
protected EnumSet<DiagnosticPart> visibleParts;
protected boolean caretEnabled;
public SimpleConfiguration(Set<DiagnosticPart> parts) {
multilineLimits = new HashMap<MultilineLimit, Integer>();
setVisible(parts);
setMultilineLimit(MultilineLimit.DEPTH, -1);
setMultilineLimit(MultilineLimit.LENGTH, -1);
setCaretEnabled(true);
}
@SuppressWarnings("fallthrough")
public SimpleConfiguration(Options options, Set<DiagnosticPart> parts) {
this(parts);
String showSource = null;
if ((showSource = options.get("showSource")) != null) {
if (showSource.equals("true"))
setVisiblePart(DiagnosticPart.SOURCE, true);
else if (showSource.equals("false"))
setVisiblePart(DiagnosticPart.SOURCE, false);
}
String diagOpts = options.get("diags");
if (diagOpts != null) {//override -XDshowSource
Collection<String> args = Arrays.asList(diagOpts.split(","));
if (args.contains("short")) {
setVisiblePart(DiagnosticPart.DETAILS, false);
setVisiblePart(DiagnosticPart.SUBDIAGNOSTICS, false);
}
if (args.contains("source"))
setVisiblePart(DiagnosticPart.SOURCE, true);
if (args.contains("-source"))
setVisiblePart(DiagnosticPart.SOURCE, false);
}
String multiPolicy = null;
if ((multiPolicy = options.get("multilinePolicy")) != null) {
if (multiPolicy.equals("disabled"))
setVisiblePart(DiagnosticPart.SUBDIAGNOSTICS, false);
else if (multiPolicy.startsWith("limit:")) {
String limitString = multiPolicy.substring("limit:".length());
String[] limits = limitString.split(":");
try {
switch (limits.length) {
case 2: {
if (!limits[1].equals("*"))
setMultilineLimit(MultilineLimit.DEPTH, Integer.parseInt(limits[1]));
}
case 1: {
if (!limits[0].equals("*"))
setMultilineLimit(MultilineLimit.LENGTH, Integer.parseInt(limits[0]));
}
}
}
catch(NumberFormatException ex) {
setMultilineLimit(MultilineLimit.DEPTH, -1);
setMultilineLimit(MultilineLimit.LENGTH, -1);
}
}
}
String showCaret = null;
if (((showCaret = options.get("showCaret")) != null) &&
showCaret.equals("false"))
setCaretEnabled(false);
else
setCaretEnabled(true);
}
public int getMultilineLimit(MultilineLimit limit) {
return multilineLimits.get(limit);
}
public EnumSet<DiagnosticPart> getVisible() {
return EnumSet.copyOf(visibleParts);
}
public void setMultilineLimit(MultilineLimit limit, int value) {
multilineLimits.put(limit, value < -1 ? -1 : value);
}
public void setVisible(Set<DiagnosticPart> diagParts) {
visibleParts = EnumSet.copyOf(diagParts);
}
public void setVisiblePart(DiagnosticPart diagParts, boolean enabled) {
if (enabled)
visibleParts.add(diagParts);
else
visibleParts.remove(diagParts);
}
/**
* Shows a '^' sign under the source line displayed by the formatter
* (if applicable).
*
* @param caretEnabled if true enables caret
*/
public void setCaretEnabled(boolean caretEnabled) {
this.caretEnabled = caretEnabled;
}
/**
* Tells whether the caret display is active or not.
*
* @return true if the caret is enabled
*/
public boolean isCaretEnabled() {
return caretEnabled;
}
}
public Printer getPrinter() {
return printer;
}
public void setPrinter(Printer printer) {
this.printer = printer;
}
/**
* An enhanced printer for formatting types/symbols used by
* AbstractDiagnosticFormatter. Provides alternate numbering of captured
* types (they are numbered starting from 1 on each new diagnostic, instead
* of relying on the underlying hashcode() method which generates unstable
* output). Also detects cycles in wildcard messages (e.g. if the wildcard
* type referred by a given captured type C contains C itself) which might
* lead to infinite loops.
*/
protected Printer printer = new Printer() {
@Override
protected String localize(Locale locale, String key, Object... args) {
return AbstractDiagnosticFormatter.this.localize(locale, key, args);
}
@Override
protected String capturedVarId(CapturedType t, Locale locale) {
return "" + (allCaptured.indexOf(t) + 1);
}
@Override
public String visitCapturedType(CapturedType t, Locale locale) {
if (!allCaptured.contains(t)) {
allCaptured = allCaptured.append(t);
}
return super.visitCapturedType(t, locale);
}
};
}

View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 1999, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.HashMap;
import java.util.Map;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
/**
* A base class for error logs. Reports errors and warnings, and
* keeps track of error numbers and positions.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public abstract class AbstractLog {
AbstractLog(JCDiagnostic.Factory diags) {
this.diags = diags;
sourceMap = new HashMap<JavaFileObject, DiagnosticSource>();
}
/** Re-assign source, returning previous setting.
*/
public JavaFileObject useSource(JavaFileObject file) {
JavaFileObject prev = (source == null ? null : source.getFile());
source = getSource(file);
return prev;
}
protected DiagnosticSource getSource(JavaFileObject file) {
if (file == null)
return DiagnosticSource.NO_SOURCE;
DiagnosticSource s = sourceMap.get(file);
if (s == null) {
s = new DiagnosticSource(file, this);
sourceMap.put(file, s);
}
return s;
}
/** Return the underlying diagnostic source
*/
public DiagnosticSource currentSource() {
return source;
}
/** Report an error, unless another error was already reported at same
* source position.
* @param key The key for the localized error message.
* @param args Fields of the error message.
*/
public void error(String key, Object ... args) {
report(diags.error(source, null, key, args));
}
/** Report an error, unless another error was already reported at same
* source position.
* @param pos The source position at which to report the error.
* @param key The key for the localized error message.
* @param args Fields of the error message.
*/
public void error(DiagnosticPosition pos, String key, Object ... args) {
report(diags.error(source, pos, key, args));
}
/** Report an error, unless another error was already reported at same
* source position.
* @param flag A flag to set on the diagnostic
* @param pos The source position at which to report the error.
* @param key The key for the localized error message.
* @param args Fields of the error message.
*/
public void error(DiagnosticFlag flag, DiagnosticPosition pos, String key, Object ... args) {
JCDiagnostic d = diags.error(source, pos, key, args);
d.setFlag(flag);
report(d);
}
/** Report an error, unless another error was already reported at same
* source position.
* @param pos The source position at which to report the error.
* @param key The key for the localized error message.
* @param args Fields of the error message.
*/
public void error(int pos, String key, Object ... args) {
report(diags.error(source, wrap(pos), key, args));
}
/** Report an error, unless another error was already reported at same
* source position.
* @param flag A flag to set on the diagnostic
* @param pos The source position at which to report the error.
* @param key The key for the localized error message.
* @param args Fields of the error message.
*/
public void error(DiagnosticFlag flag, int pos, String key, Object ... args) {
JCDiagnostic d = diags.error(source, wrap(pos), key, args);
d.setFlag(flag);
report(d);
}
/** Report a warning, unless suppressed by the -nowarn option or the
* maximum number of warnings has been reached.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public void warning(String key, Object ... args) {
report(diags.warning(source, null, key, args));
}
/** Report a lint warning, unless suppressed by the -nowarn option or the
* maximum number of warnings has been reached.
* @param lc The lint category for the diagnostic
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public void warning(LintCategory lc, String key, Object ... args) {
report(diags.warning(lc, key, args));
}
/** Report a warning, unless suppressed by the -nowarn option or the
* maximum number of warnings has been reached.
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public void warning(DiagnosticPosition pos, String key, Object ... args) {
report(diags.warning(source, pos, key, args));
}
/** Report a lint warning, unless suppressed by the -nowarn option or the
* maximum number of warnings has been reached.
* @param lc The lint category for the diagnostic
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public void warning(LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {
report(diags.warning(lc, source, pos, key, args));
}
/** Report a warning, unless suppressed by the -nowarn option or the
* maximum number of warnings has been reached.
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public void warning(int pos, String key, Object ... args) {
report(diags.warning(source, wrap(pos), key, args));
}
/** Report a warning.
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public void mandatoryWarning(DiagnosticPosition pos, String key, Object ... args) {
report(diags.mandatoryWarning(source, pos, key, args));
}
/** Report a warning.
* @param lc The lint category for the diagnostic
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public void mandatoryWarning(LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {
report(diags.mandatoryWarning(lc, source, pos, key, args));
}
/** Provide a non-fatal notification, unless suppressed by the -nowarn option.
* @param key The key for the localized notification message.
* @param args Fields of the notint an error or warning message:
*/
public void note(String key, Object ... args) {
report(diags.note(source, null, key, args));
}
/** Provide a non-fatal notification, unless suppressed by the -nowarn option.
* @param key The key for the localized notification message.
* @param args Fields of the notification message.
*/
public void note(DiagnosticPosition pos, String key, Object ... args) {
report(diags.note(source, pos, key, args));
}
/** Provide a non-fatal notification, unless suppressed by the -nowarn option.
* @param key The key for the localized notification message.
* @param args Fields of the notification message.
*/
public void note(int pos, String key, Object ... args) {
report(diags.note(source, wrap(pos), key, args));
}
/** Provide a non-fatal notification, unless suppressed by the -nowarn option.
* @param key The key for the localized notification message.
* @param args Fields of the notification message.
*/
public void note(JavaFileObject file, String key, Object ... args) {
report(diags.note(getSource(file), null, key, args));
}
/** Provide a non-fatal notification, unless suppressed by the -nowarn option.
* @param key The key for the localized notification message.
* @param args Fields of the notification message.
*/
public void mandatoryNote(final JavaFileObject file, String key, Object ... args) {
report(diags.mandatoryNote(getSource(file), key, args));
}
protected abstract void report(JCDiagnostic diagnostic);
protected abstract void directError(String key, Object... args);
private DiagnosticPosition wrap(int pos) {
return (pos == Position.NOPOS ? null : new SimpleDiagnosticPosition(pos));
}
/** Factory for diagnostics
*/
protected JCDiagnostic.Factory diags;
/** The file that's currently being translated.
*/
protected DiagnosticSource source;
/** A cache of lightweight DiagnosticSource objects.
*/
protected Map<JavaFileObject, DiagnosticSource> sourceMap;
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.lang.reflect.Array;
/** <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class ArrayUtils {
private static int calculateNewLength(int currentLength, int maxIndex) {
while (currentLength < maxIndex + 1)
currentLength = currentLength * 2;
return currentLength;
}
public static <T> T[] ensureCapacity(T[] array, int maxIndex) {
if (maxIndex < array.length) {
return array;
} else {
int newLength = calculateNewLength(array.length, maxIndex);
@SuppressWarnings("unchecked")
T[] result = (T[]) Array.newInstance(array.getClass().getComponentType(), newLength);
System.arraycopy(array, 0, result, 0, array.length);
return result;
}
}
public static byte[] ensureCapacity(byte[] array, int maxIndex) {
if (maxIndex < array.length) {
return array;
} else {
int newLength = calculateNewLength(array.length, maxIndex);
byte[] result = new byte[newLength];
System.arraycopy(array, 0, result, 0, array.length);
return result;
}
}
public static char[] ensureCapacity(char[] array, int maxIndex) {
if (maxIndex < array.length) {
return array;
} else {
int newLength = calculateNewLength(array.length, maxIndex);
char[] result = new char[newLength];
System.arraycopy(array, 0, result, 0, array.length);
return result;
}
}
public static int[] ensureCapacity(int[] array, int maxIndex) {
if (maxIndex < array.length) {
return array;
} else {
int newLength = calculateNewLength(array.length, maxIndex);
int[] result = new int[newLength];
System.arraycopy(array, 0, result, 0, array.length);
return result;
}
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/**
* Simple facility for unconditional assertions.
* The methods in this class are described in terms of equivalent assert
* statements, assuming that assertions have been enabled.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Assert {
/** Equivalent to
* assert cond;
*/
public static void check(boolean cond) {
if (!cond)
error();
}
/** Equivalent to
* assert (o == null);
*/
public static void checkNull(Object o) {
if (o != null)
error();
}
/** Equivalent to
* assert (t != null); return t;
*/
public static <T> T checkNonNull(T t) {
if (t == null)
error();
return t;
}
/** Equivalent to
* assert cond : value;
*/
public static void check(boolean cond, int value) {
if (!cond)
error(String.valueOf(value));
}
/** Equivalent to
* assert cond : value;
*/
public static void check(boolean cond, long value) {
if (!cond)
error(String.valueOf(value));
}
/** Equivalent to
* assert cond : value;
*/
public static void check(boolean cond, Object value) {
if (!cond)
error(String.valueOf(value));
}
/** Equivalent to
* assert cond : value;
*/
public static void check(boolean cond, String msg) {
if (!cond)
error(msg);
}
/** Equivalent to
* assert (o == null) : value;
*/
public static void checkNull(Object o, Object value) {
if (o != null)
error(String.valueOf(value));
}
/** Equivalent to
* assert (o == null) : value;
*/
public static void checkNull(Object o, String msg) {
if (o != null)
error(msg);
}
/** Equivalent to
* assert (o != null) : value;
*/
public static <T> T checkNonNull(T t, String msg) {
if (t == null)
error(msg);
return t;
}
/** Equivalent to
* assert false;
*/
public static void error() {
throw new AssertionError();
}
/** Equivalent to
* assert false : msg;
*/
public static void error(String msg) {
throw new AssertionError(msg);
}
/** Prevent instantiation. */
private Assert() { }
}

View File

@@ -0,0 +1,402 @@
/*
* Copyright (c) 2009, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.file.FSInfo;
import com.sun.tools.javac.file.Locations;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.main.OptionHelper;
import com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
/**
* Utility methods for building a filemanager.
* There are no references here to file-system specific objects such as
* java.io.File or java.nio.file.Path.
*/
public abstract class BaseFileManager {
protected BaseFileManager(Charset charset) {
this.charset = charset;
byteBufferCache = new ByteBufferCache();
locations = createLocations();
}
/**
* Set the context for JavacPathFileManager.
*/
public void setContext(Context context) {
log = Log.instance(context);
options = Options.instance(context);
classLoaderClass = options.get("procloader");
locations.update(log, options, Lint.instance(context), FSInfo.instance(context));
}
protected Locations createLocations() {
return new Locations();
}
/**
* The log to be used for error reporting.
*/
public Log log;
/**
* User provided charset (through javax.tools).
*/
protected Charset charset;
protected Options options;
protected String classLoaderClass;
protected Locations locations;
protected Source getSource() {
String sourceName = options.get(Option.SOURCE);
Source source = null;
if (sourceName != null)
source = Source.lookup(sourceName);
return (source != null ? source : Source.DEFAULT);
}
protected ClassLoader getClassLoader(URL[] urls) {
ClassLoader thisClassLoader = getClass().getClassLoader();
// Allow the following to specify a closeable classloader
// other than URLClassLoader.
// 1: Allow client to specify the class to use via hidden option
if (classLoaderClass != null) {
try {
Class<? extends ClassLoader> loader =
Class.forName(classLoaderClass).asSubclass(ClassLoader.class);
Class<?>[] constrArgTypes = { URL[].class, ClassLoader.class };
Constructor<? extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
return constr.newInstance(new Object[] { urls, thisClassLoader });
} catch (Throwable t) {
// ignore errors loading user-provided class loader, fall through
}
}
return new URLClassLoader(urls, thisClassLoader);
}
// <editor-fold defaultstate="collapsed" desc="Option handling">
public boolean handleOption(String current, Iterator<String> remaining) {
OptionHelper helper = new GrumpyHelper(log) {
@Override
public String get(Option option) {
return options.get(option.getText());
}
@Override
public void put(String name, String value) {
options.put(name, value);
}
@Override
public void remove(String name) {
options.remove(name);
}
};
for (Option o: javacFileManagerOptions) {
if (o.matches(current)) {
if (o.hasArg()) {
if (remaining.hasNext()) {
if (!o.process(helper, current, remaining.next()))
return true;
}
} else {
if (!o.process(helper, current))
return true;
}
// operand missing, or process returned false
throw new IllegalArgumentException(current);
}
}
return false;
}
// where
private static final Set<Option> javacFileManagerOptions =
Option.getJavacFileManagerOptions();
public int isSupportedOption(String option) {
for (Option o : javacFileManagerOptions) {
if (o.matches(option))
return o.hasArg() ? 1 : 0;
}
return -1;
}
public abstract boolean isDefaultBootClassPath();
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Encoding">
private String defaultEncodingName;
private String getDefaultEncodingName() {
if (defaultEncodingName == null) {
defaultEncodingName =
new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
}
return defaultEncodingName;
}
public String getEncodingName() {
String encName = options.get(Option.ENCODING);
if (encName == null)
return getDefaultEncodingName();
else
return encName;
}
public CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
String encodingName = getEncodingName();
CharsetDecoder decoder;
try {
decoder = getDecoder(encodingName, ignoreEncodingErrors);
} catch (IllegalCharsetNameException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
} catch (UnsupportedCharsetException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
}
// slightly overestimate the buffer size to avoid reallocation.
float factor =
decoder.averageCharsPerByte() * 0.8f +
decoder.maxCharsPerByte() * 0.2f;
CharBuffer dest = CharBuffer.
allocate(10 + (int)(inbuf.remaining()*factor));
while (true) {
CoderResult result = decoder.decode(inbuf, dest, true);
dest.flip();
if (result.isUnderflow()) { // done reading
// make sure there is at least one extra character
if (dest.limit() == dest.capacity()) {
dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
dest.flip();
}
return dest;
} else if (result.isOverflow()) { // buffer too small; expand
int newCapacity =
10 + dest.capacity() +
(int)(inbuf.remaining()*decoder.maxCharsPerByte());
dest = CharBuffer.allocate(newCapacity).put(dest);
} else if (result.isMalformed() || result.isUnmappable()) {
// bad character in input
// report coding error (warn only pre 1.5)
if (!getSource().allowEncodingErrors()) {
log.error(new SimpleDiagnosticPosition(dest.limit()),
"illegal.char.for.encoding",
charset == null ? encodingName : charset.name());
} else {
log.warning(new SimpleDiagnosticPosition(dest.limit()),
"illegal.char.for.encoding",
charset == null ? encodingName : charset.name());
}
// skip past the coding error
inbuf.position(inbuf.position() + result.length());
// undo the flip() to prepare the output buffer
// for more translation
dest.position(dest.limit());
dest.limit(dest.capacity());
dest.put((char)0xfffd); // backward compatible
} else {
throw new AssertionError(result);
}
}
// unreached
}
public CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
Charset cs = (this.charset == null)
? Charset.forName(encodingName)
: this.charset;
CharsetDecoder decoder = cs.newDecoder();
CodingErrorAction action;
if (ignoreEncodingErrors)
action = CodingErrorAction.REPLACE;
else
action = CodingErrorAction.REPORT;
return decoder
.onMalformedInput(action)
.onUnmappableCharacter(action);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="ByteBuffers">
/**
* Make a byte buffer from an input stream.
*/
public ByteBuffer makeByteBuffer(InputStream in)
throws IOException {
int limit = in.available();
if (limit < 1024) limit = 1024;
ByteBuffer result = byteBufferCache.get(limit);
int position = 0;
while (in.available() != 0) {
if (position >= limit)
// expand buffer
result = ByteBuffer.
allocate(limit <<= 1).
put((ByteBuffer)result.flip());
int count = in.read(result.array(),
position,
limit - position);
if (count < 0) break;
result.position(position += count);
}
return (ByteBuffer)result.flip();
}
public void recycleByteBuffer(ByteBuffer bb) {
byteBufferCache.put(bb);
}
/**
* A single-element cache of direct byte buffers.
*/
private static class ByteBufferCache {
private ByteBuffer cached;
ByteBuffer get(int capacity) {
if (capacity < 20480) capacity = 20480;
ByteBuffer result =
(cached != null && cached.capacity() >= capacity)
? (ByteBuffer)cached.clear()
: ByteBuffer.allocate(capacity + capacity>>1);
cached = null;
return result;
}
void put(ByteBuffer x) {
cached = x;
}
}
private final ByteBufferCache byteBufferCache;
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Content cache">
public CharBuffer getCachedContent(JavaFileObject file) {
ContentCacheEntry e = contentCache.get(file);
if (e == null)
return null;
if (!e.isValid(file)) {
contentCache.remove(file);
return null;
}
return e.getValue();
}
public void cache(JavaFileObject file, CharBuffer cb) {
contentCache.put(file, new ContentCacheEntry(file, cb));
}
public void flushCache(JavaFileObject file) {
contentCache.remove(file);
}
protected final Map<JavaFileObject, ContentCacheEntry> contentCache
= new HashMap<JavaFileObject, ContentCacheEntry>();
protected static class ContentCacheEntry {
final long timestamp;
final SoftReference<CharBuffer> ref;
ContentCacheEntry(JavaFileObject file, CharBuffer cb) {
this.timestamp = file.getLastModified();
this.ref = new SoftReference<CharBuffer>(cb);
}
boolean isValid(JavaFileObject file) {
return timestamp == file.getLastModified();
}
CharBuffer getValue() {
return ref.get();
}
}
// </editor-fold>
public static Kind getKind(String name) {
if (name.endsWith(Kind.CLASS.extension))
return Kind.CLASS;
else if (name.endsWith(Kind.SOURCE.extension))
return Kind.SOURCE;
else if (name.endsWith(Kind.HTML.extension))
return Kind.HTML;
else
return Kind.OTHER;
}
protected static <T> T nullCheck(T o) {
o.getClass(); // null check
return o;
}
protected static <T> Collection<T> nullCheck(Collection<T> it) {
for (T t : it)
t.getClass(); // null check
return it;
}
}

View File

@@ -0,0 +1,412 @@
/*
* Copyright (c) 2005, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
import com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicConfiguration;
import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*;
import static com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicConfiguration.*;
import static com.sun.tools.javac.util.LayoutCharacters.*;
/**
* A basic formatter for diagnostic messages.
* The basic formatter will format a diagnostic according to one of three format patterns, depending on whether
* or not the source name and position are set. The formatter supports a printf-like string for patterns
* with the following special characters:
* <ul>
* <li>%b: the base of the source name
* <li>%f: the source name (full absolute path)
* <li>%l: the line number of the diagnostic, derived from the character offset
* <li>%c: the column number of the diagnostic, derived from the character offset
* <li>%o: the character offset of the diagnostic if set
* <li>%p: the prefix for the diagnostic, derived from the diagnostic type
* <li>%t: the prefix as it normally appears in standard diagnostics. In this case, no prefix is
* shown if the type is ERROR and if a source name is set
* <li>%m: the text or the diagnostic, including any appropriate arguments
* <li>%_: space delimiter, useful for formatting purposes
* </ul>
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter {
/**
* Create a basic formatter based on the supplied options.
*
* @param options list of command-line options
* @param msgs JavacMessages object used for i18n
*/
public BasicDiagnosticFormatter(Options options, JavacMessages msgs) {
super(msgs, new BasicConfiguration(options));
}
/**
* Create a standard basic formatter
*
* @param msgs JavacMessages object used for i18n
*/
public BasicDiagnosticFormatter(JavacMessages msgs) {
super(msgs, new BasicConfiguration());
}
public String formatDiagnostic(JCDiagnostic d, Locale l) {
if (l == null)
l = messages.getCurrentLocale();
String format = selectFormat(d);
StringBuilder buf = new StringBuilder();
for (int i = 0; i < format.length(); i++) {
char c = format.charAt(i);
boolean meta = false;
if (c == '%' && i < format.length() - 1) {
meta = true;
c = format.charAt(++i);
}
buf.append(meta ? formatMeta(c, d, l) : String.valueOf(c));
}
if (depth == 0)
return addSourceLineIfNeeded(d, buf.toString());
else
return buf.toString();
}
public String formatMessage(JCDiagnostic d, Locale l) {
int currentIndentation = 0;
StringBuilder buf = new StringBuilder();
Collection<String> args = formatArguments(d, l);
String msg = localize(l, d.getCode(), args.toArray());
String[] lines = msg.split("\n");
if (getConfiguration().getVisible().contains(DiagnosticPart.SUMMARY)) {
currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUMMARY);
buf.append(indent(lines[0], currentIndentation)); //summary
}
if (lines.length > 1 && getConfiguration().getVisible().contains(DiagnosticPart.DETAILS)) {
currentIndentation += getConfiguration().getIndentation(DiagnosticPart.DETAILS);
for (int i = 1;i < lines.length; i++) {
buf.append("\n" + indent(lines[i], currentIndentation));
}
}
if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) {
currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUBDIAGNOSTICS);
for (String sub : formatSubdiagnostics(d, l)) {
buf.append("\n" + indent(sub, currentIndentation));
}
}
return buf.toString();
}
protected String addSourceLineIfNeeded(JCDiagnostic d, String msg) {
if (!displaySource(d))
return msg;
else {
BasicConfiguration conf = getConfiguration();
int indentSource = conf.getIndentation(DiagnosticPart.SOURCE);
String sourceLine = "\n" + formatSourceLine(d, indentSource);
boolean singleLine = msg.indexOf("\n") == -1;
if (singleLine || getConfiguration().getSourcePosition() == SourcePosition.BOTTOM)
return msg + sourceLine;
else
return msg.replaceFirst("\n", Matcher.quoteReplacement(sourceLine) + "\n");
}
}
protected String formatMeta(char c, JCDiagnostic d, Locale l) {
switch (c) {
case 'b':
return formatSource(d, false, l);
case 'e':
return formatPosition(d, END, l);
case 'f':
return formatSource(d, true, l);
case 'l':
return formatPosition(d, LINE, l);
case 'c':
return formatPosition(d, COLUMN, l);
case 'o':
return formatPosition(d, OFFSET, l);
case 'p':
return formatKind(d, l);
case 's':
return formatPosition(d, START, l);
case 't': {
boolean usePrefix;
switch (d.getType()) {
case FRAGMENT:
usePrefix = false;
break;
case ERROR:
usePrefix = (d.getIntPosition() == Position.NOPOS);
break;
default:
usePrefix = true;
}
if (usePrefix)
return formatKind(d, l);
else
return "";
}
case 'm':
return formatMessage(d, l);
case 'L':
return formatLintCategory(d, l);
case '_':
return " ";
case '%':
return "%";
default:
return String.valueOf(c);
}
}
private String selectFormat(JCDiagnostic d) {
DiagnosticSource source = d.getDiagnosticSource();
String format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT);
if (source != null && source != DiagnosticSource.NO_SOURCE) {
if (d.getIntPosition() != Position.NOPOS) {
format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_POS_FORMAT);
} else if (source.getFile() != null &&
source.getFile().getKind() == JavaFileObject.Kind.CLASS) {
format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT);
}
}
return format;
}
@Override
public BasicConfiguration getConfiguration() {
//the following cast is always safe - see init
return (BasicConfiguration)super.getConfiguration();
}
static public class BasicConfiguration extends SimpleConfiguration {
protected Map<DiagnosticPart, Integer> indentationLevels;
protected Map<BasicFormatKind, String> availableFormats;
protected SourcePosition sourcePosition;
@SuppressWarnings("fallthrough")
public BasicConfiguration(Options options) {
super(options, EnumSet.of(DiagnosticPart.SUMMARY,
DiagnosticPart.DETAILS,
DiagnosticPart.SUBDIAGNOSTICS,
DiagnosticPart.SOURCE));
initFormat();
initIndentation();
if (options.isSet("oldDiags"))
initOldFormat();
String fmt = options.get("diagsFormat");
if (fmt != null) {
if (fmt.equals("OLD"))
initOldFormat();
else
initFormats(fmt);
}
String srcPos = null;
if ((((srcPos = options.get("sourcePosition")) != null)) &&
srcPos.equals("bottom"))
setSourcePosition(SourcePosition.BOTTOM);
else
setSourcePosition(SourcePosition.AFTER_SUMMARY);
String indent = options.get("diagsIndentation");
if (indent != null) {
String[] levels = indent.split("\\|");
try {
switch (levels.length) {
case 5:
setIndentation(DiagnosticPart.JLS,
Integer.parseInt(levels[4]));
case 4:
setIndentation(DiagnosticPart.SUBDIAGNOSTICS,
Integer.parseInt(levels[3]));
case 3:
setIndentation(DiagnosticPart.SOURCE,
Integer.parseInt(levels[2]));
case 2:
setIndentation(DiagnosticPart.DETAILS,
Integer.parseInt(levels[1]));
default:
setIndentation(DiagnosticPart.SUMMARY,
Integer.parseInt(levels[0]));
}
}
catch (NumberFormatException ex) {
initIndentation();
}
}
}
public BasicConfiguration() {
super(EnumSet.of(DiagnosticPart.SUMMARY,
DiagnosticPart.DETAILS,
DiagnosticPart.SUBDIAGNOSTICS,
DiagnosticPart.SOURCE));
initFormat();
initIndentation();
}
private void initFormat() {
initFormats("%f:%l:%_%p%L%m", "%p%L%m", "%f:%_%p%L%m");
}
private void initOldFormat() {
initFormats("%f:%l:%_%t%L%m", "%p%L%m", "%f:%_%t%L%m");
}
private void initFormats(String pos, String nopos, String clazz) {
availableFormats = new EnumMap<BasicFormatKind, String>(BasicFormatKind.class);
setFormat(BasicFormatKind.DEFAULT_POS_FORMAT, pos);
setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, nopos);
setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, clazz);
}
@SuppressWarnings("fallthrough")
private void initFormats(String fmt) {
String[] formats = fmt.split("\\|");
switch (formats.length) {
case 3:
setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, formats[2]);
case 2:
setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, formats[1]);
default:
setFormat(BasicFormatKind.DEFAULT_POS_FORMAT, formats[0]);
}
}
private void initIndentation() {
indentationLevels = new HashMap<DiagnosticPart, Integer>();
setIndentation(DiagnosticPart.SUMMARY, 0);
setIndentation(DiagnosticPart.DETAILS, DetailsInc);
setIndentation(DiagnosticPart.SUBDIAGNOSTICS, DiagInc);
setIndentation(DiagnosticPart.SOURCE, 0);
}
/**
* Get the amount of spaces for a given indentation kind
* @param diagPart the diagnostic part for which the indentation is
* to be retrieved
* @return the amount of spaces used for the specified indentation kind
*/
public int getIndentation(DiagnosticPart diagPart) {
return indentationLevels.get(diagPart);
}
/**
* Set the indentation level for various element of a given diagnostic -
* this might lead to more readable diagnostics
*
* @param diagPart
* @param nSpaces amount of spaces for the specified diagnostic part
*/
public void setIndentation(DiagnosticPart diagPart, int nSpaces) {
indentationLevels.put(diagPart, nSpaces);
}
/**
* Set the source line positioning used by this formatter
*
* @param sourcePos a positioning value for source line
*/
public void setSourcePosition(SourcePosition sourcePos) {
sourcePosition = sourcePos;
}
/**
* Get the source line positioning used by this formatter
*
* @return the positioning value used by this formatter
*/
public SourcePosition getSourcePosition() {
return sourcePosition;
}
//where
/**
* A source positioning value controls the position (within a given
* diagnostic message) in which the source line the diagnostic refers to
* should be displayed (if applicable)
*/
public enum SourcePosition {
/**
* Source line is displayed after the diagnostic message
*/
BOTTOM,
/**
* Source line is displayed after the first line of the diagnostic
* message
*/
AFTER_SUMMARY;
}
/**
* Set a metachar string for a specific format
*
* @param kind the format kind to be set
* @param s the metachar string specifying the format
*/
public void setFormat(BasicFormatKind kind, String s) {
availableFormats.put(kind, s);
}
/**
* Get a metachar string for a specific format
*
* @param kind the format kind for which to get the metachar string
*/
public String getFormat(BasicFormatKind kind) {
return availableFormats.get(kind);
}
//where
/**
* This enum contains all the kinds of formatting patterns supported
* by a basic diagnostic formatter.
*/
public enum BasicFormatKind {
/**
* A format string to be used for diagnostics with a given position.
*/
DEFAULT_POS_FORMAT,
/**
* A format string to be used for diagnostics without a given position.
*/
DEFAULT_NO_POS_FORMAT,
/**
* A format string to be used for diagnostics regarding classfiles
*/
DEFAULT_CLASS_FORMAT;
}
}
}

View File

@@ -0,0 +1,369 @@
/*
* Copyright (c) 1999, 2015, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.Arrays;
/** A class for extensible, mutable bit sets.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Bits {
// ____________ reset _________
// / UNKNOWN \ <-------- / UNINIT \
// \____________/ | \_________/
// | | |
// |assign | | any
// | ___________ |
// ------> / NORMAL \ <----
// \___________/ |
// | |
// | |
// -----------
// any
protected enum BitsState {
/* A Bits instance is in UNKNOWN state if it has been explicitly reset.
* It is possible to get to this state from any other by calling the
* reset method. An instance in the UNKNOWN state can pass to the
* NORMAL state after being assigned another Bits instance.
*
* Bits instances are final fields in Flow so the UNKNOWN state models
* the null assignment.
*/
UNKNOWN,
/* A Bits instance is in UNINIT when it is created with the default
* constructor but it isn't explicitly reset. The main objective of this
* internal state is to save some memory.
*/
UNINIT,
/* The normal state is reached after creating a Bits instance from an
* existing one or after applying any operation to an instance on UNINIT
* or NORMAL state. From this state a bits instance can pass to the
* UNKNOWN state by calling the reset method.
*/
NORMAL;
static BitsState getState(int[] someBits, boolean reset) {
if (reset) {
return UNKNOWN;
} else {
if (someBits != unassignedBits) {
return NORMAL;
} else {
return UNINIT;
}
}
}
}
private final static int wordlen = 32;
private final static int wordshift = 5;
private final static int wordmask = wordlen - 1;
public int[] bits = null;
// This field will store last version of bits after every change.
private static final int[] unassignedBits = new int[0];
protected BitsState currentState;
/** Construct an initially empty set.
*/
public Bits() {
this(false);
}
public Bits(Bits someBits) {
this(someBits.dup().bits, BitsState.getState(someBits.bits, false));
}
public Bits(boolean reset) {
this(unassignedBits, BitsState.getState(unassignedBits, reset));
}
/** Construct a set consisting initially of given bit vector.
*/
protected Bits(int[] bits, BitsState initState) {
this.bits = bits;
this.currentState = initState;
switch (initState) {
case UNKNOWN:
this.bits = null;
break;
case NORMAL:
Assert.check(bits != unassignedBits);
break;
}
}
protected void sizeTo(int len) {
if (bits.length < len) {
bits = Arrays.copyOf(bits, len);
}
}
/** This set = {}.
*/
public void clear() {
Assert.check(currentState != BitsState.UNKNOWN);
for (int i = 0; i < bits.length; i++) {
bits[i] = 0;
}
currentState = BitsState.NORMAL;
}
public void reset() {
internalReset();
}
protected void internalReset() {
bits = null;
currentState = BitsState.UNKNOWN;
}
public boolean isReset() {
return currentState == BitsState.UNKNOWN;
}
public Bits assign(Bits someBits) {
bits = someBits.dup().bits;
currentState = BitsState.NORMAL;
return this;
}
/** Return a copy of this set.
*/
public Bits dup() {
Assert.check(currentState != BitsState.UNKNOWN);
Bits tmp = new Bits();
tmp.bits = dupBits();
currentState = BitsState.NORMAL;
return tmp;
}
protected int[] dupBits() {
int [] result;
if (currentState != BitsState.NORMAL) {
result = bits;
} else {
result = new int[bits.length];
System.arraycopy(bits, 0, result, 0, bits.length);
}
return result;
}
/** Include x in this set.
*/
public void incl(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
Assert.check(x >= 0, "Value of x " + x);
sizeTo((x >>> wordshift) + 1);
bits[x >>> wordshift] = bits[x >>> wordshift] |
(1 << (x & wordmask));
currentState = BitsState.NORMAL;
}
/** Include [start..limit) in this set.
*/
public void inclRange(int start, int limit) {
Assert.check(currentState != BitsState.UNKNOWN);
sizeTo((limit >>> wordshift) + 1);
for (int x = start; x < limit; x++) {
bits[x >>> wordshift] = bits[x >>> wordshift] |
(1 << (x & wordmask));
}
currentState = BitsState.NORMAL;
}
/** Exclude [start...end] from this set.
*/
public void excludeFrom(int start) {
Assert.check(currentState != BitsState.UNKNOWN);
Bits temp = new Bits();
temp.sizeTo(bits.length);
temp.inclRange(0, start);
internalAndSet(temp);
currentState = BitsState.NORMAL;
}
/** Exclude x from this set.
*/
public void excl(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
Assert.check(x >= 0);
sizeTo((x >>> wordshift) + 1);
bits[x >>> wordshift] = bits[x >>> wordshift] &
~(1 << (x & wordmask));
currentState = BitsState.NORMAL;
}
/** Is x an element of this set?
*/
public boolean isMember(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
return
0 <= x && x < (bits.length << wordshift) &&
(bits[x >>> wordshift] & (1 << (x & wordmask))) != 0;
}
/** {@literal this set = this set & xs}.
*/
public Bits andSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
internalAndSet(xs);
currentState = BitsState.NORMAL;
return this;
}
protected void internalAndSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++) {
bits[i] = bits[i] & xs.bits[i];
}
}
/** this set = this set | xs.
*/
public Bits orSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++) {
bits[i] = bits[i] | xs.bits[i];
}
currentState = BitsState.NORMAL;
return this;
}
/** this set = this set \ xs.
*/
public Bits diffSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
for (int i = 0; i < bits.length; i++) {
if (i < xs.bits.length) {
bits[i] = bits[i] & ~xs.bits[i];
}
}
currentState = BitsState.NORMAL;
return this;
}
/** this set = this set ^ xs.
*/
public Bits xorSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++) {
bits[i] = bits[i] ^ xs.bits[i];
}
currentState = BitsState.NORMAL;
return this;
}
/** Count trailing zero bits in an int. Algorithm from "Hacker's
* Delight" by Henry S. Warren Jr. (figure 5-13)
*/
private static int trailingZeroBits(int x) {
Assert.check(wordlen == 32);
if (x == 0) {
return 32;
}
int n = 1;
if ((x & 0xffff) == 0) { n += 16; x >>>= 16; }
if ((x & 0x00ff) == 0) { n += 8; x >>>= 8; }
if ((x & 0x000f) == 0) { n += 4; x >>>= 4; }
if ((x & 0x0003) == 0) { n += 2; x >>>= 2; }
return n - (x&1);
}
/** Return the index of the least bit position &ge; x that is set.
* If none are set, returns -1. This provides a nice way to iterate
* over the members of a bit set:
* <pre>{@code
* for (int i = bits.nextBit(0); i>=0; i = bits.nextBit(i+1)) ...
* }</pre>
*/
public int nextBit(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
int windex = x >>> wordshift;
if (windex >= bits.length) {
return -1;
}
int word = bits[windex] & ~((1 << (x & wordmask))-1);
while (true) {
if (word != 0) {
return (windex << wordshift) + trailingZeroBits(word);
}
windex++;
if (windex >= bits.length) {
return -1;
}
word = bits[windex];
}
}
/** a string representation of this set.
*/
@Override
public String toString() {
if (bits != null && bits.length > 0) {
char[] digits = new char[bits.length * wordlen];
for (int i = 0; i < bits.length * wordlen; i++) {
digits[i] = isMember(i) ? '1' : '0';
}
return new String(digits);
} else {
return "[]";
}
}
/** Test Bits.nextBit(int). */
public static void main(String[] args) {
java.util.Random r = new java.util.Random();
Bits bits = new Bits();
for (int i=0; i<125; i++) {
int k;
do {
k = r.nextInt(250);
} while (bits.isMember(k));
System.out.println("adding " + k);
bits.incl(k);
}
int count = 0;
for (int i = bits.nextBit(0); i >= 0; i = bits.nextBit(i+1)) {
System.out.println("found " + i);
count ++;
}
if (count != 125) {
throw new Error();
}
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 1999, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.io.*;
/** A byte buffer is a flexible array which grows when elements are
* appended. There are also methods to append names to byte buffers
* and to convert byte buffers to names.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class ByteBuffer {
/** An array holding the bytes in this buffer; can be grown.
*/
public byte[] elems;
/** The current number of defined bytes in this buffer.
*/
public int length;
/** Create a new byte buffer.
*/
public ByteBuffer() {
this(64);
}
/** Create a new byte buffer with an initial elements array
* of given size.
*/
public ByteBuffer(int initialSize) {
elems = new byte[initialSize];
length = 0;
}
/** Append byte to this buffer.
*/
public void appendByte(int b) {
elems = ArrayUtils.ensureCapacity(elems, length);
elems[length++] = (byte)b;
}
/** Append `len' bytes from byte array,
* starting at given `start' offset.
*/
public void appendBytes(byte[] bs, int start, int len) {
elems = ArrayUtils.ensureCapacity(elems, length + len);
System.arraycopy(bs, start, elems, length, len);
length += len;
}
/** Append all bytes from given byte array.
*/
public void appendBytes(byte[] bs) {
appendBytes(bs, 0, bs.length);
}
/** Append a character as a two byte number.
*/
public void appendChar(int x) {
elems = ArrayUtils.ensureCapacity(elems, length + 1);
elems[length ] = (byte)((x >> 8) & 0xFF);
elems[length+1] = (byte)((x ) & 0xFF);
length = length + 2;
}
/** Append an integer as a four byte number.
*/
public void appendInt(int x) {
elems = ArrayUtils.ensureCapacity(elems, length + 3);
elems[length ] = (byte)((x >> 24) & 0xFF);
elems[length+1] = (byte)((x >> 16) & 0xFF);
elems[length+2] = (byte)((x >> 8) & 0xFF);
elems[length+3] = (byte)((x ) & 0xFF);
length = length + 4;
}
/** Append a long as an eight byte number.
*/
public void appendLong(long x) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(8);
DataOutputStream bufout = new DataOutputStream(buffer);
try {
bufout.writeLong(x);
appendBytes(buffer.toByteArray(), 0, 8);
} catch (IOException e) {
throw new AssertionError("write");
}
}
/** Append a float as a four byte number.
*/
public void appendFloat(float x) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(4);
DataOutputStream bufout = new DataOutputStream(buffer);
try {
bufout.writeFloat(x);
appendBytes(buffer.toByteArray(), 0, 4);
} catch (IOException e) {
throw new AssertionError("write");
}
}
/** Append a double as a eight byte number.
*/
public void appendDouble(double x) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(8);
DataOutputStream bufout = new DataOutputStream(buffer);
try {
bufout.writeDouble(x);
appendBytes(buffer.toByteArray(), 0, 8);
} catch (IOException e) {
throw new AssertionError("write");
}
}
/** Append a name.
*/
public void appendName(Name name) {
appendBytes(name.getByteArray(), name.getByteOffset(), name.getByteLength());
}
/** Reset to zero length.
*/
public void reset() {
length = 0;
}
/** Convert contents to name.
*/
public Name toName(Names names) {
return names.fromUtf(elems, 0, length);
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2005, 2006, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/**
* An exception used for propogating exceptions found in client code
* invoked from javac.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class ClientCodeException extends RuntimeException {
static final long serialVersionUID = -5674494409392415163L;
public ClientCodeException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 2005, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import com.sun.tools.javac.code.Type;
/**
* Utilities for operating on constant values.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Constants {
/**
* Converts a constant in internal representation (in which
* boolean, char, byte, short, and int are each represented by an
* Integer) into standard representation. Other values (including
* null) are returned unchanged.
*/
public static Object decode(Object value, Type type) {
if (value instanceof Integer) {
int i = (Integer) value;
switch (type.getTag()) {
case BOOLEAN: return i != 0;
case CHAR: return (char) i;
case BYTE: return (byte) i;
case SHORT: return (short) i;
}
}
return value;
}
/**
* Returns a string representation of a constant value (given in
* internal representation), quoted and formatted as in Java source.
*/
public static String format(Object value, Type type) {
value = decode(value, type);
switch (type.getTag()) {
case BYTE: return formatByte((Byte) value);
case LONG: return formatLong((Long) value);
case FLOAT: return formatFloat((Float) value);
case DOUBLE: return formatDouble((Double) value);
case CHAR: return formatChar((Character) value);
}
if (value instanceof String)
return formatString((String) value);
return value + "";
}
/**
* Returns a string representation of a constant value (given in
* standard wrapped representation), quoted and formatted as in
* Java source.
*/
public static String format(Object value) {
if (value instanceof Byte) return formatByte((Byte) value);
if (value instanceof Short) return formatShort((Short) value);
if (value instanceof Long) return formatLong((Long) value);
if (value instanceof Float) return formatFloat((Float) value);
if (value instanceof Double) return formatDouble((Double) value);
if (value instanceof Character) return formatChar((Character) value);
if (value instanceof String) return formatString((String) value);
if (value instanceof Integer ||
value instanceof Boolean) return value.toString();
else
throw new IllegalArgumentException("Argument is not a primitive type or a string; it " +
((value == null) ?
"is a null value." :
"has class " +
value.getClass().getName()) + "." );
}
private static String formatByte(byte b) {
return String.format("(byte)0x%02x", b);
}
private static String formatShort(short s) {
return String.format("(short)%d", s);
}
private static String formatLong(long lng) {
return lng + "L";
}
private static String formatFloat(float f) {
if (Float.isNaN(f))
return "0.0f/0.0f";
else if (Float.isInfinite(f))
return (f < 0) ? "-1.0f/0.0f" : "1.0f/0.0f";
else
return f + "f";
}
private static String formatDouble(double d) {
if (Double.isNaN(d))
return "0.0/0.0";
else if (Double.isInfinite(d))
return (d < 0) ? "-1.0/0.0" : "1.0/0.0";
else
return d + "";
}
private static String formatChar(char c) {
return '\'' + Convert.quote(c) + '\'';
}
private static String formatString(String s) {
return '"' + Convert.quote(s) + '"';
}
}

View File

@@ -0,0 +1,227 @@
/*
* Copyright (c) 2001, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.*;
/**
* Support for an abstract context, modelled loosely after ThreadLocal
* but using a user-provided context instead of the current thread.
*
* <p>Within the compiler, a single Context is used for each
* invocation of the compiler. The context is then used to ensure a
* single copy of each compiler phase exists per compiler invocation.
*
* <p>The context can be used to assist in extending the compiler by
* extending its components. To do that, the extended component must
* be registered before the base component. We break initialization
* cycles by (1) registering a factory for the component rather than
* the component itself, and (2) a convention for a pattern of usage
* in which each base component registers itself by calling an
* instance method that is overridden in extended components. A base
* phase supporting extension would look something like this:
*
* <p><pre>{@code
* public class Phase {
* protected static final Context.Key<Phase> phaseKey =
* new Context.Key<Phase>();
*
* public static Phase instance(Context context) {
* Phase instance = context.get(phaseKey);
* if (instance == null)
* // the phase has not been overridden
* instance = new Phase(context);
* return instance;
* }
*
* protected Phase(Context context) {
* context.put(phaseKey, this);
* // other intitialization follows...
* }
* }
* }</pre>
*
* <p>In the compiler, we simply use Phase.instance(context) to get
* the reference to the phase. But in extensions of the compiler, we
* must register extensions of the phases to replace the base phase,
* and this must be done before any reference to the phase is accessed
* using Phase.instance(). An extended phase might be declared thus:
*
* <p><pre>{@code
* public class NewPhase extends Phase {
* protected NewPhase(Context context) {
* super(context);
* }
* public static void preRegister(final Context context) {
* context.put(phaseKey, new Context.Factory<Phase>() {
* public Phase make() {
* return new NewPhase(context);
* }
* });
* }
* }
* }</pre>
*
* <p>And is registered early in the extended compiler like this
*
* <p><pre>
* NewPhase.preRegister(context);
* </pre>
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Context {
/** The client creates an instance of this class for each key.
*/
public static class Key<T> {
// note: we inherit identity equality from Object.
}
/**
* The client can register a factory for lazy creation of the
* instance.
*/
public static interface Factory<T> {
T make(Context c);
};
/**
* The underlying map storing the data.
* We maintain the invariant that this table contains only
* mappings of the form
* {@literal Key<T> -> T }
* or
* {@literal Key<T> -> Factory<T> }
*/
private Map<Key<?>,Object> ht = new HashMap<Key<?>,Object>();
/** Set the factory for the key in this context. */
public <T> void put(Key<T> key, Factory<T> fac) {
checkState(ht);
Object old = ht.put(key, fac);
if (old != null)
throw new AssertionError("duplicate context value");
checkState(ft);
ft.put(key, fac); // cannot be duplicate if unique in ht
}
/** Set the value for the key in this context. */
public <T> void put(Key<T> key, T data) {
if (data instanceof Factory<?>)
throw new AssertionError("T extends Context.Factory");
checkState(ht);
Object old = ht.put(key, data);
if (old != null && !(old instanceof Factory<?>) && old != data && data != null)
throw new AssertionError("duplicate context value");
}
/** Get the value for the key in this context. */
public <T> T get(Key<T> key) {
checkState(ht);
Object o = ht.get(key);
if (o instanceof Factory<?>) {
Factory<?> fac = (Factory<?>)o;
o = fac.make(this);
if (o instanceof Factory<?>)
throw new AssertionError("T extends Context.Factory");
Assert.check(ht.get(key) == o);
}
/* The following cast can't fail unless there was
* cheating elsewhere, because of the invariant on ht.
* Since we found a key of type Key<T>, the value must
* be of type T.
*/
return Context.<T>uncheckedCast(o);
}
public Context() {}
/**
* The table of preregistered factories.
*/
private Map<Key<?>,Factory<?>> ft = new HashMap<Key<?>,Factory<?>>();
public Context(Context prev) {
kt.putAll(prev.kt); // retain all implicit keys
ft.putAll(prev.ft); // retain all factory objects
ht.putAll(prev.ft); // init main table with factories
}
/*
* The key table, providing a unique Key<T> for each Class<T>.
*/
private Map<Class<?>, Key<?>> kt = new HashMap<Class<?>, Key<?>>();
private <T> Key<T> key(Class<T> clss) {
checkState(kt);
Key<T> k = uncheckedCast(kt.get(clss));
if (k == null) {
k = new Key<T>();
kt.put(clss, k);
}
return k;
}
public <T> T get(Class<T> clazz) {
return get(key(clazz));
}
public <T> void put(Class<T> clazz, T data) {
put(key(clazz), data);
}
public <T> void put(Class<T> clazz, Factory<T> fac) {
put(key(clazz), fac);
}
/**
* TODO: This method should be removed and Context should be made type safe.
* This can be accomplished by using class literals as type tokens.
*/
@SuppressWarnings("unchecked")
private static <T> T uncheckedCast(Object o) {
return (T)o;
}
public void dump() {
for (Object value : ht.values())
System.err.println(value == null ? null : value.getClass());
}
public void clear() {
ht = null;
kt = null;
ft = null;
}
private static void checkState(Map<?,?> t) {
if (t == null)
throw new IllegalStateException();
}
}

View File

@@ -0,0 +1,338 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/** Utility class for static conversion methods between numbers
* and strings in various formats.
*
* <p>Note regarding UTF-8.
* The JVMS defines its own version of the UTF-8 format so that it
* contains no zero bytes (modified UTF-8). This is not actually the same
* as Charset.forName("UTF-8").
*
* <p>
* See also:
* <ul>
* <li><a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.7">
* JVMS 4.4.7 </a></li>
* <li><a href="https://docs.oracle.com/javase/7/docs/api/java/io/DataInput.html#modified-utf-8">
java.io.DataInput: Modified UTF-8 </a></li>
<li><a href="https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8">
Modified UTF-8 (wikipedia) </a></li>
* </ul>
*
* The methods here support modified UTF-8.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Convert {
/** Convert string to integer.
*/
public static int string2int(String s, int radix)
throws NumberFormatException {
if (radix == 10) {
return Integer.parseInt(s, radix);
} else {
char[] cs = s.toCharArray();
int limit = Integer.MAX_VALUE / (radix/2);
int n = 0;
for (int i = 0; i < cs.length; i++) {
int d = Character.digit(cs[i], radix);
if (n < 0 ||
n > limit ||
n * radix > Integer.MAX_VALUE - d)
throw new NumberFormatException();
n = n * radix + d;
}
return n;
}
}
/** Convert string to long integer.
*/
public static long string2long(String s, int radix)
throws NumberFormatException {
if (radix == 10) {
return Long.parseLong(s, radix);
} else {
char[] cs = s.toCharArray();
long limit = Long.MAX_VALUE / (radix/2);
long n = 0;
for (int i = 0; i < cs.length; i++) {
int d = Character.digit(cs[i], radix);
if (n < 0 ||
n > limit ||
n * radix > Long.MAX_VALUE - d)
throw new NumberFormatException();
n = n * radix + d;
}
return n;
}
}
/* Conversion routines between names, strings, and byte arrays in Utf8 format
*/
/** Convert `len' bytes from utf8 to characters.
* Parameters are as in System.arraycopy
* Return first index in `dst' past the last copied char.
* @param src The array holding the bytes to convert.
* @param sindex The start index from which bytes are converted.
* @param dst The array holding the converted characters..
* @param dindex The start index from which converted characters
* are written.
* @param len The maximum number of bytes to convert.
*/
public static int utf2chars(byte[] src, int sindex,
char[] dst, int dindex,
int len) {
int i = sindex;
int j = dindex;
int limit = sindex + len;
while (i < limit) {
int b = src[i++] & 0xFF;
if (b >= 0xE0) {
b = (b & 0x0F) << 12;
b = b | (src[i++] & 0x3F) << 6;
b = b | (src[i++] & 0x3F);
} else if (b >= 0xC0) {
b = (b & 0x1F) << 6;
b = b | (src[i++] & 0x3F);
}
dst[j++] = (char)b;
}
return j;
}
/** Return bytes in Utf8 representation as an array of characters.
* @param src The array holding the bytes.
* @param sindex The start index from which bytes are converted.
* @param len The maximum number of bytes to convert.
*/
public static char[] utf2chars(byte[] src, int sindex, int len) {
char[] dst = new char[len];
int len1 = utf2chars(src, sindex, dst, 0, len);
char[] result = new char[len1];
System.arraycopy(dst, 0, result, 0, len1);
return result;
}
/** Return all bytes of a given array in Utf8 representation
* as an array of characters.
* @param src The array holding the bytes.
*/
public static char[] utf2chars(byte[] src) {
return utf2chars(src, 0, src.length);
}
/** Return bytes in Utf8 representation as a string.
* @param src The array holding the bytes.
* @param sindex The start index from which bytes are converted.
* @param len The maximum number of bytes to convert.
*/
public static String utf2string(byte[] src, int sindex, int len) {
char dst[] = new char[len];
int len1 = utf2chars(src, sindex, dst, 0, len);
return new String(dst, 0, len1);
}
/** Return all bytes of a given array in Utf8 representation
* as a string.
* @param src The array holding the bytes.
*/
public static String utf2string(byte[] src) {
return utf2string(src, 0, src.length);
}
/** Copy characters in source array to bytes in target array,
* converting them to Utf8 representation.
* The target array must be large enough to hold the result.
* returns first index in `dst' past the last copied byte.
* @param src The array holding the characters to convert.
* @param sindex The start index from which characters are converted.
* @param dst The array holding the converted characters..
* @param dindex The start index from which converted bytes
* are written.
* @param len The maximum number of characters to convert.
*/
public static int chars2utf(char[] src, int sindex,
byte[] dst, int dindex,
int len) {
int j = dindex;
int limit = sindex + len;
for (int i = sindex; i < limit; i++) {
char ch = src[i];
if (1 <= ch && ch <= 0x7F) {
dst[j++] = (byte)ch;
} else if (ch <= 0x7FF) {
dst[j++] = (byte)(0xC0 | (ch >> 6));
dst[j++] = (byte)(0x80 | (ch & 0x3F));
} else {
dst[j++] = (byte)(0xE0 | (ch >> 12));
dst[j++] = (byte)(0x80 | ((ch >> 6) & 0x3F));
dst[j++] = (byte)(0x80 | (ch & 0x3F));
}
}
return j;
}
/** Return characters as an array of bytes in Utf8 representation.
* @param src The array holding the characters.
* @param sindex The start index from which characters are converted.
* @param len The maximum number of characters to convert.
*/
public static byte[] chars2utf(char[] src, int sindex, int len) {
byte[] dst = new byte[len * 3];
int len1 = chars2utf(src, sindex, dst, 0, len);
byte[] result = new byte[len1];
System.arraycopy(dst, 0, result, 0, len1);
return result;
}
/** Return all characters in given array as an array of bytes
* in Utf8 representation.
* @param src The array holding the characters.
*/
public static byte[] chars2utf(char[] src) {
return chars2utf(src, 0, src.length);
}
/** Return string as an array of bytes in in Utf8 representation.
*/
public static byte[] string2utf(String s) {
return chars2utf(s.toCharArray());
}
/**
* Escapes each character in a string that has an escape sequence or
* is non-printable ASCII. Leaves non-ASCII characters alone.
*/
public static String quote(String s) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
buf.append(quote(s.charAt(i)));
}
return buf.toString();
}
/**
* Escapes a character if it has an escape sequence or is
* non-printable ASCII. Leaves non-ASCII characters alone.
*/
public static String quote(char ch) {
switch (ch) {
case '\b': return "\\b";
case '\f': return "\\f";
case '\n': return "\\n";
case '\r': return "\\r";
case '\t': return "\\t";
case '\'': return "\\'";
case '\"': return "\\\"";
case '\\': return "\\\\";
default:
return (isPrintableAscii(ch))
? String.valueOf(ch)
: String.format("\\u%04x", (int) ch);
}
}
/**
* Is a character printable ASCII?
*/
private static boolean isPrintableAscii(char ch) {
return ch >= ' ' && ch <= '~';
}
/** Escape all unicode characters in string.
*/
public static String escapeUnicode(String s) {
int len = s.length();
int i = 0;
while (i < len) {
char ch = s.charAt(i);
if (ch > 255) {
StringBuilder buf = new StringBuilder();
buf.append(s.substring(0, i));
while (i < len) {
ch = s.charAt(i);
if (ch > 255) {
buf.append("\\u");
buf.append(Character.forDigit((ch >> 12) % 16, 16));
buf.append(Character.forDigit((ch >> 8) % 16, 16));
buf.append(Character.forDigit((ch >> 4) % 16, 16));
buf.append(Character.forDigit((ch ) % 16, 16));
} else {
buf.append(ch);
}
i++;
}
s = buf.toString();
} else {
i++;
}
}
return s;
}
/* Conversion routines for qualified name splitting
*/
/** Return the last part of a class name.
*/
public static Name shortName(Name classname) {
return classname.subName(
classname.lastIndexOf((byte)'.') + 1, classname.getByteLength());
}
public static String shortName(String classname) {
return classname.substring(classname.lastIndexOf('.') + 1);
}
/** Return the package name of a class name, excluding the trailing '.',
* "" if not existent.
*/
public static Name packagePart(Name classname) {
return classname.subName(0, classname.lastIndexOf((byte)'.'));
}
public static String packagePart(String classname) {
int lastDot = classname.lastIndexOf('.');
return (lastDot < 0 ? "" : classname.substring(0, lastDot));
}
public static List<Name> enclosingCandidates(Name name) {
List<Name> names = List.nil();
int index;
while ((index = name.lastIndexOf((byte)'$')) > 0) {
name = name.subName(0, index);
names = names.prepend(name);
}
return names;
}
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright (c) 1999, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.nio.CharBuffer;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.tree.EndPosTable;
import static com.sun.tools.javac.util.LayoutCharacters.*;
/**
* A simple abstraction of a source file, as needed for use in a diagnostic message.
* Provides access to the line and position in a line for any given character offset.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class DiagnosticSource {
/* constant DiagnosticSource to be used when sourcefile is missing */
public static final DiagnosticSource NO_SOURCE = new DiagnosticSource() {
@Override
protected boolean findLine(int pos) {
return false;
}
};
public DiagnosticSource(JavaFileObject fo, AbstractLog log) {
this.fileObject = fo;
this.log = log;
}
private DiagnosticSource() {}
/** Return the underlying file object handled by this
* DiagnosticSource object.
*/
public JavaFileObject getFile() {
return fileObject;
}
/** Return the one-based line number associated with a given pos
* for the current source file. Zero is returned if no line exists
* for the given position.
*/
public int getLineNumber(int pos) {
try {
if (findLine(pos)) {
return line;
}
return 0;
} finally {
buf = null;
}
}
/** Return the one-based column number associated with a given pos
* for the current source file. Zero is returned if no column exists
* for the given position.
*/
public int getColumnNumber(int pos, boolean expandTabs) {
try {
if (findLine(pos)) {
int column = 0;
for (int bp = lineStart; bp < pos; bp++) {
if (bp >= bufLen) {
return 0;
}
if (buf[bp] == '\t' && expandTabs) {
column = (column / TabInc * TabInc) + TabInc;
} else {
column++;
}
}
return column + 1; // positions are one-based
}
return 0;
} finally {
buf = null;
}
}
/** Return the content of the line containing a given pos.
*/
public String getLine(int pos) {
try {
if (!findLine(pos))
return null;
int lineEnd = lineStart;
while (lineEnd < bufLen && buf[lineEnd] != CR && buf[lineEnd] != LF)
lineEnd++;
if (lineEnd - lineStart == 0)
return null;
return new String(buf, lineStart, lineEnd - lineStart);
} finally {
buf = null;
}
}
public EndPosTable getEndPosTable() {
return endPosTable;
}
public void setEndPosTable(EndPosTable t) {
if (endPosTable != null && endPosTable != t)
throw new IllegalStateException("endPosTable already set");
endPosTable = t;
}
/** Find the line in the buffer that contains the current position
* @param pos Character offset into the buffer
*/
protected boolean findLine(int pos) {
if (pos == Position.NOPOS)
return false;
try {
// try and recover buffer from soft reference cache
if (buf == null && refBuf != null)
buf = refBuf.get();
if (buf == null) {
buf = initBuf(fileObject);
lineStart = 0;
line = 1;
} else if (lineStart > pos) { // messages don't come in order
lineStart = 0;
line = 1;
}
int bp = lineStart;
while (bp < bufLen && bp < pos) {
switch (buf[bp++]) {
case CR:
if (bp < bufLen && buf[bp] == LF) bp++;
line++;
lineStart = bp;
break;
case LF:
line++;
lineStart = bp;
break;
}
}
return bp <= bufLen;
} catch (IOException e) {
log.directError("source.unavailable");
buf = new char[0];
return false;
}
}
protected char[] initBuf(JavaFileObject fileObject) throws IOException {
char[] buf;
CharSequence cs = fileObject.getCharContent(true);
if (cs instanceof CharBuffer) {
CharBuffer cb = (CharBuffer) cs;
buf = JavacFileManager.toArray(cb);
bufLen = cb.limit();
} else {
buf = cs.toString().toCharArray();
bufLen = buf.length;
}
refBuf = new SoftReference<char[]>(buf);
return buf;
}
/** The underlying file object. */
protected JavaFileObject fileObject;
protected EndPosTable endPosTable;
/** A soft reference to the content of the file object. */
protected SoftReference<char[]> refBuf;
/** A temporary hard reference to the content of the file object. */
protected char[] buf;
/** The length of the content. */
protected int bufLen;
/** The start of a line found by findLine. */
protected int lineStart;
/** The line number of a line found by findLine. */
protected int line;
/** A log for reporting errors, such as errors accessing the content. */
protected AbstractLog log;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 1999, 2010, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/** Throwing an instance of this class causes immediate termination
* of the main compiler method. It is used when some non-recoverable
* error has been detected in the compiler environment at runtime.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class FatalError extends Error {
private static final long serialVersionUID = 0;
/** Construct a <code>FatalError</code> with the specified detail message.
* @param d A diagnostic containing the reason for failure.
*/
public FatalError(JCDiagnostic d) {
super(d.toString());
}
/** Construct a <code>FatalError</code> with the specified detail message
* and cause.
* @param d A diagnostic containing the reason for failure.
* @param t An exception causing the error
*/
public FatalError(JCDiagnostic d, Throwable t) {
super(d.toString(), t);
}
/** Construct a <code>FatalError</code> with the specified detail message.
* @param s An English(!) string describing the failure, typically because
* the diagnostic resources are missing.
*/
public FatalError(String s) {
super(s);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2010, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/**
* Simple filter acting as a boolean predicate. Method accepts return true if
* the supplied element matches against the filter.
*/
public interface Filter<T> {
/**
* Does this element match against the filter?
* @param t element to be checked
* @return true if the element satisfy constraints imposed by filter
*/
boolean accepts(T t);
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 2009, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.Set;
import java.util.Locale;
import javax.tools.Diagnostic;
import com.sun.tools.javac.api.DiagnosticFormatter;
import com.sun.tools.javac.api.DiagnosticFormatter.Configuration;
import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart;
import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.MultilineLimit;
import com.sun.tools.javac.api.DiagnosticFormatter.PositionKind;
/**
* A delegated diagnostic formatter delegates all formatting
* actions to an underlying formatter (aka the delegated formatter).
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class ForwardingDiagnosticFormatter<D extends Diagnostic<?>, F extends DiagnosticFormatter<D>>
implements DiagnosticFormatter<D> {
/**
* The delegated formatter
*/
protected F formatter;
/*
* configuration object used by this formatter
*/
protected ForwardingConfiguration configuration;
public ForwardingDiagnosticFormatter(F formatter) {
this.formatter = formatter;
this.configuration = new ForwardingConfiguration(formatter.getConfiguration());
}
/**
* Returns the underlying delegated formatter
* @return delegate formatter
*/
public F getDelegatedFormatter() {
return formatter;
}
public Configuration getConfiguration() {
return configuration;
}
public boolean displaySource(D diag) {
return formatter.displaySource(diag);
}
public String format(D diag, Locale l) {
return formatter.format(diag, l);
}
public String formatKind(D diag, Locale l) {
return formatter.formatKind(diag, l);
}
public String formatMessage(D diag, Locale l) {
return formatter.formatMessage(diag, l);
}
public String formatPosition(D diag, PositionKind pk, Locale l) {
return formatter.formatPosition(diag, pk, l);
}
public String formatSource(D diag, boolean fullname, Locale l) {
return formatter.formatSource(diag, fullname, l);
}
/**
* A delegated formatter configuration delegates all configurations settings
* to an underlying configuration object (aka the delegated configuration).
*/
public static class ForwardingConfiguration implements DiagnosticFormatter.Configuration {
/** The configurationr object to which the forwarding configuration delegates some settings */
protected Configuration configuration;
public ForwardingConfiguration(Configuration configuration) {
this.configuration = configuration;
}
/**
* Returns the underlying delegated configuration.
* @return delegated configuration
*/
public Configuration getDelegatedConfiguration() {
return configuration;
}
public int getMultilineLimit(MultilineLimit limit) {
return configuration.getMultilineLimit(limit);
}
public Set<DiagnosticPart> getVisible() {
return configuration.getVisible();
}
public void setMultilineLimit(MultilineLimit limit, int value) {
configuration.setMultilineLimit(limit, value);
}
public void setVisible(Set<DiagnosticPart> diagParts) {
configuration.setVisible(diagParts);
}
}
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/** <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class GraphUtils {
/**
* Basic interface for defining various dependency kinds. All dependency kinds
* must at least support basic capabilities to tell the DOT engine how to render them.
*/
public interface DependencyKind {
/**
* Returns the DOT representation (to be used in a {@code style} attribute
* that's most suited for this dependency kind.
*/
String getDotStyle();
}
/**
* This class is a basic abstract class for representing a node.
* A node is associated with a given data.
*/
public static abstract class Node<D> {
public final D data;
public Node(D data) {
this.data = data;
}
/**
* Get an array of the dependency kinds supported by this node.
*/
public abstract DependencyKind[] getSupportedDependencyKinds();
/**
* Get all dependencies, regardless of their kind.
*/
public abstract Iterable<? extends Node<D>> getAllDependencies();
/**
* Get a name for the dependency (of given kind) linking this node to a given node
*/
public abstract String getDependencyName(Node<D> to, DependencyKind dk);
@Override
public String toString() {
return data.toString();
}
}
/**
* This class specialized Node, by adding elements that are required in order
* to perform Tarjan computation of strongly connected components.
*/
public static abstract class TarjanNode<D> extends Node<D> implements Comparable<TarjanNode<D>> {
int index = -1;
int lowlink;
boolean active;
public TarjanNode(D data) {
super(data);
}
public abstract Iterable<? extends TarjanNode<D>> getAllDependencies();
public abstract Iterable<? extends TarjanNode<D>> getDependenciesByKind(DependencyKind dk);
public int compareTo(TarjanNode<D> o) {
return (index < o.index) ? -1 : (index == o.index) ? 0 : 1;
}
}
/**
* Tarjan's algorithm to determine strongly connected components of a
* directed graph in linear time. Works on TarjanNode.
*/
public static <D, N extends TarjanNode<D>> List<? extends List<? extends N>> tarjan(Iterable<? extends N> nodes) {
Tarjan<D, N> tarjan = new Tarjan<>();
return tarjan.findSCC(nodes);
}
//where
private static class Tarjan<D, N extends TarjanNode<D>> {
/** Unique node identifier. */
int index = 0;
/** List of SCCs found so far. */
ListBuffer<List<N>> sccs = new ListBuffer<>();
/** Stack of all reacheable nodes from given root. */
ListBuffer<N> stack = new ListBuffer<>();
private List<? extends List<? extends N>> findSCC(Iterable<? extends N> nodes) {
for (N node : nodes) {
if (node.index == -1) {
findSCC(node);
}
}
return sccs.toList();
}
private void findSCC(N v) {
visitNode(v);
for (TarjanNode<D> tn : v.getAllDependencies()) {
@SuppressWarnings("unchecked")
N n = (N)tn;
if (n.index == -1) {
//it's the first time we see this node
findSCC(n);
v.lowlink = Math.min(v.lowlink, n.lowlink);
} else if (stack.contains(n)) {
//this node is already reachable from current root
v.lowlink = Math.min(v.lowlink, n.index);
}
}
if (v.lowlink == v.index) {
//v is the root of a SCC
addSCC(v);
}
}
private void visitNode(N n) {
n.index = index;
n.lowlink = index;
index++;
stack.prepend(n);
n.active = true;
}
private void addSCC(N v) {
N n;
ListBuffer<N> cycle = new ListBuffer<>();
do {
n = stack.remove();
n.active = false;
cycle.add(n);
} while (n != v);
sccs.add(cycle.toList());
}
}
/**
* Debugging: dot representation of a set of connected nodes. The resulting
* dot representation will use {@code Node.toString} to display node labels
* and {@code Node.printDependency} to display edge labels. The resulting
* representation is also customizable with a graph name and a header.
*/
public static <D> String toDot(Iterable<? extends TarjanNode<D>> nodes, String name, String header) {
StringBuilder buf = new StringBuilder();
buf.append(String.format("digraph %s {\n", name));
buf.append(String.format("label = \"%s\";\n", header));
//dump nodes
for (TarjanNode<D> n : nodes) {
buf.append(String.format("%s [label = \"%s\"];\n", n.hashCode(), n.toString()));
}
//dump arcs
for (TarjanNode<D> from : nodes) {
for (DependencyKind dk : from.getSupportedDependencyKinds()) {
for (TarjanNode<D> to : from.getDependenciesByKind(dk)) {
buf.append(String.format("%s -> %s [label = \" %s \" style = %s ];\n",
from.hashCode(), to.hashCode(), from.getDependencyName(to, dk), dk.getDotStyle()));
}
}
}
buf.append("}\n");
return buf.toString();
}
}

View File

@@ -0,0 +1,198 @@
/*
* Copyright (c) 2014, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/**
* A hash table that maps Object to int.
*
* This is a custom hash table optimised for the Object -> int
* maps. This is done to avoid unnecessary object allocation in the image set.
*
* @author Charles Turner
* @author Per Bothner
*/
public class IntHashTable {
private static final int DEFAULT_INITIAL_SIZE = 64;
protected Object[] objs; // the domain set
protected int[] ints; // the image set
protected int mask; // used to clip int's into the domain
protected int num_bindings; // the number of mappings (including DELETED)
private final static Object DELETED = new Object();
/**
* Construct an Object -> int hash table.
*
* The default size of the hash table is 64 mappings.
*/
public IntHashTable() {
objs = new Object[DEFAULT_INITIAL_SIZE];
ints = new int[DEFAULT_INITIAL_SIZE];
mask = DEFAULT_INITIAL_SIZE - 1;
}
/**
* Construct an Object -> int hash table with a specified amount of mappings.
* @param capacity The number of default mappings in this hash table.
*/
public IntHashTable(int capacity) {
int log2Size = 4;
while (capacity > (1 << log2Size)) {
log2Size++;
}
capacity = 1 << log2Size;
objs = new Object[capacity];
ints = new int[capacity];
mask = capacity - 1;
}
/**
* Compute the hash code of a given object.
*
* @param key The object whose hash code is to be computed.
* @return zero if the object is null, otherwise the identityHashCode
*/
public int hash(Object key) {
return System.identityHashCode(key);
}
/**
* Find either the index of a key's value, or the index of an available space.
*
* @param key The key to whose value you want to find.
* @param hash The hash code of this key.
* @return Either the index of the key's value, or an index pointing to
* unoccupied space.
*/
public int lookup(Object key, int hash) {
Object node;
int hash1 = hash ^ (hash >>> 15);
int hash2 = (hash ^ (hash << 6)) | 1; //ensure coprimeness
int deleted = -1;
for (int i = hash1 & mask;; i = (i + hash2) & mask) {
node = objs[i];
if (node == key)
return i;
if (node == null)
return deleted >= 0 ? deleted : i;
if (node == DELETED && deleted < 0)
deleted = i;
}
}
/**
* Lookup a given key's value in the hash table.
*
* @param key The key whose value you want to find.
* @return Either the index of the key's value, or an index pointing to
* unoccupied space.
*/
public int lookup(Object key) {
return lookup(key, hash(key));
}
/**
* Return the value stored at the specified index in the table.
*
* @param index The index to inspect, as returned from {@link #lookup}
* @return A non-negative integer if the index contains a non-null
* value, or -1 if it does.
*/
public int getFromIndex(int index) {
Object node = objs[index];
return node == null || node == DELETED ? -1 : ints[index];
}
/**
* Associates the specified key with the specified value in this map.
*
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
* @param index the index at which to place this binding, as returned
* from {@link #lookup}.
* @return previous value associated with specified key, or -1 if there was
* no mapping for key.
*/
public int putAtIndex(Object key, int value, int index) {
Object old = objs[index];
if (old == null || old == DELETED) {
objs[index] = key;
ints[index] = value;
if (old != DELETED)
num_bindings++;
if (3 * num_bindings >= 2 * objs.length)
rehash();
return -1;
} else { // update existing mapping
int oldValue = ints[index];
ints[index] = value;
return oldValue;
}
}
public int remove(Object key) {
int index = lookup(key);
Object old = objs[index];
if (old == null || old == DELETED)
return -1;
objs[index] = DELETED;
return ints[index];
}
/**
* Expand the hash table when it exceeds the load factor.
*
* Rehash the existing objects.
*/
protected void rehash() {
Object[] oldObjsTable = objs;
int[] oldIntsTable = ints;
int oldCapacity = oldObjsTable.length;
int newCapacity = oldCapacity << 1;
Object[] newObjTable = new Object[newCapacity];
int[] newIntTable = new int[newCapacity];
int newMask = newCapacity - 1;
objs = newObjTable;
ints = newIntTable;
mask = newMask;
num_bindings = 0; // this is recomputed below
Object key;
for (int i = oldIntsTable.length; --i >= 0;) {
key = oldObjsTable[i];
if (key != null && key != DELETED)
putAtIndex(key, oldIntsTable[i], lookup(key, hash(key)));
}
}
/**
* Removes all mappings from this map.
*/
public void clear() {
for (int i = objs.length; --i >= 0;) {
objs[i] = null;
}
num_bindings = 0;
}
}

View File

@@ -0,0 +1,641 @@
/*
* Copyright (c) 2003, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Set;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.api.DiagnosticFormatter;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.tree.JCTree;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
/** An abstraction of a diagnostic message generated by the compiler.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class JCDiagnostic implements Diagnostic<JavaFileObject> {
/** A factory for creating diagnostic objects. */
public static class Factory {
/** The context key for the diagnostic factory. */
protected static final Context.Key<JCDiagnostic.Factory> diagnosticFactoryKey =
new Context.Key<JCDiagnostic.Factory>();
/** Get the Factory instance for this context. */
public static Factory instance(Context context) {
Factory instance = context.get(diagnosticFactoryKey);
if (instance == null)
instance = new Factory(context);
return instance;
}
DiagnosticFormatter<JCDiagnostic> formatter;
final String prefix;
final Set<DiagnosticFlag> defaultErrorFlags;
/** Create a new diagnostic factory. */
protected Factory(Context context) {
this(JavacMessages.instance(context), "compiler");
context.put(diagnosticFactoryKey, this);
final Options options = Options.instance(context);
initOptions(options);
options.addListener(new Runnable() {
public void run() {
initOptions(options);
}
});
}
private void initOptions(Options options) {
if (options.isSet("onlySyntaxErrorsUnrecoverable"))
defaultErrorFlags.add(DiagnosticFlag.RECOVERABLE);
}
/** Create a new diagnostic factory. */
public Factory(JavacMessages messages, String prefix) {
this.prefix = prefix;
this.formatter = new BasicDiagnosticFormatter(messages);
defaultErrorFlags = EnumSet.of(DiagnosticFlag.MANDATORY);
}
/**
* Create an error diagnostic.
* @param source The source of the compilation unit, if any, in which to report the error.
* @param pos The source position at which to report the error.
* @param key The key for the localized error message.
* @param args Fields of the error message.
*/
public JCDiagnostic error(
DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(ERROR, null, defaultErrorFlags, source, pos, key, args);
}
/**
* Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
* @param source The source of the compilation unit, if any, in which to report the warning.
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
* @see MandatoryWarningHandler
*/
public JCDiagnostic mandatoryWarning(
DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(WARNING, null, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, key, args);
}
/**
* Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
* @param lc The lint category for the diagnostic
* @param source The source of the compilation unit, if any, in which to report the warning.
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
* @see MandatoryWarningHandler
*/
public JCDiagnostic mandatoryWarning(
LintCategory lc,
DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(WARNING, lc, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, key, args);
}
/**
* Create a warning diagnostic.
* @param lc The lint category for the diagnostic
* @param key The key for the localized error message.
* @param args Fields of the warning message.
* @see MandatoryWarningHandler
*/
public JCDiagnostic warning(
LintCategory lc, String key, Object... args) {
return create(WARNING, lc, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
}
/**
* Create a warning diagnostic.
* @param source The source of the compilation unit, if any, in which to report the warning.
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public JCDiagnostic warning(
DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(WARNING, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
}
/**
* Create a warning diagnostic.
* @param lc The lint category for the diagnostic
* @param source The source of the compilation unit, if any, in which to report the warning.
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
* @see MandatoryWarningHandler
*/
public JCDiagnostic warning(
LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(WARNING, lc, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
}
/**
* Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
* @param key The key for the localized message.
* @param args Fields of the message.
* @see MandatoryWarningHandler
*/
public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) {
return create(NOTE, null, EnumSet.of(DiagnosticFlag.MANDATORY), source, null, key, args);
}
/**
* Create a note diagnostic.
* @param key The key for the localized error message.
* @param args Fields of the message.
*/
public JCDiagnostic note(String key, Object... args) {
return create(NOTE, null, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
}
/**
* Create a note diagnostic.
* @param source The source of the compilation unit, if any, in which to report the note.
* @param pos The source position at which to report the note.
* @param key The key for the localized message.
* @param args Fields of the message.
*/
public JCDiagnostic note(
DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(NOTE, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
}
/**
* Create a fragment diagnostic, for use as an argument in other diagnostics
* @param key The key for the localized message.
* @param args Fields of the message.
*/
public JCDiagnostic fragment(String key, Object... args) {
return create(FRAGMENT, null, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
}
/**
* Create a new diagnostic of the given kind, which is not mandatory and which has
* no lint category.
* @param kind The diagnostic kind
* @param source The source of the compilation unit, if any, in which to report the message.
* @param pos The source position at which to report the message.
* @param key The key for the localized message.
* @param args Fields of the message.
*/
public JCDiagnostic create(
DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(kind, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
}
/**
* Create a new diagnostic of the given kind.
* @param kind The diagnostic kind
* @param lc The lint category, if applicable, or null
* @param flags The set of flags for the diagnostic
* @param source The source of the compilation unit, if any, in which to report the message.
* @param pos The source position at which to report the message.
* @param key The key for the localized message.
* @param args Fields of the message.
*/
public JCDiagnostic create(
DiagnosticType kind, LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return new JCDiagnostic(formatter, kind, lc, flags, source, pos, qualify(kind, key), args);
}
protected String qualify(DiagnosticType t, String key) {
return prefix + "." + t.key + "." + key;
}
}
/**
* Create a fragment diagnostic, for use as an argument in other diagnostics
* @param key The key for the localized error message.
* @param args Fields of the error message.
*
*/
@Deprecated
public static JCDiagnostic fragment(String key, Object... args) {
return new JCDiagnostic(getFragmentFormatter(),
FRAGMENT,
null,
EnumSet.noneOf(DiagnosticFlag.class),
null,
null,
"compiler." + FRAGMENT.key + "." + key,
args);
}
//where
@Deprecated
public static DiagnosticFormatter<JCDiagnostic> getFragmentFormatter() {
if (fragmentFormatter == null) {
fragmentFormatter = new BasicDiagnosticFormatter(JavacMessages.getDefaultMessages());
}
return fragmentFormatter;
}
/**
* A DiagnosticType defines the type of the diagnostic.
**/
public enum DiagnosticType {
/** A fragment of an enclosing diagnostic. */
FRAGMENT("misc"),
/** A note: similar to, but less serious than, a warning. */
NOTE("note"),
/** A warning. */
WARNING("warn"),
/** An error. */
ERROR("err");
final String key;
/** Create a DiagnosticType.
* @param key A string used to create the resource key for the diagnostic.
*/
DiagnosticType(String key) {
this.key = key;
}
};
/**
* A DiagnosticPosition provides information about the positions in a file
* that gave rise to a diagnostic. It always defines a "preferred" position
* that most accurately defines the location of the diagnostic, it may also
* provide a related tree node that spans that location.
*/
public static interface DiagnosticPosition {
/** Gets the tree node, if any, to which the diagnostic applies. */
JCTree getTree();
/** If there is a tree node, get the start position of the tree node.
* Otherwise, just returns the same as getPreferredPosition(). */
int getStartPosition();
/** Get the position within the file that most accurately defines the
* location for the diagnostic. */
int getPreferredPosition();
/** If there is a tree node, and if endPositions are available, get
* the end position of the tree node. Otherwise, just returns the
* same as getPreferredPosition(). */
int getEndPosition(EndPosTable endPosTable);
}
/**
* A DiagnosticPosition that simply identifies a position, but no related
* tree node, as the location for a diagnostic. Used for scanner and parser
* diagnostics. */
public static class SimpleDiagnosticPosition implements DiagnosticPosition {
public SimpleDiagnosticPosition(int pos) {
this.pos = pos;
}
public JCTree getTree() {
return null;
}
public int getStartPosition() {
return pos;
}
public int getPreferredPosition() {
return pos;
}
public int getEndPosition(EndPosTable endPosTable) {
return pos;
}
private final int pos;
}
public enum DiagnosticFlag {
MANDATORY,
RESOLVE_ERROR,
SYNTAX,
RECOVERABLE,
NON_DEFERRABLE,
COMPRESSED
}
private final DiagnosticType type;
private final DiagnosticSource source;
private final DiagnosticPosition position;
private final String key;
protected final Object[] args;
private final Set<DiagnosticFlag> flags;
private final LintCategory lintCategory;
/** source line position (set lazily) */
private SourcePosition sourcePosition;
/**
* This class is used to defer the line/column position fetch logic after diagnostic construction.
*/
class SourcePosition {
private final int line;
private final int column;
SourcePosition() {
int n = (position == null ? Position.NOPOS : position.getPreferredPosition());
if (n == Position.NOPOS || source == null)
line = column = -1;
else {
line = source.getLineNumber(n);
column = source.getColumnNumber(n, true);
}
}
public int getLineNumber() {
return line;
}
public int getColumnNumber() {
return column;
}
}
/**
* Create a diagnostic object.
* @param formatter the formatter to use for the diagnostic
* @param dt the type of diagnostic
* @param lc the lint category for the diagnostic
* @param source the name of the source file, or null if none.
* @param pos the character offset within the source file, if given.
* @param key a resource key to identify the text of the diagnostic
* @param args arguments to be included in the text of the diagnostic
*/
protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter,
DiagnosticType dt,
LintCategory lc,
Set<DiagnosticFlag> flags,
DiagnosticSource source,
DiagnosticPosition pos,
String key,
Object... args) {
if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
throw new IllegalArgumentException();
this.defaultFormatter = formatter;
this.type = dt;
this.lintCategory = lc;
this.flags = flags;
this.source = source;
this.position = pos;
this.key = key;
this.args = args;
}
/**
* Get the type of this diagnostic.
* @return the type of this diagnostic
*/
public DiagnosticType getType() {
return type;
}
/**
* Get the subdiagnostic list
* @return subdiagnostic list
*/
public List<JCDiagnostic> getSubdiagnostics() {
return List.nil();
}
public boolean isMultiline() {
return false;
}
/**
* Check whether or not this diagnostic is required to be shown.
* @return true if this diagnostic is required to be shown.
*/
public boolean isMandatory() {
return flags.contains(DiagnosticFlag.MANDATORY);
}
/**
* Check whether this diagnostic has an associated lint category.
*/
public boolean hasLintCategory() {
return (lintCategory != null);
}
/**
* Get the associated lint category, or null if none.
*/
public LintCategory getLintCategory() {
return lintCategory;
}
/**
* Get the name of the source file referred to by this diagnostic.
* @return the name of the source referred to with this diagnostic, or null if none
*/
public JavaFileObject getSource() {
if (source == null)
return null;
else
return source.getFile();
}
/**
* Get the source referred to by this diagnostic.
* @return the source referred to with this diagnostic, or null if none
*/
public DiagnosticSource getDiagnosticSource() {
return source;
}
protected int getIntStartPosition() {
return (position == null ? Position.NOPOS : position.getStartPosition());
}
protected int getIntPosition() {
return (position == null ? Position.NOPOS : position.getPreferredPosition());
}
protected int getIntEndPosition() {
return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable()));
}
public long getStartPosition() {
return getIntStartPosition();
}
public long getPosition() {
return getIntPosition();
}
public long getEndPosition() {
return getIntEndPosition();
}
public DiagnosticPosition getDiagnosticPosition() {
return position;
}
/**
* Get the line number within the source referred to by this diagnostic.
* @return the line number within the source referred to by this diagnostic
*/
public long getLineNumber() {
if (sourcePosition == null) {
sourcePosition = new SourcePosition();
}
return sourcePosition.getLineNumber();
}
/**
* Get the column number within the line of source referred to by this diagnostic.
* @return the column number within the line of source referred to by this diagnostic
*/
public long getColumnNumber() {
if (sourcePosition == null) {
sourcePosition = new SourcePosition();
}
return sourcePosition.getColumnNumber();
}
/**
* Get the arguments to be included in the text of the diagnostic.
* @return the arguments to be included in the text of the diagnostic
*/
public Object[] getArgs() {
return args;
}
/**
* Get the prefix string associated with this type of diagnostic.
* @return the prefix string associated with this type of diagnostic
*/
public String getPrefix() {
return getPrefix(type);
}
/**
* Get the prefix string associated with a particular type of diagnostic.
* @return the prefix string associated with a particular type of diagnostic
*/
public String getPrefix(DiagnosticType dt) {
return defaultFormatter.formatKind(this, Locale.getDefault());
}
/**
* Return the standard presentation of this diagnostic.
*/
@Override
public String toString() {
return defaultFormatter.format(this,Locale.getDefault());
}
private DiagnosticFormatter<JCDiagnostic> defaultFormatter;
@Deprecated
private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter;
// Methods for javax.tools.Diagnostic
public Diagnostic.Kind getKind() {
switch (type) {
case NOTE:
return Diagnostic.Kind.NOTE;
case WARNING:
return flags.contains(DiagnosticFlag.MANDATORY)
? Diagnostic.Kind.MANDATORY_WARNING
: Diagnostic.Kind.WARNING;
case ERROR:
return Diagnostic.Kind.ERROR;
default:
return Diagnostic.Kind.OTHER;
}
}
public String getCode() {
return key;
}
public String getMessage(Locale locale) {
return defaultFormatter.formatMessage(this, locale);
}
public void setFlag(DiagnosticFlag flag) {
flags.add(flag);
if (type == DiagnosticType.ERROR) {
switch (flag) {
case SYNTAX:
flags.remove(DiagnosticFlag.RECOVERABLE);
break;
case RESOLVE_ERROR:
flags.add(DiagnosticFlag.RECOVERABLE);
break;
}
}
}
public boolean isFlagSet(DiagnosticFlag flag) {
return flags.contains(flag);
}
public static class MultilineDiagnostic extends JCDiagnostic {
private final List<JCDiagnostic> subdiagnostics;
public MultilineDiagnostic(JCDiagnostic other, List<JCDiagnostic> subdiagnostics) {
super(other.defaultFormatter,
other.getType(),
other.getLintCategory(),
other.flags,
other.getDiagnosticSource(),
other.position,
other.getCode(),
other.getArgs());
this.subdiagnostics = subdiagnostics;
}
@Override
public List<JCDiagnostic> getSubdiagnostics() {
return subdiagnostics;
}
@Override
public boolean isMultiline() {
return true;
}
}
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) 2005, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import com.sun.tools.javac.api.Messages;
import java.lang.ref.SoftReference;
import java.util.ResourceBundle;
import java.util.MissingResourceException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Support for formatted localized messages.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class JavacMessages implements Messages {
/** The context key for the JavacMessages object. */
public static final Context.Key<JavacMessages> messagesKey =
new Context.Key<JavacMessages>();
/** Get the JavacMessages instance for this context. */
public static JavacMessages instance(Context context) {
JavacMessages instance = context.get(messagesKey);
if (instance == null)
instance = new JavacMessages(context);
return instance;
}
private Map<Locale, SoftReference<List<ResourceBundle>>> bundleCache;
private List<String> bundleNames;
private Locale currentLocale;
private List<ResourceBundle> currentBundles;
public Locale getCurrentLocale() {
return currentLocale;
}
public void setCurrentLocale(Locale locale) {
if (locale == null) {
locale = Locale.getDefault();
}
this.currentBundles = getBundles(locale);
this.currentLocale = locale;
}
/** Creates a JavacMessages object.
*/
public JavacMessages(Context context) {
this(defaultBundleName, context.get(Locale.class));
context.put(messagesKey, this);
}
/** Creates a JavacMessages object.
* @param bundleName the name to identify the resource bundle of localized messages.
*/
public JavacMessages(String bundleName) throws MissingResourceException {
this(bundleName, null);
}
/** Creates a JavacMessages object.
* @param bundleName the name to identify the resource bundle of localized messages.
*/
public JavacMessages(String bundleName, Locale locale) throws MissingResourceException {
bundleNames = List.nil();
bundleCache = new HashMap<Locale, SoftReference<List<ResourceBundle>>>();
add(bundleName);
setCurrentLocale(locale);
}
public JavacMessages() throws MissingResourceException {
this(defaultBundleName);
}
public void add(String bundleName) throws MissingResourceException {
bundleNames = bundleNames.prepend(bundleName);
if (!bundleCache.isEmpty())
bundleCache.clear();
currentBundles = null;
}
public List<ResourceBundle> getBundles(Locale locale) {
if (locale == currentLocale && currentBundles != null)
return currentBundles;
SoftReference<List<ResourceBundle>> bundles = bundleCache.get(locale);
List<ResourceBundle> bundleList = bundles == null ? null : bundles.get();
if (bundleList == null) {
bundleList = List.nil();
for (String bundleName : bundleNames) {
try {
ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale);
bundleList = bundleList.prepend(rb);
} catch (MissingResourceException e) {
throw new InternalError("Cannot find javac resource bundle for locale " + locale);
}
}
bundleCache.put(locale, new SoftReference<List<ResourceBundle>>(bundleList));
}
return bundleList;
}
/** Gets the localized string corresponding to a key, formatted with a set of args.
*/
public String getLocalizedString(String key, Object... args) {
return getLocalizedString(currentLocale, key, args);
}
public String getLocalizedString(Locale l, String key, Object... args) {
if (l == null)
l = getCurrentLocale();
return getLocalizedString(getBundles(l), key, args);
}
/* Static access:
* javac has a firmly entrenched notion of a default message bundle
* which it can access from any static context. This is used to get
* easy access to simple localized strings.
*/
private static final String defaultBundleName =
"com.sun.tools.javac.resources.compiler";
private static ResourceBundle defaultBundle;
private static JavacMessages defaultMessages;
/**
* Gets a localized string from the compiler's default bundle.
*/
// used to support legacy Log.getLocalizedString
static String getDefaultLocalizedString(String key, Object... args) {
return getLocalizedString(List.of(getDefaultBundle()), key, args);
}
// used to support legacy static Diagnostic.fragment
@Deprecated
static JavacMessages getDefaultMessages() {
if (defaultMessages == null)
defaultMessages = new JavacMessages(defaultBundleName);
return defaultMessages;
}
public static ResourceBundle getDefaultBundle() {
try {
if (defaultBundle == null)
defaultBundle = ResourceBundle.getBundle(defaultBundleName);
return defaultBundle;
}
catch (MissingResourceException e) {
throw new Error("Fatal: Resource for compiler is missing", e);
}
}
private static String getLocalizedString(List<ResourceBundle> bundles,
String key,
Object... args) {
String msg = null;
for (List<ResourceBundle> l = bundles; l.nonEmpty() && msg == null; l = l.tail) {
ResourceBundle rb = l.head;
try {
msg = rb.getString(key);
}
catch (MissingResourceException e) {
// ignore, try other bundles in list
}
}
if (msg == null) {
msg = "compiler message file broken: key=" + key +
" arguments={0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}";
}
return MessageFormat.format(msg, args);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 1999, 2010, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/** An interface containing layout character constants used in Java
* programs.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public interface LayoutCharacters {
/** Tabulator column increment.
*/
final static int TabInc = 8;
/** Standard indentation for subdiagnostics
*/
final static int DiagInc = 4;
/** Standard indentation for additional diagnostic lines
*/
final static int DetailsInc = 2;
/** Tabulator character.
*/
final static byte TAB = 0x9;
/** Line feed character.
*/
final static byte LF = 0xA;
/** Form feed character.
*/
final static byte FF = 0xC;
/** Carriage return character.
*/
final static byte CR = 0xD;
/** End of input character. Used as a sentinel to denote the
* character one beyond the last defined character in a
* source file.
*/
final static byte EOI = 0x1A;
}

View File

@@ -0,0 +1,540 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.AbstractCollection;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/** A class for generic linked lists. Links are supposed to be
* immutable, the only exception being the incremental construction of
* lists via ListBuffers. List is the main container class in
* GJC. Most data structures and algorithms in GJC use lists rather
* than arrays.
*
* <p>Lists are always trailed by a sentinel element, whose head and tail
* are both null.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class List<A> extends AbstractCollection<A> implements java.util.List<A> {
/** The first element of the list, supposed to be immutable.
*/
public A head;
/** The remainder of the list except for its first element, supposed
* to be immutable.
*/
//@Deprecated
public List<A> tail;
/** Construct a list given its head and tail.
*/
List(A head, List<A> tail) {
this.tail = tail;
this.head = head;
}
/** Construct an empty list.
*/
@SuppressWarnings("unchecked")
public static <A> List<A> nil() {
return (List<A>)EMPTY_LIST;
}
private static final List<?> EMPTY_LIST = new List<Object>(null,null) {
public List<Object> setTail(List<Object> tail) {
throw new UnsupportedOperationException();
}
public boolean isEmpty() {
return true;
}
};
/** Returns the list obtained from 'l' after removing all elements 'elem'
*/
public static <A> List<A> filter(List<A> l, A elem) {
Assert.checkNonNull(elem);
List<A> res = List.nil();
for (A a : l) {
if (a != null && !a.equals(elem)) {
res = res.prepend(a);
}
}
return res.reverse();
}
public List<A> intersect(List<A> that) {
ListBuffer<A> buf = new ListBuffer<>();
for (A el : this) {
if (that.contains(el)) {
buf.append(el);
}
}
return buf.toList();
}
public List<A> diff(List<A> that) {
ListBuffer<A> buf = new ListBuffer<>();
for (A el : this) {
if (!that.contains(el)) {
buf.append(el);
}
}
return buf.toList();
}
/**
* Create a new list from the first {@code n} elements of this list
*/
public List<A> take(int n) {
ListBuffer<A> buf = new ListBuffer<>();
int count = 0;
for (A el : this) {
if (count++ == n) break;
buf.append(el);
}
return buf.toList();
}
/** Construct a list consisting of given element.
*/
public static <A> List<A> of(A x1) {
return new List<A>(x1, List.<A>nil());
}
/** Construct a list consisting of given elements.
*/
public static <A> List<A> of(A x1, A x2) {
return new List<A>(x1, of(x2));
}
/** Construct a list consisting of given elements.
*/
public static <A> List<A> of(A x1, A x2, A x3) {
return new List<A>(x1, of(x2, x3));
}
/** Construct a list consisting of given elements.
*/
@SuppressWarnings({"varargs", "unchecked"})
public static <A> List<A> of(A x1, A x2, A x3, A... rest) {
return new List<A>(x1, new List<A>(x2, new List<A>(x3, from(rest))));
}
/**
* Construct a list consisting all elements of given array.
* @param array an array; if {@code null} return an empty list
*/
public static <A> List<A> from(A[] array) {
List<A> xs = nil();
if (array != null)
for (int i = array.length - 1; i >= 0; i--)
xs = new List<A>(array[i], xs);
return xs;
}
public static <A> List<A> from(Iterable<? extends A> coll) {
ListBuffer<A> xs = new ListBuffer<>();
for (A a : coll) {
xs.append(a);
}
return xs.toList();
}
/** Construct a list consisting of a given number of identical elements.
* @param len The number of elements in the list.
* @param init The value of each element.
*/
@Deprecated
public static <A> List<A> fill(int len, A init) {
List<A> l = nil();
for (int i = 0; i < len; i++) l = new List<A>(init, l);
return l;
}
/** Does list have no elements?
*/
@Override
public boolean isEmpty() {
return tail == null;
}
/** Does list have elements?
*/
//@Deprecated
public boolean nonEmpty() {
return tail != null;
}
/** Return the number of elements in this list.
*/
//@Deprecated
public int length() {
List<A> l = this;
int len = 0;
while (l.tail != null) {
l = l.tail;
len++;
}
return len;
}
@Override
public int size() {
return length();
}
public List<A> setTail(List<A> tail) {
this.tail = tail;
return tail;
}
/** Prepend given element to front of list, forming and returning
* a new list.
*/
public List<A> prepend(A x) {
return new List<A>(x, this);
}
/** Prepend given list of elements to front of list, forming and returning
* a new list.
*/
public List<A> prependList(List<A> xs) {
if (this.isEmpty()) return xs;
if (xs.isEmpty()) return this;
if (xs.tail.isEmpty()) return prepend(xs.head);
// return this.prependList(xs.tail).prepend(xs.head);
List<A> result = this;
List<A> rev = xs.reverse();
Assert.check(rev != xs);
// since xs.reverse() returned a new list, we can reuse the
// individual List objects, instead of allocating new ones.
while (rev.nonEmpty()) {
List<A> h = rev;
rev = rev.tail;
h.setTail(result);
result = h;
}
return result;
}
/** Reverse list.
* If the list is empty or a singleton, then the same list is returned.
* Otherwise a new list is formed.
*/
public List<A> reverse() {
// if it is empty or a singleton, return itself
if (isEmpty() || tail.isEmpty())
return this;
List<A> rev = nil();
for (List<A> l = this; l.nonEmpty(); l = l.tail)
rev = new List<A>(l.head, rev);
return rev;
}
/** Append given element at length, forming and returning
* a new list.
*/
public List<A> append(A x) {
return of(x).prependList(this);
}
/** Append given list at length, forming and returning
* a new list.
*/
public List<A> appendList(List<A> x) {
return x.prependList(this);
}
/**
* Append given list buffer at length, forming and returning a new
* list.
*/
public List<A> appendList(ListBuffer<A> x) {
return appendList(x.toList());
}
/** Copy successive elements of this list into given vector until
* list is exhausted or end of vector is reached.
*/
@Override @SuppressWarnings("unchecked")
public <T> T[] toArray(T[] vec) {
int i = 0;
List<A> l = this;
Object[] dest = vec;
while (l.nonEmpty() && i < vec.length) {
dest[i] = l.head;
l = l.tail;
i++;
}
if (l.isEmpty()) {
if (i < vec.length)
vec[i] = null;
return vec;
}
vec = (T[])Array.newInstance(vec.getClass().getComponentType(), size());
return toArray(vec);
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
/** Form a string listing all elements with given separator character.
*/
public String toString(String sep) {
if (isEmpty()) {
return "";
} else {
StringBuilder buf = new StringBuilder();
buf.append(head);
for (List<A> l = tail; l.nonEmpty(); l = l.tail) {
buf.append(sep);
buf.append(l.head);
}
return buf.toString();
}
}
/** Form a string listing all elements with comma as the separator character.
*/
@Override
public String toString() {
return toString(",");
}
/** Compute a hash code, overrides Object
* @see java.util.List#hashCode
*/
@Override
public int hashCode() {
List<A> l = this;
int h = 1;
while (l.tail != null) {
h = h * 31 + (l.head == null ? 0 : l.head.hashCode());
l = l.tail;
}
return h;
}
/** Is this list the same as other list?
* @see java.util.List#equals
*/
@Override
public boolean equals(Object other) {
if (other instanceof List<?>)
return equals(this, (List<?>)other);
if (other instanceof java.util.List<?>) {
List<A> t = this;
Iterator<?> oIter = ((java.util.List<?>) other).iterator();
while (t.tail != null && oIter.hasNext()) {
Object o = oIter.next();
if ( !(t.head == null ? o == null : t.head.equals(o)))
return false;
t = t.tail;
}
return (t.isEmpty() && !oIter.hasNext());
}
return false;
}
/** Are the two lists the same?
*/
public static boolean equals(List<?> xs, List<?> ys) {
while (xs.tail != null && ys.tail != null) {
if (xs.head == null) {
if (ys.head != null) return false;
} else {
if (!xs.head.equals(ys.head)) return false;
}
xs = xs.tail;
ys = ys.tail;
}
return xs.tail == null && ys.tail == null;
}
/** Does the list contain the specified element?
*/
@Override
public boolean contains(Object x) {
List<A> l = this;
while (l.tail != null) {
if (x == null) {
if (l.head == null) return true;
} else {
if (l.head.equals(x)) return true;
}
l = l.tail;
}
return false;
}
/** The last element in the list, if any, or null.
*/
public A last() {
A last = null;
List<A> t = this;
while (t.tail != null) {
last = t.head;
t = t.tail;
}
return last;
}
@SuppressWarnings("unchecked")
public static <T> List<T> convert(Class<T> klass, List<?> list) {
if (list == null)
return null;
for (Object o : list)
klass.cast(o);
return (List<T>)list;
}
private static final Iterator<?> EMPTYITERATOR = new Iterator<Object>() {
public boolean hasNext() {
return false;
}
public Object next() {
throw new java.util.NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
@SuppressWarnings("unchecked")
private static <A> Iterator<A> emptyIterator() {
return (Iterator<A>)EMPTYITERATOR;
}
@Override
public Iterator<A> iterator() {
if (tail == null)
return emptyIterator();
return new Iterator<A>() {
List<A> elems = List.this;
public boolean hasNext() {
return elems.tail != null;
}
public A next() {
if (elems.tail == null)
throw new NoSuchElementException();
A result = elems.head;
elems = elems.tail;
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public A get(int index) {
if (index < 0)
throw new IndexOutOfBoundsException(String.valueOf(index));
List<A> l = this;
for (int i = index; i-- > 0 && !l.isEmpty(); l = l.tail)
;
if (l.isEmpty())
throw new IndexOutOfBoundsException("Index: " + index + ", " +
"Size: " + size());
return l.head;
}
public boolean addAll(int index, Collection<? extends A> c) {
if (c.isEmpty())
return false;
throw new UnsupportedOperationException();
}
public A set(int index, A element) {
throw new UnsupportedOperationException();
}
public void add(int index, A element) {
throw new UnsupportedOperationException();
}
public A remove(int index) {
throw new UnsupportedOperationException();
}
public int indexOf(Object o) {
int i = 0;
for (List<A> l = this; l.tail != null; l = l.tail, i++) {
if (l.head == null ? o == null : l.head.equals(o))
return i;
}
return -1;
}
public int lastIndexOf(Object o) {
int last = -1;
int i = 0;
for (List<A> l = this; l.tail != null; l = l.tail, i++) {
if (l.head == null ? o == null : l.head.equals(o))
last = i;
}
return last;
}
public ListIterator<A> listIterator() {
return Collections.unmodifiableList(new ArrayList<A>(this)).listIterator();
}
public ListIterator<A> listIterator(int index) {
return Collections.unmodifiableList(new ArrayList<A>(this)).listIterator(index);
}
public java.util.List<A> subList(int fromIndex, int toIndex) {
if (fromIndex < 0 || toIndex > size() || fromIndex > toIndex)
throw new IllegalArgumentException();
ArrayList<A> a = new ArrayList<A>(toIndex - fromIndex);
int i = 0;
for (List<A> l = this; l.tail != null; l = l.tail, i++) {
if (i == toIndex)
break;
if (i >= fromIndex)
a.add(l.head);
}
return Collections.unmodifiableList(a);
}
}

View File

@@ -0,0 +1,273 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
/** A class for constructing lists by appending elements. Modelled after
* java.lang.StringBuffer.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class ListBuffer<A> extends AbstractQueue<A> {
public static <T> ListBuffer<T> of(T x) {
ListBuffer<T> lb = new ListBuffer<T>();
lb.add(x);
return lb;
}
/** The list of elements of this buffer.
*/
private List<A> elems;
/** A pointer pointing to the last element of 'elems' containing data,
* or null if the list is empty.
*/
private List<A> last;
/** The number of element in this buffer.
*/
private int count;
/** Has a list been created from this buffer yet?
*/
private boolean shared;
/** Create a new initially empty list buffer.
*/
public ListBuffer() {
clear();
}
public final void clear() {
this.elems = List.nil();
this.last = null;
count = 0;
shared = false;
}
/** Return the number of elements in this buffer.
*/
public int length() {
return count;
}
public int size() {
return count;
}
/** Is buffer empty?
*/
public boolean isEmpty() {
return count == 0;
}
/** Is buffer not empty?
*/
public boolean nonEmpty() {
return count != 0;
}
/** Copy list and sets last.
*/
private void copy() {
if (elems.nonEmpty()) {
List<A> orig = elems;
elems = last = List.<A>of(orig.head);
while ((orig = orig.tail).nonEmpty()) {
last.tail = List.<A>of(orig.head);
last = last.tail;
}
}
}
/** Prepend an element to buffer.
*/
public ListBuffer<A> prepend(A x) {
elems = elems.prepend(x);
if (last == null) last = elems;
count++;
return this;
}
/** Append an element to buffer.
*/
public ListBuffer<A> append(A x) {
x.getClass(); // null check
if (shared) copy();
List<A> newLast = List.<A>of(x);
if (last != null) {
last.tail = newLast;
last = newLast;
} else {
elems = last = newLast;
}
count++;
return this;
}
/** Append all elements in a list to buffer.
*/
public ListBuffer<A> appendList(List<A> xs) {
while (xs.nonEmpty()) {
append(xs.head);
xs = xs.tail;
}
return this;
}
/** Append all elements in a list to buffer.
*/
public ListBuffer<A> appendList(ListBuffer<A> xs) {
return appendList(xs.toList());
}
/** Append all elements in an array to buffer.
*/
public ListBuffer<A> appendArray(A[] xs) {
for (int i = 0; i < xs.length; i++) {
append(xs[i]);
}
return this;
}
/** Convert buffer to a list of all its elements.
*/
public List<A> toList() {
shared = true;
return elems;
}
/** Does the list contain the specified element?
*/
public boolean contains(Object x) {
return elems.contains(x);
}
/** Convert buffer to an array
*/
public <T> T[] toArray(T[] vec) {
return elems.toArray(vec);
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
/** The first element in this buffer.
*/
public A first() {
return elems.head;
}
/** Return first element in this buffer and remove
*/
public A next() {
A x = elems.head;
if (!elems.isEmpty()) {
elems = elems.tail;
if (elems.isEmpty()) last = null;
count--;
}
return x;
}
/** An enumeration of all elements in this buffer.
*/
public Iterator<A> iterator() {
return new Iterator<A>() {
List<A> elems = ListBuffer.this.elems;
public boolean hasNext() {
return !elems.isEmpty();
}
public A next() {
if (elems.isEmpty())
throw new NoSuchElementException();
A elem = elems.head;
elems = elems.tail;
return elem;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public boolean add(A a) {
append(a);
return true;
}
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
public boolean containsAll(Collection<?> c) {
for (Object x: c) {
if (!contains(x))
return false;
}
return true;
}
public boolean addAll(Collection<? extends A> c) {
for (A a: c)
append(a);
return true;
}
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
public boolean offer(A a) {
append(a);
return true;
}
public A poll() {
return next();
}
public A peek() {
return first();
}
public A last() {
return last != null ? last.head : null;
}
}

View File

@@ -0,0 +1,738 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.io.*;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.api.DiagnosticFormatter;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
import static com.sun.tools.javac.main.Option.*;
/** A class for error logs. Reports errors and warnings, and
* keeps track of error numbers and positions.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Log extends AbstractLog {
/** The context key for the log. */
public static final Context.Key<Log> logKey
= new Context.Key<Log>();
/** The context key for the output PrintWriter. */
public static final Context.Key<PrintWriter> outKey =
new Context.Key<PrintWriter>();
/* TODO: Should unify this with prefix handling in JCDiagnostic.Factory. */
public enum PrefixKind {
JAVAC("javac."),
COMPILER_MISC("compiler.misc.");
PrefixKind(String v) {
value = v;
}
public String key(String k) {
return value + k;
}
final String value;
}
/**
* DiagnosticHandler's provide the initial handling for diagnostics.
* When a diagnostic handler is created and has been initialized, it
* should install itself as the current diagnostic handler. When a
* client has finished using a handler, the client should call
* {@code log.removeDiagnosticHandler();}
*
* Note that javax.tools.DiagnosticListener (if set) is called later in the
* diagnostic pipeline.
*/
public static abstract class DiagnosticHandler {
/**
* The previously installed diagnostic handler.
*/
protected DiagnosticHandler prev;
/**
* Install this diagnostic handler as the current one,
* recording the previous one.
*/
protected void install(Log log) {
prev = log.diagnosticHandler;
log.diagnosticHandler = this;
}
/**
* Handle a diagnostic.
*/
public abstract void report(JCDiagnostic diag);
}
/**
* A DiagnosticHandler that discards all diagnostics.
*/
public static class DiscardDiagnosticHandler extends DiagnosticHandler {
public DiscardDiagnosticHandler(Log log) {
install(log);
}
public void report(JCDiagnostic diag) { }
}
/**
* A DiagnosticHandler that can defer some or all diagnostics,
* by buffering them for later examination and/or reporting.
* If a diagnostic is not deferred, or is subsequently reported
* with reportAllDiagnostics(), it will be reported to the previously
* active diagnostic handler.
*/
public static class DeferredDiagnosticHandler extends DiagnosticHandler {
private Queue<JCDiagnostic> deferred = new ListBuffer<>();
private final Filter<JCDiagnostic> filter;
public DeferredDiagnosticHandler(Log log) {
this(log, null);
}
public DeferredDiagnosticHandler(Log log, Filter<JCDiagnostic> filter) {
this.filter = filter;
install(log);
}
public void report(JCDiagnostic diag) {
if (!diag.isFlagSet(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE) &&
(filter == null || filter.accepts(diag))) {
deferred.add(diag);
} else {
prev.report(diag);
}
}
public Queue<JCDiagnostic> getDiagnostics() {
return deferred;
}
/** Report all deferred diagnostics. */
public void reportDeferredDiagnostics() {
reportDeferredDiagnostics(EnumSet.allOf(JCDiagnostic.Kind.class));
}
/** Report selected deferred diagnostics. */
public void reportDeferredDiagnostics(Set<JCDiagnostic.Kind> kinds) {
JCDiagnostic d;
while ((d = deferred.poll()) != null) {
if (kinds.contains(d.getKind()))
prev.report(d);
}
deferred = null; // prevent accidental ongoing use
}
}
public enum WriterKind { NOTICE, WARNING, ERROR };
protected PrintWriter errWriter;
protected PrintWriter warnWriter;
protected PrintWriter noticeWriter;
/** The maximum number of errors/warnings that are reported.
*/
protected int MaxErrors;
protected int MaxWarnings;
/** Switch: prompt user on each error.
*/
public boolean promptOnError;
/** Switch: emit warning messages.
*/
public boolean emitWarnings;
/** Switch: suppress note messages.
*/
public boolean suppressNotes;
/** Print stack trace on errors?
*/
public boolean dumpOnError;
/** Print multiple errors for same source locations.
*/
public boolean multipleErrors;
/**
* Diagnostic listener, if provided through programmatic
* interface to javac (JSR 199).
*/
protected DiagnosticListener<? super JavaFileObject> diagListener;
/**
* Formatter for diagnostics.
*/
private DiagnosticFormatter<JCDiagnostic> diagFormatter;
/**
* Keys for expected diagnostics.
*/
public Set<String> expectDiagKeys;
/**
* Set to true if a compressed diagnostic is reported
*/
public boolean compressedOutput;
/**
* JavacMessages object used for localization.
*/
private JavacMessages messages;
/**
* Handler for initial dispatch of diagnostics.
*/
private DiagnosticHandler diagnosticHandler;
/** Construct a log with given I/O redirections.
*/
protected Log(Context context, PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter) {
super(JCDiagnostic.Factory.instance(context));
context.put(logKey, this);
this.errWriter = errWriter;
this.warnWriter = warnWriter;
this.noticeWriter = noticeWriter;
@SuppressWarnings("unchecked") // FIXME
DiagnosticListener<? super JavaFileObject> dl =
context.get(DiagnosticListener.class);
this.diagListener = dl;
diagnosticHandler = new DefaultDiagnosticHandler();
messages = JavacMessages.instance(context);
messages.add(Main.javacBundleName);
final Options options = Options.instance(context);
initOptions(options);
options.addListener(new Runnable() {
public void run() {
initOptions(options);
}
});
}
// where
private void initOptions(Options options) {
this.dumpOnError = options.isSet(DOE);
this.promptOnError = options.isSet(PROMPT);
this.emitWarnings = options.isUnset(XLINT_CUSTOM, "none");
this.suppressNotes = options.isSet("suppressNotes");
this.MaxErrors = getIntOption(options, XMAXERRS, getDefaultMaxErrors());
this.MaxWarnings = getIntOption(options, XMAXWARNS, getDefaultMaxWarnings());
boolean rawDiagnostics = options.isSet("rawDiagnostics");
this.diagFormatter = rawDiagnostics ? new RawDiagnosticFormatter(options) :
new BasicDiagnosticFormatter(options, messages);
String ek = options.get("expectKeys");
if (ek != null)
expectDiagKeys = new HashSet<String>(Arrays.asList(ek.split(", *")));
}
private int getIntOption(Options options, Option option, int defaultValue) {
String s = options.get(option);
try {
if (s != null) {
int n = Integer.parseInt(s);
return (n <= 0 ? Integer.MAX_VALUE : n);
}
} catch (NumberFormatException e) {
// silently ignore ill-formed numbers
}
return defaultValue;
}
/** Default value for -Xmaxerrs.
*/
protected int getDefaultMaxErrors() {
return 100;
}
/** Default value for -Xmaxwarns.
*/
protected int getDefaultMaxWarnings() {
return 100;
}
/** The default writer for diagnostics
*/
static PrintWriter defaultWriter(Context context) {
PrintWriter result = context.get(outKey);
if (result == null)
context.put(outKey, result = new PrintWriter(System.err));
return result;
}
/** Construct a log with default settings.
*/
protected Log(Context context) {
this(context, defaultWriter(context));
}
/** Construct a log with all output redirected.
*/
protected Log(Context context, PrintWriter defaultWriter) {
this(context, defaultWriter, defaultWriter, defaultWriter);
}
/** Get the Log instance for this context. */
public static Log instance(Context context) {
Log instance = context.get(logKey);
if (instance == null)
instance = new Log(context);
return instance;
}
/** The number of errors encountered so far.
*/
public int nerrors = 0;
/** The number of warnings encountered so far.
*/
public int nwarnings = 0;
/** A set of all errors generated so far. This is used to avoid printing an
* error message more than once. For each error, a pair consisting of the
* source file name and source code position of the error is added to the set.
*/
private Set<Pair<JavaFileObject, Integer>> recorded = new HashSet<Pair<JavaFileObject,Integer>>();
public boolean hasDiagnosticListener() {
return diagListener != null;
}
public void setEndPosTable(JavaFileObject name, EndPosTable endPosTable) {
name.getClass(); // null check
getSource(name).setEndPosTable(endPosTable);
}
/** Return current sourcefile.
*/
public JavaFileObject currentSourceFile() {
return source == null ? null : source.getFile();
}
/** Get the current diagnostic formatter.
*/
public DiagnosticFormatter<JCDiagnostic> getDiagnosticFormatter() {
return diagFormatter;
}
/** Set the current diagnostic formatter.
*/
public void setDiagnosticFormatter(DiagnosticFormatter<JCDiagnostic> diagFormatter) {
this.diagFormatter = diagFormatter;
}
public PrintWriter getWriter(WriterKind kind) {
switch (kind) {
case NOTICE: return noticeWriter;
case WARNING: return warnWriter;
case ERROR: return errWriter;
default: throw new IllegalArgumentException();
}
}
public void setWriter(WriterKind kind, PrintWriter pw) {
pw.getClass();
switch (kind) {
case NOTICE: noticeWriter = pw; break;
case WARNING: warnWriter = pw; break;
case ERROR: errWriter = pw; break;
default: throw new IllegalArgumentException();
}
}
public void setWriters(PrintWriter pw) {
pw.getClass();
noticeWriter = warnWriter = errWriter = pw;
}
/**
* Propagate the previous log's information.
*/
public void initRound(Log other) {
this.noticeWriter = other.noticeWriter;
this.warnWriter = other.warnWriter;
this.errWriter = other.errWriter;
this.sourceMap = other.sourceMap;
this.recorded = other.recorded;
this.nerrors = other.nerrors;
this.nwarnings = other.nwarnings;
}
/**
* Replace the specified diagnostic handler with the
* handler that was current at the time this handler was created.
* The given handler must be the currently installed handler;
* it must be specified explicitly for clarity and consistency checking.
*/
public void popDiagnosticHandler(DiagnosticHandler h) {
Assert.check(diagnosticHandler == h);
diagnosticHandler = h.prev;
}
/** Flush the logs
*/
public void flush() {
errWriter.flush();
warnWriter.flush();
noticeWriter.flush();
}
public void flush(WriterKind kind) {
getWriter(kind).flush();
}
/** Returns true if an error needs to be reported for a given
* source name and pos.
*/
protected boolean shouldReport(JavaFileObject file, int pos) {
if (multipleErrors || file == null)
return true;
Pair<JavaFileObject,Integer> coords = new Pair<JavaFileObject,Integer>(file, pos);
boolean shouldReport = !recorded.contains(coords);
if (shouldReport)
recorded.add(coords);
return shouldReport;
}
/** Prompt user after an error.
*/
public void prompt() {
if (promptOnError) {
System.err.println(localize("resume.abort"));
try {
while (true) {
switch (System.in.read()) {
case 'a': case 'A':
System.exit(-1);
return;
case 'r': case 'R':
return;
case 'x': case 'X':
throw new AssertionError("user abort");
default:
}
}
} catch (IOException e) {}
}
}
/** Print the faulty source code line and point to the error.
* @param pos Buffer index of the error position, must be on current line
*/
private void printErrLine(int pos, PrintWriter writer) {
String line = (source == null ? null : source.getLine(pos));
if (line == null)
return;
int col = source.getColumnNumber(pos, false);
printRawLines(writer, line);
for (int i = 0; i < col - 1; i++) {
writer.print((line.charAt(i) == '\t') ? "\t" : " ");
}
writer.println("^");
writer.flush();
}
public void printNewline() {
noticeWriter.println();
}
public void printNewline(WriterKind wk) {
getWriter(wk).println();
}
public void printLines(String key, Object... args) {
printRawLines(noticeWriter, localize(key, args));
}
public void printLines(PrefixKind pk, String key, Object... args) {
printRawLines(noticeWriter, localize(pk, key, args));
}
public void printLines(WriterKind wk, String key, Object... args) {
printRawLines(getWriter(wk), localize(key, args));
}
public void printLines(WriterKind wk, PrefixKind pk, String key, Object... args) {
printRawLines(getWriter(wk), localize(pk, key, args));
}
/** Print the text of a message, translating newlines appropriately
* for the platform.
*/
public void printRawLines(String msg) {
printRawLines(noticeWriter, msg);
}
/** Print the text of a message, translating newlines appropriately
* for the platform.
*/
public void printRawLines(WriterKind kind, String msg) {
printRawLines(getWriter(kind), msg);
}
/** Print the text of a message, translating newlines appropriately
* for the platform.
*/
public static void printRawLines(PrintWriter writer, String msg) {
int nl;
while ((nl = msg.indexOf('\n')) != -1) {
writer.println(msg.substring(0, nl));
msg = msg.substring(nl+1);
}
if (msg.length() != 0) writer.println(msg);
}
/**
* Print the localized text of a "verbose" message to the
* noticeWriter stream.
*/
public void printVerbose(String key, Object... args) {
printRawLines(noticeWriter, localize("verbose." + key, args));
}
protected void directError(String key, Object... args) {
printRawLines(errWriter, localize(key, args));
errWriter.flush();
}
/** Report a warning that cannot be suppressed.
* @param pos The source position at which to report the warning.
* @param key The key for the localized warning message.
* @param args Fields of the warning message.
*/
public void strictWarning(DiagnosticPosition pos, String key, Object ... args) {
writeDiagnostic(diags.warning(source, pos, key, args));
nwarnings++;
}
/**
* Primary method to report a diagnostic.
* @param diagnostic
*/
public void report(JCDiagnostic diagnostic) {
diagnosticHandler.report(diagnostic);
}
/**
* Common diagnostic handling.
* The diagnostic is counted, and depending on the options and how many diagnostics have been
* reported so far, the diagnostic may be handed off to writeDiagnostic.
*/
private class DefaultDiagnosticHandler extends DiagnosticHandler {
public void report(JCDiagnostic diagnostic) {
if (expectDiagKeys != null)
expectDiagKeys.remove(diagnostic.getCode());
switch (diagnostic.getType()) {
case FRAGMENT:
throw new IllegalArgumentException();
case NOTE:
// Print out notes only when we are permitted to report warnings
// Notes are only generated at the end of a compilation, so should be small
// in number.
if ((emitWarnings || diagnostic.isMandatory()) && !suppressNotes) {
writeDiagnostic(diagnostic);
}
break;
case WARNING:
if (emitWarnings || diagnostic.isMandatory()) {
if (nwarnings < MaxWarnings) {
writeDiagnostic(diagnostic);
nwarnings++;
}
}
break;
case ERROR:
if (nerrors < MaxErrors
&& shouldReport(diagnostic.getSource(), diagnostic.getIntPosition())) {
writeDiagnostic(diagnostic);
nerrors++;
}
break;
}
if (diagnostic.isFlagSet(JCDiagnostic.DiagnosticFlag.COMPRESSED)) {
compressedOutput = true;
}
}
}
/**
* Write out a diagnostic.
*/
protected void writeDiagnostic(JCDiagnostic diag) {
if (diagListener != null) {
diagListener.report(diag);
return;
}
PrintWriter writer = getWriterForDiagnosticType(diag.getType());
printRawLines(writer, diagFormatter.format(diag, messages.getCurrentLocale()));
if (promptOnError) {
switch (diag.getType()) {
case ERROR:
case WARNING:
prompt();
}
}
if (dumpOnError)
new RuntimeException().printStackTrace(writer);
writer.flush();
}
@Deprecated
protected PrintWriter getWriterForDiagnosticType(DiagnosticType dt) {
switch (dt) {
case FRAGMENT:
throw new IllegalArgumentException();
case NOTE:
return noticeWriter;
case WARNING:
return warnWriter;
case ERROR:
return errWriter;
default:
throw new Error();
}
}
/** Find a localized string in the resource bundle.
* Because this method is static, it ignores the locale.
* Use localize(key, args) when possible.
* @param key The key for the localized string.
* @param args Fields to substitute into the string.
*/
public static String getLocalizedString(String key, Object ... args) {
return JavacMessages.getDefaultLocalizedString(PrefixKind.COMPILER_MISC.key(key), args);
}
/** Find a localized string in the resource bundle.
* @param key The key for the localized string.
* @param args Fields to substitute into the string.
*/
public String localize(String key, Object... args) {
return localize(PrefixKind.COMPILER_MISC, key, args);
}
/** Find a localized string in the resource bundle.
* @param key The key for the localized string.
* @param args Fields to substitute into the string.
*/
public String localize(PrefixKind pk, String key, Object... args) {
if (useRawMessages)
return pk.key(key);
else
return messages.getLocalizedString(pk.key(key), args);
}
// where
// backdoor hook for testing, should transition to use -XDrawDiagnostics
private static boolean useRawMessages = false;
/***************************************************************************
* raw error messages without internationalization; used for experimentation
* and quick prototyping
***************************************************************************/
/** print an error or warning message:
*/
private void printRawError(int pos, String msg) {
if (source == null || pos == Position.NOPOS) {
printRawLines(errWriter, "error: " + msg);
} else {
int line = source.getLineNumber(pos);
JavaFileObject file = source.getFile();
if (file != null)
printRawLines(errWriter,
file.getName() + ":" +
line + ": " + msg);
printErrLine(pos, errWriter);
}
errWriter.flush();
}
/** report an error:
*/
public void rawError(int pos, String msg) {
if (nerrors < MaxErrors && shouldReport(currentSourceFile(), pos)) {
printRawError(pos, msg);
prompt();
nerrors++;
}
errWriter.flush();
}
/** report a warning:
*/
public void rawWarning(int pos, String msg) {
if (nwarnings < MaxWarnings && emitWarnings) {
printRawError(pos, "warning: " + msg);
}
prompt();
nwarnings++;
errWriter.flush();
}
public static String format(String fmt, Object... args) {
return String.format((java.util.Locale)null, fmt, args);
}
}

View File

@@ -0,0 +1,270 @@
/*
* Copyright (c) 2005, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.HashSet;
import java.util.Set;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
/**
* A handler to process mandatory warnings, setting up a deferred diagnostic
* to be printed at the end of the compilation if some warnings get suppressed
* because too many warnings have already been generated.
*
* Note that the SuppressWarnings annotation can be used to suppress warnings
* about conditions that would otherwise merit a warning. Such processing
* is done when the condition is detected, and in those cases, no call is
* made on any API to generate a warning at all. In consequence, this handler only
* gets to handle those warnings that JLS says must be generated.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class MandatoryWarningHandler {
/**
* The kinds of different deferred diagnostics that might be generated
* if a mandatory warning is suppressed because too many warnings have
* already been output.
*
* The parameter is a fragment used to build an I18N message key for Log.
*/
private enum DeferredDiagnosticKind {
/**
* This kind is used when a single specific file is found to have warnings
* and no similar warnings have already been given.
* It generates a message like:
* FILE has ISSUES
*/
IN_FILE(".filename"),
/**
* This kind is used when a single specific file is found to have warnings
* and when similar warnings have already been reported for the file.
* It generates a message like:
* FILE has additional ISSUES
*/
ADDITIONAL_IN_FILE(".filename.additional"),
/**
* This kind is used when multiple files have been found to have warnings,
* and none of them have had any similar warnings.
* It generates a message like:
* Some files have ISSUES
*/
IN_FILES(".plural"),
/**
* This kind is used when multiple files have been found to have warnings,
* and some of them have had already had specific similar warnings.
* It generates a message like:
* Some files have additional ISSUES
*/
ADDITIONAL_IN_FILES(".plural.additional");
DeferredDiagnosticKind(String v) { value = v; }
String getKey(String prefix) { return prefix + value; }
private final String value;
}
/**
* Create a handler for mandatory warnings.
* @param log The log on which to generate any diagnostics
* @param verbose Specify whether or not detailed messages about
* individual instances should be given, or whether an aggregate
* message should be generated at the end of the compilation.
* Typically set via -Xlint:option.
* @param enforceMandatory
* True if mandatory warnings and notes are being enforced.
* @param prefix A common prefix for the set of message keys for
* the messages that may be generated.
* @param lc An associated lint category for the warnings, or null if none.
*/
public MandatoryWarningHandler(Log log, boolean verbose,
boolean enforceMandatory, String prefix,
LintCategory lc) {
this.log = log;
this.verbose = verbose;
this.prefix = prefix;
this.enforceMandatory = enforceMandatory;
this.lintCategory = lc;
}
/**
* Report a mandatory warning.
*/
public void report(DiagnosticPosition pos, String msg, Object... args) {
JavaFileObject currentSource = log.currentSourceFile();
if (verbose) {
if (sourcesWithReportedWarnings == null)
sourcesWithReportedWarnings = new HashSet<JavaFileObject>();
if (log.nwarnings < log.MaxWarnings) {
// generate message and remember the source file
logMandatoryWarning(pos, msg, args);
sourcesWithReportedWarnings.add(currentSource);
} else if (deferredDiagnosticKind == null) {
// set up deferred message
if (sourcesWithReportedWarnings.contains(currentSource)) {
// more errors in a file that already has reported warnings
deferredDiagnosticKind = DeferredDiagnosticKind.ADDITIONAL_IN_FILE;
} else {
// warnings in a new source file
deferredDiagnosticKind = DeferredDiagnosticKind.IN_FILE;
}
deferredDiagnosticSource = currentSource;
deferredDiagnosticArg = currentSource;
} else if ((deferredDiagnosticKind == DeferredDiagnosticKind.IN_FILE
|| deferredDiagnosticKind == DeferredDiagnosticKind.ADDITIONAL_IN_FILE)
&& !equal(deferredDiagnosticSource, currentSource)) {
// additional errors in more than one source file
deferredDiagnosticKind = DeferredDiagnosticKind.ADDITIONAL_IN_FILES;
deferredDiagnosticArg = null;
}
} else {
if (deferredDiagnosticKind == null) {
// warnings in a single source
deferredDiagnosticKind = DeferredDiagnosticKind.IN_FILE;
deferredDiagnosticSource = currentSource;
deferredDiagnosticArg = currentSource;
} else if (deferredDiagnosticKind == DeferredDiagnosticKind.IN_FILE &&
!equal(deferredDiagnosticSource, currentSource)) {
// warnings in multiple source files
deferredDiagnosticKind = DeferredDiagnosticKind.IN_FILES;
deferredDiagnosticArg = null;
}
}
}
/**
* Report any diagnostic that might have been deferred by previous calls of report().
*/
public void reportDeferredDiagnostic() {
if (deferredDiagnosticKind != null) {
if (deferredDiagnosticArg == null)
logMandatoryNote(deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix));
else
logMandatoryNote(deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix), deferredDiagnosticArg);
if (!verbose)
logMandatoryNote(deferredDiagnosticSource, prefix + ".recompile");
}
}
/**
* Check two objects, each possibly null, are either both null or are equal.
*/
private static boolean equal(Object o1, Object o2) {
return ((o1 == null || o2 == null) ? (o1 == o2) : o1.equals(o2));
}
/**
* The log to which to report warnings.
*/
private Log log;
/**
* Whether or not to report individual warnings, or simply to report a
* single aggregate warning at the end of the compilation.
*/
private boolean verbose;
/**
* The common prefix for all I18N message keys generated by this handler.
*/
private String prefix;
/**
* A set containing the names of the source files for which specific
* warnings have been generated -- i.e. in verbose mode. If a source name
* appears in this list, then deferred diagnostics will be phrased to
* include "additionally"...
*/
private Set<JavaFileObject> sourcesWithReportedWarnings;
/**
* A variable indicating the latest best guess at what the final
* deferred diagnostic will be. Initially as specific and helpful
* as possible, as more warnings are reported, the scope of the
* diagnostic will be broadened.
*/
private DeferredDiagnosticKind deferredDiagnosticKind;
/**
* If deferredDiagnosticKind is IN_FILE or ADDITIONAL_IN_FILE, this variable
* gives the value of log.currentSource() for the file in question.
*/
private JavaFileObject deferredDiagnosticSource;
/**
* An optional argument to be used when constructing the
* deferred diagnostic message, based on deferredDiagnosticKind.
* This variable should normally be set/updated whenever
* deferredDiagnosticKind is updated.
*/
private Object deferredDiagnosticArg;
/**
* True if mandatory warnings and notes are being enforced.
*/
private final boolean enforceMandatory;
/**
* A LintCategory to be included in point-of-use diagnostics to indicate
* how messages might be suppressed (i.e. with @SuppressWarnings).
*/
private final LintCategory lintCategory;
/**
* Reports a mandatory warning to the log. If mandatory warnings
* are not being enforced, treat this as an ordinary warning.
*/
private void logMandatoryWarning(DiagnosticPosition pos, String msg,
Object... args) {
// Note: the following log methods are safe if lintCategory is null.
if (enforceMandatory)
log.mandatoryWarning(lintCategory, pos, msg, args);
else
log.warning(lintCategory, pos, msg, args);
}
/**
* Reports a mandatory note to the log. If mandatory notes are
* not being enforced, treat this as an ordinary note.
*/
private void logMandatoryNote(JavaFileObject file, String msg, Object... args) {
if (enforceMandatory)
log.mandatoryNote(file, msg, args);
else
log.note(file, msg, args);
}
}

View File

@@ -0,0 +1,247 @@
/*
* Copyright (c) 1999, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/** An abstraction for internal compiler strings. They are stored in
* Utf8 format. Names are stored in a Name.Table, and are unique within
* that table.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public abstract class Name implements javax.lang.model.element.Name {
public final Table table;
protected Name(Table table) {
this.table = table;
}
/**
* {@inheritDoc}
*/
public boolean contentEquals(CharSequence cs) {
return toString().equals(cs.toString());
}
/**
* {@inheritDoc}
*/
public int length() {
return toString().length();
}
/**
* {@inheritDoc}
*/
public char charAt(int index) {
return toString().charAt(index);
}
/**
* {@inheritDoc}
*/
public CharSequence subSequence(int start, int end) {
return toString().subSequence(start, end);
}
/** Return the concatenation of this name and name `n'.
*/
public Name append(Name n) {
int len = getByteLength();
byte[] bs = new byte[len + n.getByteLength()];
getBytes(bs, 0);
n.getBytes(bs, len);
return table.fromUtf(bs, 0, bs.length);
}
/** Return the concatenation of this name, the given ASCII
* character, and name `n'.
*/
public Name append(char c, Name n) {
int len = getByteLength();
byte[] bs = new byte[len + 1 + n.getByteLength()];
getBytes(bs, 0);
bs[len] = (byte) c;
n.getBytes(bs, len+1);
return table.fromUtf(bs, 0, bs.length);
}
/** An arbitrary but consistent complete order among all Names.
*/
public int compareTo(Name other) {
return other.getIndex() - this.getIndex();
}
/** Return true if this is the empty name.
*/
public boolean isEmpty() {
return getByteLength() == 0;
}
/** Returns last occurrence of byte b in this name, -1 if not found.
*/
public int lastIndexOf(byte b) {
byte[] bytes = getByteArray();
int offset = getByteOffset();
int i = getByteLength() - 1;
while (i >= 0 && bytes[offset + i] != b) i--;
return i;
}
/** Does this name start with prefix?
*/
public boolean startsWith(Name prefix) {
byte[] thisBytes = this.getByteArray();
int thisOffset = this.getByteOffset();
int thisLength = this.getByteLength();
byte[] prefixBytes = prefix.getByteArray();
int prefixOffset = prefix.getByteOffset();
int prefixLength = prefix.getByteLength();
int i = 0;
while (i < prefixLength &&
i < thisLength &&
thisBytes[thisOffset + i] == prefixBytes[prefixOffset + i])
i++;
return i == prefixLength;
}
/** Returns the sub-name starting at position start, up to and
* excluding position end.
*/
public Name subName(int start, int end) {
if (end < start) end = start;
return table.fromUtf(getByteArray(), getByteOffset() + start, end - start);
}
/** Return the string representation of this name.
*/
@Override
public String toString() {
return Convert.utf2string(getByteArray(), getByteOffset(), getByteLength());
}
/** Return the Utf8 representation of this name.
*/
public byte[] toUtf() {
byte[] bs = new byte[getByteLength()];
getBytes(bs, 0);
return bs;
}
/* Get a "reasonably small" value that uniquely identifies this name
* within its name table.
*/
public abstract int getIndex();
/** Get the length (in bytes) of this name.
*/
public abstract int getByteLength();
/** Returns i'th byte of this name.
*/
public abstract byte getByteAt(int i);
/** Copy all bytes of this name to buffer cs, starting at start.
*/
public void getBytes(byte cs[], int start) {
System.arraycopy(getByteArray(), getByteOffset(), cs, start, getByteLength());
}
/** Get the underlying byte array for this name. The contents of the
* array must not be modified.
*/
public abstract byte[] getByteArray();
/** Get the start offset of this name within its byte array.
*/
public abstract int getByteOffset();
/** An abstraction for the hash table used to create unique Name instances.
*/
public static abstract class Table {
/** Standard name table.
*/
public final Names names;
Table(Names names) {
this.names = names;
}
/** Get the name from the characters in cs[start..start+len-1].
*/
public abstract Name fromChars(char[] cs, int start, int len);
/** Get the name for the characters in string s.
*/
public Name fromString(String s) {
char[] cs = s.toCharArray();
return fromChars(cs, 0, cs.length);
}
/** Get the name for the bytes in array cs.
* Assume that bytes are in utf8 format.
*/
public Name fromUtf(byte[] cs) {
return fromUtf(cs, 0, cs.length);
}
/** get the name for the bytes in cs[start..start+len-1].
* Assume that bytes are in utf8 format.
*/
public abstract Name fromUtf(byte[] cs, int start, int len);
/** Release any resources used by this table.
*/
public abstract void dispose();
/** The hashcode of a name.
*/
protected static int hashValue(byte bytes[], int offset, int length) {
int h = 0;
int off = offset;
for (int i = 0; i < length; i++) {
h = (h << 5) - h + bytes[off++];
}
return h;
}
/** Compare two subarrays
*/
protected static boolean equals(byte[] bytes1, int offset1,
byte[] bytes2, int offset2, int length) {
int i = 0;
while (i < length && bytes1[offset1 + i] == bytes2[offset2 + i]) {
i++;
}
return i == length;
}
}
}

View File

@@ -0,0 +1,346 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/**
* Access to the compiler's name table. STandard names are defined,
* as well as methods to create new names.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Names {
public static final Context.Key<Names> namesKey = new Context.Key<Names>();
public static Names instance(Context context) {
Names instance = context.get(namesKey);
if (instance == null) {
instance = new Names(context);
context.put(namesKey, instance);
}
return instance;
}
// operators and punctuation
public final Name asterisk;
public final Name comma;
public final Name empty;
public final Name hyphen;
public final Name one;
public final Name period;
public final Name semicolon;
public final Name slash;
public final Name slashequals;
// keywords
public final Name _class;
public final Name _default;
public final Name _super;
public final Name _this;
// field and method names
public final Name _name;
public final Name addSuppressed;
public final Name any;
public final Name append;
public final Name clinit;
public final Name clone;
public final Name close;
public final Name compareTo;
public final Name deserializeLambda;
public final Name desiredAssertionStatus;
public final Name equals;
public final Name error;
public final Name family;
public final Name finalize;
public final Name forName;
public final Name getClass;
public final Name getClassLoader;
public final Name getComponentType;
public final Name getDeclaringClass;
public final Name getMessage;
public final Name hasNext;
public final Name hashCode;
public final Name init;
public final Name initCause;
public final Name iterator;
public final Name length;
public final Name next;
public final Name ordinal;
public final Name serialVersionUID;
public final Name toString;
public final Name value;
public final Name valueOf;
public final Name values;
// class names
public final Name java_io_Serializable;
public final Name java_lang_AutoCloseable;
public final Name java_lang_Class;
public final Name java_lang_Cloneable;
public final Name java_lang_Enum;
public final Name java_lang_Object;
public final Name java_lang_invoke_MethodHandle;
// names of builtin classes
public final Name Array;
public final Name Bound;
public final Name Method;
// package names
public final Name java_lang;
// attribute names
public final Name Annotation;
public final Name AnnotationDefault;
public final Name BootstrapMethods;
public final Name Bridge;
public final Name CharacterRangeTable;
public final Name Code;
public final Name CompilationID;
public final Name ConstantValue;
public final Name Deprecated;
public final Name EnclosingMethod;
public final Name Enum;
public final Name Exceptions;
public final Name InnerClasses;
public final Name LineNumberTable;
public final Name LocalVariableTable;
public final Name LocalVariableTypeTable;
public final Name MethodParameters;
public final Name RuntimeInvisibleAnnotations;
public final Name RuntimeInvisibleParameterAnnotations;
public final Name RuntimeInvisibleTypeAnnotations;
public final Name RuntimeVisibleAnnotations;
public final Name RuntimeVisibleParameterAnnotations;
public final Name RuntimeVisibleTypeAnnotations;
public final Name Signature;
public final Name SourceFile;
public final Name SourceID;
public final Name StackMap;
public final Name StackMapTable;
public final Name Synthetic;
public final Name Value;
public final Name Varargs;
// members of java.lang.annotation.ElementType
public final Name ANNOTATION_TYPE;
public final Name CONSTRUCTOR;
public final Name FIELD;
public final Name LOCAL_VARIABLE;
public final Name METHOD;
public final Name PACKAGE;
public final Name PARAMETER;
public final Name TYPE;
public final Name TYPE_PARAMETER;
public final Name TYPE_USE;
// members of java.lang.annotation.RetentionPolicy
public final Name CLASS;
public final Name RUNTIME;
public final Name SOURCE;
// other identifiers
public final Name T;
public final Name deprecated;
public final Name ex;
public final Name package_info;
//lambda-related
public final Name lambda;
public final Name metafactory;
public final Name altMetafactory;
public final Name dollarThis;
public final Name.Table table;
public Names(Context context) {
Options options = Options.instance(context);
table = createTable(options);
// operators and punctuation
asterisk = fromString("*");
comma = fromString(",");
empty = fromString("");
hyphen = fromString("-");
one = fromString("1");
period = fromString(".");
semicolon = fromString(";");
slash = fromString("/");
slashequals = fromString("/=");
// keywords
_class = fromString("class");
_default = fromString("default");
_super = fromString("super");
_this = fromString("this");
// field and method names
_name = fromString("name");
addSuppressed = fromString("addSuppressed");
any = fromString("<any>");
append = fromString("append");
clinit = fromString("<clinit>");
clone = fromString("clone");
close = fromString("close");
compareTo = fromString("compareTo");
deserializeLambda = fromString("$deserializeLambda$");
desiredAssertionStatus = fromString("desiredAssertionStatus");
equals = fromString("equals");
error = fromString("<error>");
family = fromString("family");
finalize = fromString("finalize");
forName = fromString("forName");
getClass = fromString("getClass");
getClassLoader = fromString("getClassLoader");
getComponentType = fromString("getComponentType");
getDeclaringClass = fromString("getDeclaringClass");
getMessage = fromString("getMessage");
hasNext = fromString("hasNext");
hashCode = fromString("hashCode");
init = fromString("<init>");
initCause = fromString("initCause");
iterator = fromString("iterator");
length = fromString("length");
next = fromString("next");
ordinal = fromString("ordinal");
serialVersionUID = fromString("serialVersionUID");
toString = fromString("toString");
value = fromString("value");
valueOf = fromString("valueOf");
values = fromString("values");
dollarThis = fromString("$this");
// class names
java_io_Serializable = fromString("java.io.Serializable");
java_lang_AutoCloseable = fromString("java.lang.AutoCloseable");
java_lang_Class = fromString("java.lang.Class");
java_lang_Cloneable = fromString("java.lang.Cloneable");
java_lang_Enum = fromString("java.lang.Enum");
java_lang_Object = fromString("java.lang.Object");
java_lang_invoke_MethodHandle = fromString("java.lang.invoke.MethodHandle");
// names of builtin classes
Array = fromString("Array");
Bound = fromString("Bound");
Method = fromString("Method");
// package names
java_lang = fromString("java.lang");
// attribute names
Annotation = fromString("Annotation");
AnnotationDefault = fromString("AnnotationDefault");
BootstrapMethods = fromString("BootstrapMethods");
Bridge = fromString("Bridge");
CharacterRangeTable = fromString("CharacterRangeTable");
Code = fromString("Code");
CompilationID = fromString("CompilationID");
ConstantValue = fromString("ConstantValue");
Deprecated = fromString("Deprecated");
EnclosingMethod = fromString("EnclosingMethod");
Enum = fromString("Enum");
Exceptions = fromString("Exceptions");
InnerClasses = fromString("InnerClasses");
LineNumberTable = fromString("LineNumberTable");
LocalVariableTable = fromString("LocalVariableTable");
LocalVariableTypeTable = fromString("LocalVariableTypeTable");
MethodParameters = fromString("MethodParameters");
RuntimeInvisibleAnnotations = fromString("RuntimeInvisibleAnnotations");
RuntimeInvisibleParameterAnnotations = fromString("RuntimeInvisibleParameterAnnotations");
RuntimeInvisibleTypeAnnotations = fromString("RuntimeInvisibleTypeAnnotations");
RuntimeVisibleAnnotations = fromString("RuntimeVisibleAnnotations");
RuntimeVisibleParameterAnnotations = fromString("RuntimeVisibleParameterAnnotations");
RuntimeVisibleTypeAnnotations = fromString("RuntimeVisibleTypeAnnotations");
Signature = fromString("Signature");
SourceFile = fromString("SourceFile");
SourceID = fromString("SourceID");
StackMap = fromString("StackMap");
StackMapTable = fromString("StackMapTable");
Synthetic = fromString("Synthetic");
Value = fromString("Value");
Varargs = fromString("Varargs");
// members of java.lang.annotation.ElementType
ANNOTATION_TYPE = fromString("ANNOTATION_TYPE");
CONSTRUCTOR = fromString("CONSTRUCTOR");
FIELD = fromString("FIELD");
LOCAL_VARIABLE = fromString("LOCAL_VARIABLE");
METHOD = fromString("METHOD");
PACKAGE = fromString("PACKAGE");
PARAMETER = fromString("PARAMETER");
TYPE = fromString("TYPE");
TYPE_PARAMETER = fromString("TYPE_PARAMETER");
TYPE_USE = fromString("TYPE_USE");
// members of java.lang.annotation.RetentionPolicy
CLASS = fromString("CLASS");
RUNTIME = fromString("RUNTIME");
SOURCE = fromString("SOURCE");
// other identifiers
T = fromString("T");
deprecated = fromString("deprecated");
ex = fromString("ex");
package_info = fromString("package-info");
//lambda-related
lambda = fromString("lambda$");
metafactory = fromString("metafactory");
altMetafactory = fromString("altMetafactory");
}
protected Name.Table createTable(Options options) {
boolean useUnsharedTable = options.isSet("useUnsharedTable");
if (useUnsharedTable)
return new UnsharedNameTable(this);
else
return new SharedNameTable(this);
}
public void dispose() {
table.dispose();
}
public Name fromChars(char[] cs, int start, int len) {
return table.fromChars(cs, start, len);
}
public Name fromString(String s) {
return table.fromString(s);
}
public Name fromUtf(byte[] cs) {
return table.fromUtf(cs);
}
public Name fromUtf(byte[] cs, int start, int len) {
return table.fromUtf(cs, start, len);
}
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2001, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.*;
import com.sun.tools.javac.main.Option;
import static com.sun.tools.javac.main.Option.*;
/** A table of all command-line options.
* If an option has an argument, the option name is mapped to the argument.
* If a set option has no argument, it is mapped to itself.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Options {
private static final long serialVersionUID = 0;
/** The context key for the options. */
public static final Context.Key<Options> optionsKey =
new Context.Key<Options>();
private LinkedHashMap<String,String> values;
/** Get the Options instance for this context. */
public static Options instance(Context context) {
Options instance = context.get(optionsKey);
if (instance == null)
instance = new Options(context);
return instance;
}
protected Options(Context context) {
// DEBUGGING -- Use LinkedHashMap for reproducability
values = new LinkedHashMap<String,String>();
context.put(optionsKey, this);
}
/**
* Get the value for an undocumented option.
*/
public String get(String name) {
return values.get(name);
}
/**
* Get the value for an option.
*/
public String get(Option option) {
return values.get(option.text);
}
/**
* Get the boolean value for an option, patterned after Boolean.getBoolean,
* essentially will return true, iff the value exists and is set to "true".
*/
public boolean getBoolean(String name) {
return getBoolean(name, false);
}
/**
* Get the boolean with a default value if the option is not set.
*/
public boolean getBoolean(String name, boolean defaultValue) {
String value = get(name);
return (value == null) ? defaultValue : Boolean.parseBoolean(value);
}
/**
* Check if the value for an undocumented option has been set.
*/
public boolean isSet(String name) {
return (values.get(name) != null);
}
/**
* Check if the value for an option has been set.
*/
public boolean isSet(Option option) {
return (values.get(option.text) != null);
}
/**
* Check if the value for a choice option has been set to a specific value.
*/
public boolean isSet(Option option, String value) {
return (values.get(option.text + value) != null);
}
/**
* Check if the value for an undocumented option has not been set.
*/
public boolean isUnset(String name) {
return (values.get(name) == null);
}
/**
* Check if the value for an option has not been set.
*/
public boolean isUnset(Option option) {
return (values.get(option.text) == null);
}
/**
* Check if the value for a choice option has not been set to a specific value.
*/
public boolean isUnset(Option option, String value) {
return (values.get(option.text + value) == null);
}
public void put(String name, String value) {
values.put(name, value);
}
public void put(Option option, String value) {
values.put(option.text, value);
}
public void putAll(Options options) {
values.putAll(options.values);
}
public void remove(String name) {
values.remove(name);
}
public Set<String> keySet() {
return values.keySet();
}
public int size() {
return values.size();
}
// light-weight notification mechanism
private List<Runnable> listeners = List.nil();
public void addListener(Runnable listener) {
listeners = listeners.prepend(listener);
}
public void notifyListeners() {
for (Runnable r: listeners)
r.run();
}
/** Check for a lint suboption. */
public boolean lint(String s) {
// return true if either the specific option is enabled, or
// they are all enabled without the specific one being
// disabled
return
isSet(XLINT_CUSTOM, s) ||
(isSet(XLINT) || isSet(XLINT_CUSTOM, "all")) &&
isUnset(XLINT_CUSTOM, "-" + s);
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.Objects;
/** A generic class for pairs.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Pair<A, B> {
public final A fst;
public final B snd;
public Pair(A fst, B snd) {
this.fst = fst;
this.snd = snd;
}
public String toString() {
return "Pair[" + fst + "," + snd + "]";
}
public boolean equals(Object other) {
return
other instanceof Pair<?,?> &&
Objects.equals(fst, ((Pair<?,?>)other).fst) &&
Objects.equals(snd, ((Pair<?,?>)other).snd);
}
public int hashCode() {
if (fst == null) return (snd == null) ? 0 : snd.hashCode() + 1;
else if (snd == null) return fst.hashCode() + 2;
else return fst.hashCode() * 17 + snd.hashCode();
}
public static <A,B> Pair<A,B> of(A a, B b) {
return new Pair<A,B>(a,b);
}
}

View File

@@ -0,0 +1,282 @@
/*
* Copyright (c) 1999, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.BitSet;
import static com.sun.tools.javac.util.LayoutCharacters.*;
/** A class that defines source code positions as simple character
* offsets from the beginning of the file. The first character
* is at position 0.
*
* Support is also provided for (line,column) coordinates, but tab
* expansion is optional and no Unicode excape translation is considered.
* The first character is at location (1,1).
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Position {
public static final int NOPOS = -1;
public static final int FIRSTPOS = 0;
public static final int FIRSTLINE = 1;
public static final int FIRSTCOLUMN = 1;
public static final int LINESHIFT = 10;
public static final int MAXCOLUMN = (1<<LINESHIFT) - 1;
public static final int MAXLINE = (1<<(Integer.SIZE-LINESHIFT)) - 1;
public static final int MAXPOS = Integer.MAX_VALUE;
/**
* This is class is not supposed to be instantiated.
*/
private Position() {}
/** A two-way map between line/column numbers and positions,
* derived from a scan done at creation time. Tab expansion is
* optionally supported via a character map. Text content
* is not retained.
*<p>
* Notes: The first character position FIRSTPOS is at
* (FIRSTLINE,FIRSTCOLUMN). No account is taken of Unicode escapes.
*
* @param src Source characters
* @param max Number of characters to read
* @param expandTabs If true, expand tabs when calculating columns
*/
public static LineMap makeLineMap(char[] src, int max, boolean expandTabs) {
LineMapImpl lineMap = expandTabs ?
new LineTabMapImpl(max) : new LineMapImpl();
lineMap.build(src, max);
return lineMap;
}
/** Encode line and column numbers in an integer as:
* {@code line-number << LINESHIFT + column-number }.
* {@link Position#NOPOS} represents an undefined position.
*
* @param line number of line (first is 1)
* @param col number of character on line (first is 1)
* @return an encoded position or {@link Position#NOPOS}
* if the line or column number is too big to
* represent in the encoded format
* @throws IllegalArgumentException if line or col is less than 1
*/
public static int encodePosition(int line, int col) {
if (line < 1)
throw new IllegalArgumentException("line must be greater than 0");
if (col < 1)
throw new IllegalArgumentException("column must be greater than 0");
if (line > MAXLINE || col > MAXCOLUMN) {
return NOPOS;
}
return (line << LINESHIFT) + col;
}
public static interface LineMap extends com.sun.source.tree.LineMap {
/** Find the start position of a line.
*
* @param line number of line (first is 1)
* @return position of first character in line
* @throws ArrayIndexOutOfBoundsException
* if {@code lineNumber < 1}
* if {@code lineNumber > no. of lines}
*/
int getStartPosition(int line);
/** Find the position corresponding to a (line,column).
*
* @param line number of line (first is 1)
* @param column number of character on line (first is 1)
*
* @return position of character
* @throws ArrayIndexOutOfBoundsException
* if {@code line < 1}
* if {@code line > no. of lines}
*/
int getPosition(int line, int column);
/** Find the line containing a position; a line termination
* character is on the line it terminates.
*
* @param pos character offset of the position
* @return the line number on which pos occurs (first line is 1)
*/
int getLineNumber(int pos);
/** Find the column for a character position.
* Note: this method does not handle tab expansion.
* If tab expansion is needed, use a LineTabMap instead.
*
* @param pos character offset of the position
* @return the column number at which pos occurs
*/
int getColumnNumber(int pos);
}
static class LineMapImpl implements LineMap {
protected int[] startPosition; // start position of each line
protected LineMapImpl() {}
protected void build(char[] src, int max) {
int c = 0;
int i = 0;
int[] linebuf = new int[max];
while (i < max) {
linebuf[c++] = i;
do {
char ch = src[i];
if (ch == '\r' || ch == '\n') {
if (ch == '\r' && (i+1) < max && src[i+1] == '\n')
i += 2;
else
++i;
break;
}
else if (ch == '\t')
setTabPosition(i);
} while (++i < max);
}
this.startPosition = new int[c];
System.arraycopy(linebuf, 0, startPosition, 0, c);
}
public int getStartPosition(int line) {
return startPosition[line - FIRSTLINE];
}
public long getStartPosition(long line) {
return getStartPosition(longToInt(line));
}
public int getPosition(int line, int column) {
return startPosition[line - FIRSTLINE] + column - FIRSTCOLUMN;
}
public long getPosition(long line, long column) {
return getPosition(longToInt(line), longToInt(column));
}
// Cache of last line number lookup
private int lastPosition = Position.FIRSTPOS;
private int lastLine = Position.FIRSTLINE;
public int getLineNumber(int pos) {
if (pos == lastPosition) {
return lastLine;
}
lastPosition = pos;
int low = 0;
int high = startPosition.length-1;
while (low <= high) {
int mid = (low + high) >> 1;
int midVal = startPosition[mid];
if (midVal < pos)
low = mid + 1;
else if (midVal > pos)
high = mid - 1;
else {
lastLine = mid + 1; // pos is at beginning of this line
return lastLine;
}
}
lastLine = low;
return lastLine; // pos is on this line
}
public long getLineNumber(long pos) {
return getLineNumber(longToInt(pos));
}
public int getColumnNumber(int pos) {
return pos - startPosition[getLineNumber(pos) - FIRSTLINE] + FIRSTCOLUMN;
}
public long getColumnNumber(long pos) {
return getColumnNumber(longToInt(pos));
}
private static int longToInt(long longValue) {
int intValue = (int)longValue;
if (intValue != longValue)
throw new IndexOutOfBoundsException();
return intValue;
}
protected void setTabPosition(int offset) {}
}
/**
* A LineMap that handles tab expansion correctly. The cost is
* an additional bit per character in the source array.
*/
public static class LineTabMapImpl extends LineMapImpl {
private BitSet tabMap; // bits set for tab positions.
public LineTabMapImpl(int max) {
super();
tabMap = new BitSet(max);
}
protected void setTabPosition(int offset) {
tabMap.set(offset);
}
public int getColumnNumber(int pos) {
int lineStart = startPosition[getLineNumber(pos) - FIRSTLINE];
int column = 0;
for (int bp = lineStart; bp < pos; bp++) {
if (tabMap.get(bp))
column = (column / TabInc * TabInc) + TabInc;
else
column++;
}
return column + FIRSTCOLUMN;
}
public int getPosition(int line, int column) {
int pos = startPosition[line - FIRSTLINE];
column -= FIRSTCOLUMN;
int col = 0;
while (col < column) {
pos++;
if (tabMap.get(pos))
col = (col / TabInc * TabInc) + TabInc;
else
col++;
}
return pos;
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2006, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
/**
* Used to propagate exceptions through to the user.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*
* @author Peter von der Ah\u00e9
*/
public class PropagatedException extends RuntimeException {
static final long serialVersionUID = -6065309339888775367L;
public PropagatedException(RuntimeException cause) {
super(cause);
}
@Override
public RuntimeException getCause() {
return (RuntimeException)super.getCause();
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) 2008, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Locale;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.*;
import com.sun.tools.javac.api.Formattable;
import com.sun.tools.javac.file.BaseFileObject;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*;
/**
* A raw formatter for diagnostic messages.
* The raw formatter will format a diagnostic according to one of two format patterns, depending on whether
* or not the source name and position are set. This formatter provides a standardized, localize-independent
* implementation of a diagnostic formatter; as such, this formatter is best suited for testing purposes.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public final class RawDiagnosticFormatter extends AbstractDiagnosticFormatter {
/**
* Create a formatter based on the supplied options.
* @param options
*/
public RawDiagnosticFormatter(Options options) {
super(null, new SimpleConfiguration(options,
EnumSet.of(DiagnosticPart.SUMMARY,
DiagnosticPart.DETAILS,
DiagnosticPart.SUBDIAGNOSTICS)));
}
//provide common default formats
public String formatDiagnostic(JCDiagnostic d, Locale l) {
try {
StringBuilder buf = new StringBuilder();
if (d.getPosition() != Position.NOPOS) {
buf.append(formatSource(d, false, null));
buf.append(':');
buf.append(formatPosition(d, LINE, null));
buf.append(':');
buf.append(formatPosition(d, COLUMN, null));
buf.append(':');
}
else if (d.getSource() != null && d.getSource().getKind() == JavaFileObject.Kind.CLASS) {
buf.append(formatSource(d, false, null));
buf.append(":-:-:");
}
else
buf.append('-');
buf.append(' ');
buf.append(formatMessage(d, null));
if (displaySource(d)) {
buf.append("\n");
buf.append(formatSourceLine(d, 0));
}
return buf.toString();
}
catch (Exception e) {
//e.printStackTrace();
return null;
}
}
public String formatMessage(JCDiagnostic d, Locale l) {
StringBuilder buf = new StringBuilder();
Collection<String> args = formatArguments(d, l);
buf.append(localize(null, d.getCode(), args.toArray()));
if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) {
List<String> subDiags = formatSubdiagnostics(d, null);
if (subDiags.nonEmpty()) {
String sep = "";
buf.append(",{");
for (String sub : formatSubdiagnostics(d, null)) {
buf.append(sep);
buf.append("(");
buf.append(sub);
buf.append(")");
sep = ",";
}
buf.append('}');
}
}
return buf.toString();
}
@Override
protected String formatArgument(JCDiagnostic diag, Object arg, Locale l) {
String s;
if (arg instanceof Formattable) {
s = arg.toString();
} else if (arg instanceof JCExpression) {
JCExpression tree = (JCExpression)arg;
s = "@" + tree.getStartPosition();
} else if (arg instanceof BaseFileObject) {
s = ((BaseFileObject) arg).getShortName();
} else {
s = super.formatArgument(diag, arg, null);
}
return (arg instanceof JCDiagnostic) ? "(" + s + ")" : s;
}
@Override
protected String localize(Locale l, String key, Object... args) {
StringBuilder buf = new StringBuilder();
buf.append(key);
String sep = ": ";
for (Object o : args) {
buf.append(sep);
buf.append(o);
sep = ", ";
}
return buf.toString();
}
@Override
public boolean isRaw() {
return true;
}
}

View File

@@ -0,0 +1,710 @@
/*
* Copyright (c) 2009, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javac.code.Printer;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Types;
import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.util.LayoutCharacters.*;
import static com.sun.tools.javac.util.RichDiagnosticFormatter.RichConfiguration.*;
/**
* A rich diagnostic formatter is a formatter that provides better integration
* with javac's type system. A diagostic is first preprocessed in order to keep
* track of each types/symbols in it; after these informations are collected,
* the diagnostic is rendered using a standard formatter, whose type/symbol printer
* has been replaced by a more refined version provided by this rich formatter.
* The rich formatter currently enables three different features: (i) simple class
* names - that is class names are displayed used a non qualified name (thus
* omitting package info) whenever possible - (ii) where clause list - a list of
* additional subdiagnostics that provide specific info about type-variables,
* captured types, intersection types that occur in the diagnostic that is to be
* formatted and (iii) type-variable disambiguation - when the diagnostic refers
* to two different type-variables with the same name, their representation is
* disambiguated by appending an index to the type variable name.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class RichDiagnosticFormatter extends
ForwardingDiagnosticFormatter<JCDiagnostic, AbstractDiagnosticFormatter> {
final Symtab syms;
final Types types;
final JCDiagnostic.Factory diags;
final JavacMessages messages;
/* name simplifier used by this formatter */
protected ClassNameSimplifier nameSimplifier;
/* type/symbol printer used by this formatter */
private RichPrinter printer;
/* map for keeping track of a where clause associated to a given type */
Map<WhereClauseKind, Map<Type, JCDiagnostic>> whereClauses;
/** Get the DiagnosticFormatter instance for this context. */
public static RichDiagnosticFormatter instance(Context context) {
RichDiagnosticFormatter instance = context.get(RichDiagnosticFormatter.class);
if (instance == null)
instance = new RichDiagnosticFormatter(context);
return instance;
}
protected RichDiagnosticFormatter(Context context) {
super((AbstractDiagnosticFormatter)Log.instance(context).getDiagnosticFormatter());
setRichPrinter(new RichPrinter());
this.syms = Symtab.instance(context);
this.diags = JCDiagnostic.Factory.instance(context);
this.types = Types.instance(context);
this.messages = JavacMessages.instance(context);
whereClauses = new EnumMap<WhereClauseKind, Map<Type, JCDiagnostic>>(WhereClauseKind.class);
configuration = new RichConfiguration(Options.instance(context), formatter);
for (WhereClauseKind kind : WhereClauseKind.values())
whereClauses.put(kind, new LinkedHashMap<Type, JCDiagnostic>());
}
@Override
public String format(JCDiagnostic diag, Locale l) {
StringBuilder sb = new StringBuilder();
nameSimplifier = new ClassNameSimplifier();
for (WhereClauseKind kind : WhereClauseKind.values())
whereClauses.get(kind).clear();
preprocessDiagnostic(diag);
sb.append(formatter.format(diag, l));
if (getConfiguration().isEnabled(RichFormatterFeature.WHERE_CLAUSES)) {
List<JCDiagnostic> clauses = getWhereClauses();
String indent = formatter.isRaw() ? "" :
formatter.indentString(DetailsInc);
for (JCDiagnostic d : clauses) {
String whereClause = formatter.format(d, l);
if (whereClause.length() > 0) {
sb.append('\n' + indent + whereClause);
}
}
}
return sb.toString();
}
@Override
public String formatMessage(JCDiagnostic diag, Locale l) {
nameSimplifier = new ClassNameSimplifier();
preprocessDiagnostic(diag);
return super.formatMessage(diag, l);
}
/**
* Sets the type/symbol printer used by this formatter.
* @param printer the rich printer to be set
*/
protected void setRichPrinter(RichPrinter printer) {
this.printer = printer;
formatter.setPrinter(printer);
}
/**
* Gets the type/symbol printer used by this formatter.
* @return type/symbol rich printer
*/
protected RichPrinter getRichPrinter() {
return printer;
}
/**
* Preprocess a given diagnostic by looking both into its arguments and into
* its subdiagnostics (if any). This preprocessing is responsible for
* generating info corresponding to features like where clauses, name
* simplification, etc.
*
* @param diag the diagnostic to be preprocessed
*/
protected void preprocessDiagnostic(JCDiagnostic diag) {
for (Object o : diag.getArgs()) {
if (o != null) {
preprocessArgument(o);
}
}
if (diag.isMultiline()) {
for (JCDiagnostic d : diag.getSubdiagnostics())
preprocessDiagnostic(d);
}
}
/**
* Preprocess a diagnostic argument. A type/symbol argument is
* preprocessed by specialized type/symbol preprocessors.
*
* @param arg the argument to be translated
*/
protected void preprocessArgument(Object arg) {
if (arg instanceof Type) {
preprocessType((Type)arg);
}
else if (arg instanceof Symbol) {
preprocessSymbol((Symbol)arg);
}
else if (arg instanceof JCDiagnostic) {
preprocessDiagnostic((JCDiagnostic)arg);
}
else if (arg instanceof Iterable<?>) {
for (Object o : (Iterable<?>)arg) {
preprocessArgument(o);
}
}
}
/**
* Build a list of multiline diagnostics containing detailed info about
* type-variables, captured types, and intersection types
*
* @return where clause list
*/
protected List<JCDiagnostic> getWhereClauses() {
List<JCDiagnostic> clauses = List.nil();
for (WhereClauseKind kind : WhereClauseKind.values()) {
List<JCDiagnostic> lines = List.nil();
for (Map.Entry<Type, JCDiagnostic> entry : whereClauses.get(kind).entrySet()) {
lines = lines.prepend(entry.getValue());
}
if (!lines.isEmpty()) {
String key = kind.key();
if (lines.size() > 1)
key += ".1";
JCDiagnostic d = diags.fragment(key, whereClauses.get(kind).keySet());
d = new JCDiagnostic.MultilineDiagnostic(d, lines.reverse());
clauses = clauses.prepend(d);
}
}
return clauses.reverse();
}
private int indexOf(Type type, WhereClauseKind kind) {
int index = 1;
for (Type t : whereClauses.get(kind).keySet()) {
if (t.tsym == type.tsym) {
return index;
}
if (kind != WhereClauseKind.TYPEVAR ||
t.toString().equals(type.toString())) {
index++;
}
}
return -1;
}
private boolean unique(TypeVar typevar) {
int found = 0;
for (Type t : whereClauses.get(WhereClauseKind.TYPEVAR).keySet()) {
if (t.toString().equals(typevar.toString())) {
found++;
}
}
if (found < 1)
throw new AssertionError("Missing type variable in where clause " + typevar);
return found == 1;
}
//where
/**
* This enum defines all posssible kinds of where clauses that can be
* attached by a rich diagnostic formatter to a given diagnostic
*/
enum WhereClauseKind {
/** where clause regarding a type variable */
TYPEVAR("where.description.typevar"),
/** where clause regarding a captured type */
CAPTURED("where.description.captured"),
/** where clause regarding an intersection type */
INTERSECTION("where.description.intersection");
/** resource key for this where clause kind */
private final String key;
WhereClauseKind(String key) {
this.key = key;
}
String key() {
return key;
}
}
// <editor-fold defaultstate="collapsed" desc="name simplifier">
/**
* A name simplifier keeps track of class names usages in order to determine
* whether a class name can be compacted or not. Short names are not used
* if a conflict is detected, e.g. when two classes with the same simple
* name belong to different packages - in this case the formatter reverts
* to fullnames as compact names might lead to a confusing diagnostic.
*/
protected class ClassNameSimplifier {
/* table for keeping track of all short name usages */
Map<Name, List<Symbol>> nameClashes = new HashMap<Name, List<Symbol>>();
/**
* Add a name usage to the simplifier's internal cache
*/
protected void addUsage(Symbol sym) {
Name n = sym.getSimpleName();
List<Symbol> conflicts = nameClashes.get(n);
if (conflicts == null) {
conflicts = List.nil();
}
if (!conflicts.contains(sym))
nameClashes.put(n, conflicts.append(sym));
}
public String simplify(Symbol s) {
String name = s.getQualifiedName().toString();
if (!s.type.isCompound() && !s.type.isPrimitive()) {
List<Symbol> conflicts = nameClashes.get(s.getSimpleName());
if (conflicts == null ||
(conflicts.size() == 1 &&
conflicts.contains(s))) {
List<Name> l = List.nil();
Symbol s2 = s;
while (s2.type.hasTag(CLASS) &&
s2.type.getEnclosingType().hasTag(CLASS) &&
s2.owner.kind == Kinds.TYP) {
l = l.prepend(s2.getSimpleName());
s2 = s2.owner;
}
l = l.prepend(s2.getSimpleName());
StringBuilder buf = new StringBuilder();
String sep = "";
for (Name n2 : l) {
buf.append(sep);
buf.append(n2);
sep = ".";
}
name = buf.toString();
}
}
return name;
}
};
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="rich printer">
/**
* Enhanced type/symbol printer that provides support for features like simple names
* and type variable disambiguation. This enriched printer exploits the info
* discovered during type/symbol preprocessing. This printer is set on the delegate
* formatter so that rich type/symbol info can be properly rendered.
*/
protected class RichPrinter extends Printer {
@Override
public String localize(Locale locale, String key, Object... args) {
return formatter.localize(locale, key, args);
}
@Override
public String capturedVarId(CapturedType t, Locale locale) {
return indexOf(t, WhereClauseKind.CAPTURED) + "";
}
@Override
public String visitType(Type t, Locale locale) {
String s = super.visitType(t, locale);
if (t == syms.botType)
s = localize(locale, "compiler.misc.type.null");
return s;
}
@Override
public String visitCapturedType(CapturedType t, Locale locale) {
if (getConfiguration().isEnabled(RichFormatterFeature.WHERE_CLAUSES)) {
return localize(locale,
"compiler.misc.captured.type",
indexOf(t, WhereClauseKind.CAPTURED));
}
else
return super.visitCapturedType(t, locale);
}
@Override
public String visitClassType(ClassType t, Locale locale) {
if (t.isCompound() &&
getConfiguration().isEnabled(RichFormatterFeature.WHERE_CLAUSES)) {
return localize(locale,
"compiler.misc.intersection.type",
indexOf(t, WhereClauseKind.INTERSECTION));
}
else
return super.visitClassType(t, locale);
}
@Override
protected String className(ClassType t, boolean longform, Locale locale) {
Symbol sym = t.tsym;
if (sym.name.length() == 0 ||
!getConfiguration().isEnabled(RichFormatterFeature.SIMPLE_NAMES)) {
return super.className(t, longform, locale);
}
else if (longform)
return nameSimplifier.simplify(sym).toString();
else
return sym.name.toString();
}
@Override
public String visitTypeVar(TypeVar t, Locale locale) {
if (unique(t) ||
!getConfiguration().isEnabled(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES)) {
return t.toString();
}
else {
return localize(locale,
"compiler.misc.type.var",
t.toString(), indexOf(t, WhereClauseKind.TYPEVAR));
}
}
@Override
public String visitClassSymbol(ClassSymbol s, Locale locale) {
if (s.type.isCompound()) {
return visit(s.type, locale);
}
String name = nameSimplifier.simplify(s);
if (name.length() == 0 ||
!getConfiguration().isEnabled(RichFormatterFeature.SIMPLE_NAMES)) {
return super.visitClassSymbol(s, locale);
}
else {
return name;
}
}
@Override
public String visitMethodSymbol(MethodSymbol s, Locale locale) {
String ownerName = visit(s.owner, locale);
if (s.isStaticOrInstanceInit()) {
return ownerName;
} else {
String ms = (s.name == s.name.table.names.init)
? ownerName
: s.name.toString();
if (s.type != null) {
if (s.type.hasTag(FORALL)) {
ms = "<" + visitTypes(s.type.getTypeArguments(), locale) + ">" + ms;
}
ms += "(" + printMethodArgs(
s.type.getParameterTypes(),
(s.flags() & VARARGS) != 0,
locale) + ")";
}
return ms;
}
}
};
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="type scanner">
/**
* Preprocess a given type looking for (i) additional info (where clauses) to be
* added to the main diagnostic (ii) names to be compacted.
*/
protected void preprocessType(Type t) {
typePreprocessor.visit(t);
}
//where
protected Types.UnaryVisitor<Void> typePreprocessor =
new Types.UnaryVisitor<Void>() {
public Void visit(List<Type> ts) {
for (Type t : ts)
visit(t);
return null;
}
@Override
public Void visitForAll(ForAll t, Void ignored) {
visit(t.tvars);
visit(t.qtype);
return null;
}
@Override
public Void visitMethodType(MethodType t, Void ignored) {
visit(t.argtypes);
visit(t.restype);
return null;
}
@Override
public Void visitErrorType(ErrorType t, Void ignored) {
Type ot = t.getOriginalType();
if (ot != null)
visit(ot);
return null;
}
@Override
public Void visitArrayType(ArrayType t, Void ignored) {
visit(t.elemtype);
return null;
}
@Override
public Void visitWildcardType(WildcardType t, Void ignored) {
visit(t.type);
return null;
}
public Void visitType(Type t, Void ignored) {
return null;
}
@Override
public Void visitCapturedType(CapturedType t, Void ignored) {
if (indexOf(t, WhereClauseKind.CAPTURED) == -1) {
String suffix = t.lower == syms.botType ? ".1" : "";
JCDiagnostic d = diags.fragment("where.captured"+ suffix, t, t.bound, t.lower, t.wildcard);
whereClauses.get(WhereClauseKind.CAPTURED).put(t, d);
visit(t.wildcard);
visit(t.lower);
visit(t.bound);
}
return null;
}
@Override
public Void visitClassType(ClassType t, Void ignored) {
if (t.isCompound()) {
if (indexOf(t, WhereClauseKind.INTERSECTION) == -1) {
Type supertype = types.supertype(t);
List<Type> interfaces = types.interfaces(t);
JCDiagnostic d = diags.fragment("where.intersection", t, interfaces.prepend(supertype));
whereClauses.get(WhereClauseKind.INTERSECTION).put(t, d);
visit(supertype);
visit(interfaces);
}
} else if (t.tsym.name.isEmpty()) {
//anon class
ClassType norm = (ClassType) t.tsym.type;
if (norm != null) {
if (norm.interfaces_field != null && norm.interfaces_field.nonEmpty()) {
visit(norm.interfaces_field.head);
} else {
visit(norm.supertype_field);
}
}
}
nameSimplifier.addUsage(t.tsym);
visit(t.getTypeArguments());
if (t.getEnclosingType() != Type.noType)
visit(t.getEnclosingType());
return null;
}
@Override
public Void visitTypeVar(TypeVar t, Void ignored) {
if (indexOf(t, WhereClauseKind.TYPEVAR) == -1) {
//access the bound type and skip error types
Type bound = t.bound;
while ((bound instanceof ErrorType))
bound = ((ErrorType)bound).getOriginalType();
//retrieve the bound list - if the type variable
//has not been attributed the bound is not set
List<Type> bounds = (bound != null) &&
(bound.hasTag(CLASS) || bound.hasTag(TYPEVAR)) ?
types.getBounds(t) :
List.<Type>nil();
nameSimplifier.addUsage(t.tsym);
boolean boundErroneous = bounds.head == null ||
bounds.head.hasTag(NONE) ||
bounds.head.hasTag(ERROR);
if ((t.tsym.flags() & SYNTHETIC) == 0) {
//this is a true typevar
JCDiagnostic d = diags.fragment("where.typevar" +
(boundErroneous ? ".1" : ""), t, bounds,
Kinds.kindName(t.tsym.location()), t.tsym.location());
whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d);
symbolPreprocessor.visit(t.tsym.location(), null);
visit(bounds);
} else {
Assert.check(!boundErroneous);
//this is a fresh (synthetic) tvar
JCDiagnostic d = diags.fragment("where.fresh.typevar", t, bounds);
whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d);
visit(bounds);
}
}
return null;
}
};
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="symbol scanner">
/**
* Preprocess a given symbol looking for (i) additional info (where clauses) to be
* added to the main diagnostic (ii) names to be compacted
*/
protected void preprocessSymbol(Symbol s) {
symbolPreprocessor.visit(s, null);
}
//where
protected Types.DefaultSymbolVisitor<Void, Void> symbolPreprocessor =
new Types.DefaultSymbolVisitor<Void, Void>() {
@Override
public Void visitClassSymbol(ClassSymbol s, Void ignored) {
if (s.type.isCompound()) {
typePreprocessor.visit(s.type);
} else {
nameSimplifier.addUsage(s);
}
return null;
}
@Override
public Void visitSymbol(Symbol s, Void ignored) {
return null;
}
@Override
public Void visitMethodSymbol(MethodSymbol s, Void ignored) {
visit(s.owner, null);
if (s.type != null)
typePreprocessor.visit(s.type);
return null;
}
};
// </editor-fold>
@Override
public RichConfiguration getConfiguration() {
//the following cast is always safe - see init
return (RichConfiguration)configuration;
}
/**
* Configuration object provided by the rich formatter.
*/
public static class RichConfiguration extends ForwardingDiagnosticFormatter.ForwardingConfiguration {
/** set of enabled rich formatter's features */
protected java.util.EnumSet<RichFormatterFeature> features;
@SuppressWarnings("fallthrough")
public RichConfiguration(Options options, AbstractDiagnosticFormatter formatter) {
super(formatter.getConfiguration());
features = formatter.isRaw() ? EnumSet.noneOf(RichFormatterFeature.class) :
EnumSet.of(RichFormatterFeature.SIMPLE_NAMES,
RichFormatterFeature.WHERE_CLAUSES,
RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
String diagOpts = options.get("diags");
if (diagOpts != null) {
for (String args: diagOpts.split(",")) {
if (args.equals("-where")) {
features.remove(RichFormatterFeature.WHERE_CLAUSES);
}
else if (args.equals("where")) {
features.add(RichFormatterFeature.WHERE_CLAUSES);
}
if (args.equals("-simpleNames")) {
features.remove(RichFormatterFeature.SIMPLE_NAMES);
}
else if (args.equals("simpleNames")) {
features.add(RichFormatterFeature.SIMPLE_NAMES);
}
if (args.equals("-disambiguateTvars")) {
features.remove(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
}
else if (args.equals("disambiguateTvars")) {
features.add(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
}
}
}
}
/**
* Returns a list of all the features supported by the rich formatter.
* @return list of supported features
*/
public RichFormatterFeature[] getAvailableFeatures() {
return RichFormatterFeature.values();
}
/**
* Enable a specific feature on this rich formatter.
* @param feature feature to be enabled
*/
public void enable(RichFormatterFeature feature) {
features.add(feature);
}
/**
* Disable a specific feature on this rich formatter.
* @param feature feature to be disabled
*/
public void disable(RichFormatterFeature feature) {
features.remove(feature);
}
/**
* Is a given feature enabled on this formatter?
* @param feature feature to be tested
*/
public boolean isEnabled(RichFormatterFeature feature) {
return features.contains(feature);
}
/**
* The advanced formatting features provided by the rich formatter
*/
public enum RichFormatterFeature {
/** a list of additional info regarding a given type/symbol */
WHERE_CLAUSES,
/** full class names simplification (where possible) */
SIMPLE_NAMES,
/** type-variable names disambiguation */
UNIQUE_TYPEVAR_NAMES;
}
}
}

View File

@@ -0,0 +1,437 @@
/*
* Copyright (c) 2005, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.ServiceConfigurationError;
/**
* This is a temporary, modified copy of java.util.ServiceLoader, for use by
* javac, to work around bug JDK-8004082.
*
* The bug describes problems in the interaction between ServiceLoader and
* URLClassLoader, such that references to a jar file passed to URLClassLoader
* may be retained after calling URLClassLoader.close(), preventing the jar
* file from being deleted on Windows.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public final class ServiceLoader<S>
implements Iterable<S>
{
private static final String PREFIX = "META-INF/services/";
// The class or interface representing the service being loaded
private Class<S> service;
// The class loader used to locate, load, and instantiate providers
private ClassLoader loader;
// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// The current lazy-lookup iterator
private LazyIterator lookupIterator;
/**
* Clear this loader's provider cache so that all providers will be
* reloaded.
*
* <p> After invoking this method, subsequent invocations of the {@link
* #iterator() iterator} method will lazily look up and instantiate
* providers from scratch, just as is done by a newly-created loader.
*
* <p> This method is intended for use in situations in which new providers
* can be installed into a running Java virtual machine.
*/
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
reload();
}
private static void fail(Class<?> service, String msg, Throwable cause)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg,
cause);
}
private static void fail(Class<?> service, String msg)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg);
}
private static void fail(Class<?> service, URL u, int line, String msg)
throws ServiceConfigurationError
{
fail(service, u + ":" + line + ": " + msg);
}
// Parse a single line from the given configuration file, adding the name
// on the line to the names list.
//
private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
List<String> names)
throws IOException, ServiceConfigurationError
{
String ln = r.readLine();
if (ln == null) {
return -1;
}
int ci = ln.indexOf('#');
if (ci >= 0) ln = ln.substring(0, ci);
ln = ln.trim();
int n = ln.length();
if (n != 0) {
if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
fail(service, u, lc, "Illegal configuration-file syntax");
int cp = ln.codePointAt(0);
if (!Character.isJavaIdentifierStart(cp))
fail(service, u, lc, "Illegal provider-class name: " + ln);
for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
cp = ln.codePointAt(i);
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
if (!providers.containsKey(ln) && !names.contains(ln))
names.add(ln);
}
return lc + 1;
}
// Parse the content of the given URL as a provider-configuration file.
//
// @param service
// The service type for which providers are being sought;
// used to construct error detail strings
//
// @param u
// The URL naming the configuration file to be parsed
//
// @return A (possibly empty) iterator that will yield the provider-class
// names in the given configuration file that are not yet members
// of the returned set
//
// @throws ServiceConfigurationError
// If an I/O error occurs while reading from the given URL, or
// if a configuration-file format error is detected
//
private Iterator<String> parse(Class<?> service, URL u)
throws ServiceConfigurationError
{
InputStream in = null;
BufferedReader r = null;
ArrayList<String> names = new ArrayList<>();
try {
// The problem is that by default, streams opened with
// u.openInputStream use a cached reference to a JarFile, which
// is separate from the reference used by URLClassLoader, and
// which is not closed by URLClassLoader.close().
// The workaround is to disable caching for this specific jar file,
// so that the reference to the jar file can be closed when the
// file has been read.
// Original code:
// in = u.openStream();
// Workaround ...
URLConnection uc = u.openConnection();
uc.setUseCaches(false);
in = uc.getInputStream();
// ... end of workaround.
r = new BufferedReader(new InputStreamReader(in, "utf-8"));
int lc = 1;
while ((lc = parseLine(service, u, r, lc, names)) >= 0);
} catch (IOException x) {
fail(service, "Error reading configuration file", x);
} finally {
try {
if (r != null) r.close();
if (in != null) in.close();
} catch (IOException y) {
fail(service, "Error closing configuration file", y);
}
}
return names.iterator();
}
// Private inner class implementing fully-lazy provider lookup
//
private class LazyIterator
implements Iterator<S>
{
Class<S> service;
ClassLoader loader;
Enumeration<URL> configs = null;
Iterator<String> pending = null;
String nextName = null;
private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
public boolean hasNext() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
public S next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service,
"Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated: " + x,
x);
}
throw new Error(); // This cannot happen
}
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* Lazily loads the available providers of this loader's service.
*
* <p> The iterator returned by this method first yields all of the
* elements of the provider cache, in instantiation order. It then lazily
* loads and instantiates any remaining providers, adding each one to the
* cache in turn.
*
* <p> To achieve laziness the actual work of parsing the available
* provider-configuration files and instantiating providers must be done by
* the iterator itself. Its {@link java.util.Iterator#hasNext hasNext} and
* {@link java.util.Iterator#next next} methods can therefore throw a
* {@link ServiceConfigurationError} if a provider-configuration file
* violates the specified format, or if it names a provider class that
* cannot be found and instantiated, or if the result of instantiating the
* class is not assignable to the service type, or if any other kind of
* exception or error is thrown as the next provider is located and
* instantiated. To write robust code it is only necessary to catch {@link
* ServiceConfigurationError} when using a service iterator.
*
* <p> If such an error is thrown then subsequent invocations of the
* iterator will make a best effort to locate and instantiate the next
* available provider, but in general such recovery cannot be guaranteed.
*
* <blockquote style="font-size: smaller; line-height: 1.2"><span
* style="padding-right: 1em; font-weight: bold">Design Note</span>
* Throwing an error in these cases may seem extreme. The rationale for
* this behavior is that a malformed provider-configuration file, like a
* malformed class file, indicates a serious problem with the way the Java
* virtual machine is configured or is being used. As such it is
* preferable to throw an error rather than try to recover or, even worse,
* fail silently.</blockquote>
*
* <p> The iterator returned by this method does not support removal.
* Invoking its {@link java.util.Iterator#remove() remove} method will
* cause an {@link UnsupportedOperationException} to be thrown.
*
* @return An iterator that lazily loads providers for this loader's
* service
*/
public Iterator<S> iterator() {
return new Iterator<S>() {
Iterator<Map.Entry<String,S>> knownProviders
= providers.entrySet().iterator();
public boolean hasNext() {
if (knownProviders.hasNext())
return true;
return lookupIterator.hasNext();
}
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Creates a new service loader for the given service type and class
* loader.
*
* @param service
* The interface or abstract class representing the service
*
* @param loader
* The class loader to be used to load provider-configuration files
* and provider classes, or <tt>null</tt> if the system class
* loader (or, failing that, the bootstrap class loader) is to be
* used
*
* @return A new service loader
*/
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
return new ServiceLoader<>(service, loader);
}
/**
* Creates a new service loader for the given service type, using the
* current thread's {@linkplain java.lang.Thread#getContextClassLoader
* context class loader}.
*
* <p> An invocation of this convenience method of the form
*
* <blockquote><pre>
* ServiceLoader.load(<i>service</i>)</pre></blockquote>
*
* is equivalent to
*
* <blockquote><pre>
* ServiceLoader.load(<i>service</i>,
* Thread.currentThread().getContextClassLoader())</pre></blockquote>
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*/
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
/**
* Creates a new service loader for the given service type, using the
* extension class loader.
*
* <p> This convenience method simply locates the extension class loader,
* call it <tt><i>extClassLoader</i></tt>, and then returns
*
* <blockquote><pre>
* ServiceLoader.load(<i>service</i>, <i>extClassLoader</i>)</pre></blockquote>
*
* <p> If the extension class loader cannot be found then the system class
* loader is used; if there is no system class loader then the bootstrap
* class loader is used.
*
* <p> This method is intended for use when only installed providers are
* desired. The resulting service will only find and load providers that
* have been installed into the current Java virtual machine; providers on
* the application's class path will be ignored.
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*/
public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
ClassLoader prev = null;
while (cl != null) {
prev = cl;
cl = cl.getParent();
}
return ServiceLoader.load(service, prev);
}
/**
* Returns a string describing this service.
*
* @return A descriptive string
*/
public String toString() {
return "java.util.ServiceLoader[" + service.getName() + "]";
}
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (c) 1999, 2012, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.lang.ref.SoftReference;
/**
* Implementation of Name.Table that stores all names in a single shared
* byte array, expanding it as needed. This avoids the overhead incurred
* by using an array of bytes for each name.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class SharedNameTable extends Name.Table {
// maintain a freelist of recently used name tables for reuse.
private static List<SoftReference<SharedNameTable>> freelist = List.nil();
static public synchronized SharedNameTable create(Names names) {
while (freelist.nonEmpty()) {
SharedNameTable t = freelist.head.get();
freelist = freelist.tail;
if (t != null) {
return t;
}
}
return new SharedNameTable(names);
}
static private synchronized void dispose(SharedNameTable t) {
freelist = freelist.prepend(new SoftReference<SharedNameTable>(t));
}
/** The hash table for names.
*/
private NameImpl[] hashes;
/** The shared byte array holding all encountered names.
*/
public byte[] bytes;
/** The mask to be used for hashing
*/
private int hashMask;
/** The number of filled bytes in `names'.
*/
private int nc = 0;
/** Allocator
* @param names The main name table
* @param hashSize the (constant) size to be used for the hash table
* needs to be a power of two.
* @param nameSize the initial size of the name table.
*/
public SharedNameTable(Names names, int hashSize, int nameSize) {
super(names);
hashMask = hashSize - 1;
hashes = new NameImpl[hashSize];
bytes = new byte[nameSize];
}
public SharedNameTable(Names names) {
this(names, 0x8000, 0x20000);
}
@Override
public Name fromChars(char[] cs, int start, int len) {
int nc = this.nc;
byte[] bytes = this.bytes = ArrayUtils.ensureCapacity(this.bytes, nc + len * 3);
int nbytes = Convert.chars2utf(cs, start, bytes, nc, len) - nc;
int h = hashValue(bytes, nc, nbytes) & hashMask;
NameImpl n = hashes[h];
while (n != null &&
(n.getByteLength() != nbytes ||
!equals(bytes, n.index, bytes, nc, nbytes))) {
n = n.next;
}
if (n == null) {
n = new NameImpl(this);
n.index = nc;
n.length = nbytes;
n.next = hashes[h];
hashes[h] = n;
this.nc = nc + nbytes;
if (nbytes == 0) {
this.nc++;
}
}
return n;
}
@Override
public Name fromUtf(byte[] cs, int start, int len) {
int h = hashValue(cs, start, len) & hashMask;
NameImpl n = hashes[h];
byte[] names = this.bytes;
while (n != null &&
(n.getByteLength() != len || !equals(names, n.index, cs, start, len))) {
n = n.next;
}
if (n == null) {
int nc = this.nc;
names = this.bytes = ArrayUtils.ensureCapacity(names, nc + len);
System.arraycopy(cs, start, names, nc, len);
n = new NameImpl(this);
n.index = nc;
n.length = len;
n.next = hashes[h];
hashes[h] = n;
this.nc = nc + len;
if (len == 0) {
this.nc++;
}
}
return n;
}
@Override
public void dispose() {
dispose(this);
}
static class NameImpl extends Name {
/** The next name occupying the same hash bucket.
*/
NameImpl next;
/** The index where the bytes of this name are stored in the global name
* buffer `byte'.
*/
int index;
/** The number of bytes in this name.
*/
int length;
NameImpl(SharedNameTable table) {
super(table);
}
@Override
public int getIndex() {
return index;
}
@Override
public int getByteLength() {
return length;
}
@Override
public byte getByteAt(int i) {
return getByteArray()[index + i];
}
@Override
public byte[] getByteArray() {
return ((SharedNameTable) table).bytes;
}
@Override
public int getByteOffset() {
return index;
}
/** Return the hash value of this name.
*/
public int hashCode() {
return index;
}
/** Is this name equal to other?
*/
public boolean equals(Object other) {
if (other instanceof Name)
return
table == ((Name)other).table && index == ((Name) other).getIndex();
else return false;
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2013, 2014, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** A collection of utilities for String manipulation.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class StringUtils {
/**Converts the given String to lower case using the {@link Locale#US US Locale}. The result
* is independent of the default Locale in the current JVM instance.
*/
public static String toLowerCase(String source) {
return source.toLowerCase(Locale.US);
}
/**Converts the given String to upper case using the {@link Locale#US US Locale}. The result
* is independent of the default Locale in the current JVM instance.
*/
public static String toUpperCase(String source) {
return source.toUpperCase(Locale.US);
}
/**Case insensitive version of {@link String#indexOf(java.lang.String)}. Equivalent to
* {@code text.indexOf(str)}, except the matching is case insensitive.
*/
public static int indexOfIgnoreCase(String text, String str) {
return indexOfIgnoreCase(text, str, 0);
}
/**Case insensitive version of {@link String#indexOf(java.lang.String, int)}. Equivalent to
* {@code text.indexOf(str, startIndex)}, except the matching is case insensitive.
*/
public static int indexOfIgnoreCase(String text, String str, int startIndex) {
Matcher m = Pattern.compile(Pattern.quote(str), Pattern.CASE_INSENSITIVE).matcher(text);
return m.find(startIndex) ? m.start() : -1;
}
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 1999, 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import java.lang.ref.WeakReference;
/**
* Implementation of Name.Table that stores names in individual arrays
* using weak references. It is recommended for use when a single shared
* byte array is unsuitable.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class UnsharedNameTable extends Name.Table {
static public Name.Table create(Names names) {
return new UnsharedNameTable(names);
}
static class HashEntry extends WeakReference<NameImpl> {
HashEntry next;
HashEntry(NameImpl referent) {
super(referent);
}
}
/** The hash table for names.
*/
private HashEntry[] hashes = null;
/** The mask to be used for hashing
*/
private int hashMask;
/** Index counter for names in this table.
*/
public int index;
/** Allocator
* @param names The main name table
* @param hashSize the (constant) size to be used for the hash table
* needs to be a power of two.
*/
public UnsharedNameTable(Names names, int hashSize) {
super(names);
hashMask = hashSize - 1;
hashes = new HashEntry[hashSize];
}
public UnsharedNameTable(Names names) {
this(names, 0x8000);
}
@Override
public Name fromChars(char[] cs, int start, int len) {
byte[] name = new byte[len * 3];
int nbytes = Convert.chars2utf(cs, start, name, 0, len);
return fromUtf(name, 0, nbytes);
}
@Override
public Name fromUtf(byte[] cs, int start, int len) {
int h = hashValue(cs, start, len) & hashMask;
HashEntry element = hashes[h];
NameImpl n = null;
HashEntry previousNonNullTableEntry = null;
HashEntry firstTableEntry = element;
while (element != null) {
if (element == null) {
break;
}
n = element.get();
if (n == null) {
if (firstTableEntry == element) {
hashes[h] = firstTableEntry = element.next;
}
else {
Assert.checkNonNull(previousNonNullTableEntry, "previousNonNullTableEntry cannot be null here.");
previousNonNullTableEntry.next = element.next;
}
}
else {
if (n.getByteLength() == len && equals(n.bytes, 0, cs, start, len)) {
return n;
}
previousNonNullTableEntry = element;
}
element = element.next;
}
byte[] bytes = new byte[len];
System.arraycopy(cs, start, bytes, 0, len);
n = new NameImpl(this, bytes, index++);
HashEntry newEntry = new HashEntry(n);
if (previousNonNullTableEntry == null) { // We are not the first name with that hashCode.
hashes[h] = newEntry;
}
else {
Assert.checkNull(previousNonNullTableEntry.next, "previousNonNullTableEntry.next must be null.");
previousNonNullTableEntry.next = newEntry;
}
return n;
}
@Override
public void dispose() {
hashes = null;
}
static class NameImpl extends Name {
NameImpl(UnsharedNameTable table, byte[] bytes, int index) {
super(table);
this.bytes = bytes;
this.index = index;
}
final byte[] bytes;
final int index;
@Override
public int getIndex() {
return index;
}
@Override
public int getByteLength() {
return bytes.length;
}
@Override
public byte getByteAt(int i) {
return bytes[i];
}
@Override
public byte[] getByteArray() {
return bytes;
}
@Override
public int getByteOffset() {
return 0;
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2003, 2010, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.util;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import java.util.EnumSet;
/**
* An interface to support optional warnings, needed for support of
* unchecked conversions and unchecked casts.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Warner {
private DiagnosticPosition pos = null;
protected boolean warned = false;
private EnumSet<LintCategory> nonSilentLintSet = EnumSet.noneOf(LintCategory.class);
private EnumSet<LintCategory> silentLintSet = EnumSet.noneOf(LintCategory.class);
public DiagnosticPosition pos() {
return pos;
}
public void warn(LintCategory lint) {
nonSilentLintSet.add(lint);
}
public void silentWarn(LintCategory lint) {
silentLintSet.add(lint);
}
public Warner(DiagnosticPosition pos) {
this.pos = pos;
}
public boolean hasSilentLint(LintCategory lint) {
return silentLintSet.contains(lint);
}
public boolean hasNonSilentLint(LintCategory lint) {
return nonSilentLintSet.contains(lint);
}
public boolean hasLint(LintCategory lint) {
return hasSilentLint(lint) ||
hasNonSilentLint(lint);
}
public void clear() {
nonSilentLintSet.clear();
silentLintSet.clear();
this.warned = false;
}
public Warner() {
this(null);
}
}