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,42 @@
/*
* Copyright (c) 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.processing;
/**
* Error thrown for problems encountered during annotation processing.
*
* <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 AnnotationProcessingError extends Error {
static final long serialVersionUID = 305337707019230790L;
AnnotationProcessingError(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,642 @@
/*
* Copyright (c) 2005, 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.processing;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FilterOutputStream;
import java.io.Reader;
import java.io.Writer;
import java.io.FilterWriter;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.*;
import static java.util.Collections.*;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Element;
import javax.tools.*;
import javax.tools.JavaFileManager.Location;
import static javax.tools.StandardLocation.SOURCE_OUTPUT;
import static javax.tools.StandardLocation.CLASS_OUTPUT;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.util.*;
import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING;
/**
* The FilerImplementation class must maintain a number of
* constraints. First, multiple attempts to open the same path within
* the same invocation of the tool results in an IOException being
* thrown. For example, trying to open the same source file twice:
*
* <pre>
* createSourceFile("foo.Bar")
* ...
* createSourceFile("foo.Bar")
* </pre>
*
* is disallowed as is opening a text file that happens to have
* the same name as a source file:
*
* <pre>
* createSourceFile("foo.Bar")
* ...
* createTextFile(SOURCE_TREE, "foo", new File("Bar"), null)
* </pre>
*
* <p>Additionally, creating a source file that corresponds to an
* already created class file (or vice versa) also results in an
* IOException since each type can only be created once. However, if
* the Filer is used to create a text file named *.java that happens
* to correspond to an existing class file, a warning is *not*
* generated. Similarly, a warning is not generated for a binary file
* named *.class and an existing source file.
*
* <p>The reason for this difference is that source files and class
* files are registered with the tool and can get passed on as
* declarations to the next round of processing. Files that are just
* named *.java and *.class are not processed in that manner; although
* having extra source files and class files on the source path and
* class path can alter the behavior of the tool and any final
* compile.
*
* <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 JavacFiler implements Filer, Closeable {
// TODO: Implement different transaction model for updating the
// Filer's record keeping on file close.
private static final String ALREADY_OPENED =
"Output stream or writer has already been opened.";
private static final String NOT_FOR_READING =
"FileObject was not opened for reading.";
private static final String NOT_FOR_WRITING =
"FileObject was not opened for writing.";
/**
* Wrap a JavaFileObject to manage writing by the Filer.
*/
private class FilerOutputFileObject extends ForwardingFileObject<FileObject> {
private boolean opened = false;
private String name;
FilerOutputFileObject(String name, FileObject fileObject) {
super(fileObject);
this.name = name;
}
@Override
public synchronized OutputStream openOutputStream() throws IOException {
if (opened)
throw new IOException(ALREADY_OPENED);
opened = true;
return new FilerOutputStream(name, fileObject);
}
@Override
public synchronized Writer openWriter() throws IOException {
if (opened)
throw new IOException(ALREADY_OPENED);
opened = true;
return new FilerWriter(name, fileObject);
}
// Three anti-literacy methods
@Override
public InputStream openInputStream() throws IOException {
throw new IllegalStateException(NOT_FOR_READING);
}
@Override
public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
throw new IllegalStateException(NOT_FOR_READING);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
throw new IllegalStateException(NOT_FOR_READING);
}
@Override
public boolean delete() {
return false;
}
}
private class FilerOutputJavaFileObject extends FilerOutputFileObject implements JavaFileObject {
private final JavaFileObject javaFileObject;
FilerOutputJavaFileObject(String name, JavaFileObject javaFileObject) {
super(name, javaFileObject);
this.javaFileObject = javaFileObject;
}
public JavaFileObject.Kind getKind() {
return javaFileObject.getKind();
}
public boolean isNameCompatible(String simpleName,
JavaFileObject.Kind kind) {
return javaFileObject.isNameCompatible(simpleName, kind);
}
public NestingKind getNestingKind() {
return javaFileObject.getNestingKind();
}
public Modifier getAccessLevel() {
return javaFileObject.getAccessLevel();
}
}
/**
* Wrap a JavaFileObject to manage reading by the Filer.
*/
private class FilerInputFileObject extends ForwardingFileObject<FileObject> {
FilerInputFileObject(FileObject fileObject) {
super(fileObject);
}
@Override
public OutputStream openOutputStream() throws IOException {
throw new IllegalStateException(NOT_FOR_WRITING);
}
@Override
public Writer openWriter() throws IOException {
throw new IllegalStateException(NOT_FOR_WRITING);
}
@Override
public boolean delete() {
return false;
}
}
private class FilerInputJavaFileObject extends FilerInputFileObject implements JavaFileObject {
private final JavaFileObject javaFileObject;
FilerInputJavaFileObject(JavaFileObject javaFileObject) {
super(javaFileObject);
this.javaFileObject = javaFileObject;
}
public JavaFileObject.Kind getKind() {
return javaFileObject.getKind();
}
public boolean isNameCompatible(String simpleName,
JavaFileObject.Kind kind) {
return javaFileObject.isNameCompatible(simpleName, kind);
}
public NestingKind getNestingKind() {
return javaFileObject.getNestingKind();
}
public Modifier getAccessLevel() {
return javaFileObject.getAccessLevel();
}
}
/**
* Wrap a {@code OutputStream} returned from the {@code
* JavaFileManager} to properly register source or class files
* when they are closed.
*/
private class FilerOutputStream extends FilterOutputStream {
String typeName;
FileObject fileObject;
boolean closed = false;
/**
* @param typeName name of class or {@code null} if just a
* binary file
*/
FilerOutputStream(String typeName, FileObject fileObject) throws IOException {
super(fileObject.openOutputStream());
this.typeName = typeName;
this.fileObject = fileObject;
}
public synchronized void close() throws IOException {
if (!closed) {
closed = true;
/*
* If an IOException occurs when closing the underlying
* stream, still try to process the file.
*/
closeFileObject(typeName, fileObject);
out.close();
}
}
}
/**
* Wrap a {@code Writer} returned from the {@code JavaFileManager}
* to properly register source or class files when they are
* closed.
*/
private class FilerWriter extends FilterWriter {
String typeName;
FileObject fileObject;
boolean closed = false;
/**
* @param fileObject the fileObject to be written to
* @param typeName name of source file or {@code null} if just a
* text file
*/
FilerWriter(String typeName, FileObject fileObject) throws IOException {
super(fileObject.openWriter());
this.typeName = typeName;
this.fileObject = fileObject;
}
public synchronized void close() throws IOException {
if (!closed) {
closed = true;
/*
* If an IOException occurs when closing the underlying
* Writer, still try to process the file.
*/
closeFileObject(typeName, fileObject);
out.close();
}
}
}
JavaFileManager fileManager;
Log log;
Context context;
boolean lastRound;
private final boolean lint;
/**
* Logical names of all created files. This set must be
* synchronized.
*/
private final Set<FileObject> fileObjectHistory;
/**
* Names of types that have had files created but not closed.
*/
private final Set<String> openTypeNames;
/**
* Names of source files closed in this round. This set must be
* synchronized. Its iterators should preserve insertion order.
*/
private Set<String> generatedSourceNames;
/**
* Names and class files of the class files closed in this round.
* This set must be synchronized. Its iterators should preserve
* insertion order.
*/
private final Map<String, JavaFileObject> generatedClasses;
/**
* JavaFileObjects for source files closed in this round. This
* set must be synchronized. Its iterators should preserve
* insertion order.
*/
private Set<JavaFileObject> generatedSourceFileObjects;
/**
* Names of all created source files. Its iterators should
* preserve insertion order.
*/
private final Set<String> aggregateGeneratedSourceNames;
/**
* Names of all created class files. Its iterators should
* preserve insertion order.
*/
private final Set<String> aggregateGeneratedClassNames;
JavacFiler(Context context) {
this.context = context;
fileManager = context.get(JavaFileManager.class);
log = Log.instance(context);
fileObjectHistory = synchronizedSet(new LinkedHashSet<FileObject>());
generatedSourceNames = synchronizedSet(new LinkedHashSet<String>());
generatedSourceFileObjects = synchronizedSet(new LinkedHashSet<JavaFileObject>());
generatedClasses = synchronizedMap(new LinkedHashMap<String, JavaFileObject>());
openTypeNames = synchronizedSet(new LinkedHashSet<String>());
aggregateGeneratedSourceNames = new LinkedHashSet<String>();
aggregateGeneratedClassNames = new LinkedHashSet<String>();
lint = (Lint.instance(context)).isEnabled(PROCESSING);
}
public JavaFileObject createSourceFile(CharSequence name,
Element... originatingElements) throws IOException {
return createSourceOrClassFile(true, name.toString());
}
public JavaFileObject createClassFile(CharSequence name,
Element... originatingElements) throws IOException {
return createSourceOrClassFile(false, name.toString());
}
private JavaFileObject createSourceOrClassFile(boolean isSourceFile, String name) throws IOException {
if (lint) {
int periodIndex = name.lastIndexOf(".");
if (periodIndex != -1) {
String base = name.substring(periodIndex);
String extn = (isSourceFile ? ".java" : ".class");
if (base.equals(extn))
log.warning("proc.suspicious.class.name", name, extn);
}
}
checkNameAndExistence(name, isSourceFile);
Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT);
JavaFileObject.Kind kind = (isSourceFile ?
JavaFileObject.Kind.SOURCE :
JavaFileObject.Kind.CLASS);
JavaFileObject fileObject =
fileManager.getJavaFileForOutput(loc, name, kind, null);
checkFileReopening(fileObject, true);
if (lastRound)
log.warning("proc.file.create.last.round", name);
if (isSourceFile)
aggregateGeneratedSourceNames.add(name);
else
aggregateGeneratedClassNames.add(name);
openTypeNames.add(name);
return new FilerOutputJavaFileObject(name, fileObject);
}
public FileObject createResource(JavaFileManager.Location location,
CharSequence pkg,
CharSequence relativeName,
Element... originatingElements) throws IOException {
locationCheck(location);
String strPkg = pkg.toString();
if (strPkg.length() > 0)
checkName(strPkg);
FileObject fileObject =
fileManager.getFileForOutput(location, strPkg,
relativeName.toString(), null);
checkFileReopening(fileObject, true);
if (fileObject instanceof JavaFileObject)
return new FilerOutputJavaFileObject(null, (JavaFileObject)fileObject);
else
return new FilerOutputFileObject(null, fileObject);
}
private void locationCheck(JavaFileManager.Location location) {
if (location instanceof StandardLocation) {
StandardLocation stdLoc = (StandardLocation) location;
if (!stdLoc.isOutputLocation())
throw new IllegalArgumentException("Resource creation not supported in location " +
stdLoc);
}
}
public FileObject getResource(JavaFileManager.Location location,
CharSequence pkg,
CharSequence relativeName) throws IOException {
String strPkg = pkg.toString();
if (strPkg.length() > 0)
checkName(strPkg);
// TODO: Only support reading resources in selected output
// locations? Only allow reading of non-source, non-class
// files from the supported input locations?
// In the following, getFileForInput is the "obvious" method
// to use, but it does not have the "obvious" semantics for
// SOURCE_OUTPUT and CLASS_OUTPUT. Conversely, getFileForOutput
// does not have the correct semantics for any "path" location
// with more than one component. So, for now, we use a hybrid
// invocation.
FileObject fileObject;
if (location.isOutputLocation()) {
fileObject = fileManager.getFileForOutput(location,
pkg.toString(),
relativeName.toString(),
null);
} else {
fileObject = fileManager.getFileForInput(location,
pkg.toString(),
relativeName.toString());
}
if (fileObject == null) {
String name = (pkg.length() == 0)
? relativeName.toString() : (pkg + "/" + relativeName);
throw new FileNotFoundException(name);
}
// If the path was already opened for writing, throw an exception.
checkFileReopening(fileObject, false);
return new FilerInputFileObject(fileObject);
}
private void checkName(String name) throws FilerException {
checkName(name, false);
}
private void checkName(String name, boolean allowUnnamedPackageInfo) throws FilerException {
if (!SourceVersion.isName(name) && !isPackageInfo(name, allowUnnamedPackageInfo)) {
if (lint)
log.warning("proc.illegal.file.name", name);
throw new FilerException("Illegal name " + name);
}
}
private boolean isPackageInfo(String name, boolean allowUnnamedPackageInfo) {
// Is the name of the form "package-info" or
// "foo.bar.package-info"?
final String PKG_INFO = "package-info";
int periodIndex = name.lastIndexOf(".");
if (periodIndex == -1) {
return allowUnnamedPackageInfo ? name.equals(PKG_INFO) : false;
} else {
// "foo.bar.package-info." illegal
String prefix = name.substring(0, periodIndex);
String simple = name.substring(periodIndex+1);
return SourceVersion.isName(prefix) && simple.equals(PKG_INFO);
}
}
private void checkNameAndExistence(String typename, boolean allowUnnamedPackageInfo) throws FilerException {
// TODO: Check if type already exists on source or class path?
// If so, use warning message key proc.type.already.exists
checkName(typename, allowUnnamedPackageInfo);
if (aggregateGeneratedSourceNames.contains(typename) ||
aggregateGeneratedClassNames.contains(typename)) {
if (lint)
log.warning("proc.type.recreate", typename);
throw new FilerException("Attempt to recreate a file for type " + typename);
}
}
/**
* Check to see if the file has already been opened; if so, throw
* an exception, otherwise add it to the set of files.
*/
private void checkFileReopening(FileObject fileObject, boolean addToHistory) throws FilerException {
for(FileObject veteran : fileObjectHistory) {
if (fileManager.isSameFile(veteran, fileObject)) {
if (lint)
log.warning("proc.file.reopening", fileObject.getName());
throw new FilerException("Attempt to reopen a file for path " + fileObject.getName());
}
}
if (addToHistory)
fileObjectHistory.add(fileObject);
}
public boolean newFiles() {
return (!generatedSourceNames.isEmpty())
|| (!generatedClasses.isEmpty());
}
public Set<String> getGeneratedSourceNames() {
return generatedSourceNames;
}
public Set<JavaFileObject> getGeneratedSourceFileObjects() {
return generatedSourceFileObjects;
}
public Map<String, JavaFileObject> getGeneratedClasses() {
return generatedClasses;
}
public void warnIfUnclosedFiles() {
if (!openTypeNames.isEmpty())
log.warning("proc.unclosed.type.files", openTypeNames.toString());
}
/**
* Update internal state for a new round.
*/
public void newRound(Context context) {
this.context = context;
this.log = Log.instance(context);
clearRoundState();
}
void setLastRound(boolean lastRound) {
this.lastRound = lastRound;
}
public void close() {
clearRoundState();
// Cross-round state
fileObjectHistory.clear();
openTypeNames.clear();
aggregateGeneratedSourceNames.clear();
aggregateGeneratedClassNames.clear();
}
private void clearRoundState() {
generatedSourceNames.clear();
generatedSourceFileObjects.clear();
generatedClasses.clear();
}
/**
* Debugging function to display internal state.
*/
public void displayState() {
PrintWriter xout = context.get(Log.outKey);
xout.println("File Object History : " + fileObjectHistory);
xout.println("Open Type Names : " + openTypeNames);
xout.println("Gen. Src Names : " + generatedSourceNames);
xout.println("Gen. Cls Names : " + generatedClasses.keySet());
xout.println("Agg. Gen. Src Names : " + aggregateGeneratedSourceNames);
xout.println("Agg. Gen. Cls Names : " + aggregateGeneratedClassNames);
}
public String toString() {
return "javac Filer";
}
/**
* Upon close, register files opened by create{Source, Class}File
* for annotation processing.
*/
private void closeFileObject(String typeName, FileObject fileObject) {
/*
* If typeName is non-null, the file object was opened as a
* source or class file by the user. If a file was opened as
* a resource, typeName will be null and the file is *not*
* subject to annotation processing.
*/
if ((typeName != null)) {
if (!(fileObject instanceof JavaFileObject))
throw new AssertionError("JavaFileOject not found for " + fileObject);
JavaFileObject javaFileObject = (JavaFileObject)fileObject;
switch(javaFileObject.getKind()) {
case SOURCE:
generatedSourceNames.add(typeName);
generatedSourceFileObjects.add(javaFileObject);
openTypeNames.remove(typeName);
break;
case CLASS:
generatedClasses.put(typeName, javaFileObject);
openTypeNames.remove(typeName);
break;
default:
break;
}
}
}
}

View File

@@ -0,0 +1,187 @@
/*
* 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.processing;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
import javax.lang.model.element.*;
import javax.tools.JavaFileObject;
import javax.tools.Diagnostic;
import javax.annotation.processing.*;
/**
* An implementation of the Messager built on top of log.
*
* <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 JavacMessager implements Messager {
Log log;
JavacProcessingEnvironment processingEnv;
int errorCount = 0;
int warningCount = 0;
JavacMessager(Context context, JavacProcessingEnvironment processingEnv) {
log = Log.instance(context);
this.processingEnv = processingEnv;
}
// processingEnv.getElementUtils()
public void printMessage(Diagnostic.Kind kind, CharSequence msg) {
printMessage(kind, msg, null, null, null);
}
public void printMessage(Diagnostic.Kind kind, CharSequence msg,
Element e) {
printMessage(kind, msg, e, null, null);
}
/**
* Prints a message of the specified kind at the location of the
* annotation mirror of the annotated element.
*
* @param kind the kind of message
* @param msg the message, or an empty string if none
* @param e the annotated element
* @param a the annotation to use as a position hint
*/
public void printMessage(Diagnostic.Kind kind, CharSequence msg,
Element e, AnnotationMirror a) {
printMessage(kind, msg, e, a, null);
}
/**
* Prints a message of the specified kind at the location of the
* annotation value inside the annotation mirror of the annotated
* element.
*
* @param kind the kind of message
* @param msg the message, or an empty string if none
* @param e the annotated element
* @param a the annotation containing the annotaiton value
* @param v the annotation value to use as a position hint
*/
public void printMessage(Diagnostic.Kind kind, CharSequence msg,
Element e, AnnotationMirror a, AnnotationValue v) {
JavaFileObject oldSource = null;
JavaFileObject newSource = null;
JCDiagnostic.DiagnosticPosition pos = null;
JavacElements elemUtils = processingEnv.getElementUtils();
Pair<JCTree, JCCompilationUnit> treeTop = elemUtils.getTreeAndTopLevel(e, a, v);
if (treeTop != null) {
newSource = treeTop.snd.sourcefile;
if (newSource != null) {
// save the old version and reinstate it later
oldSource = log.useSource(newSource);
pos = treeTop.fst.pos();
}
}
try {
switch (kind) {
case ERROR:
errorCount++;
boolean prev = log.multipleErrors;
log.multipleErrors = true;
try {
log.error(pos, "proc.messager", msg.toString());
} finally {
log.multipleErrors = prev;
}
break;
case WARNING:
warningCount++;
log.warning(pos, "proc.messager", msg.toString());
break;
case MANDATORY_WARNING:
warningCount++;
log.mandatoryWarning(pos, "proc.messager", msg.toString());
break;
default:
log.note(pos, "proc.messager", msg.toString());
break;
}
} finally {
// reinstate the saved version, only if it was saved earlier
if (newSource != null)
log.useSource(oldSource);
}
}
/**
* Prints an error message.
* Equivalent to {@code printError(null, msg)}.
* @param msg the message, or an empty string if none
*/
public void printError(String msg) {
printMessage(Diagnostic.Kind.ERROR, msg);
}
/**
* Prints a warning message.
* Equivalent to {@code printWarning(null, msg)}.
* @param msg the message, or an empty string if none
*/
public void printWarning(String msg) {
printMessage(Diagnostic.Kind.WARNING, msg);
}
/**
* Prints a notice.
* @param msg the message, or an empty string if none
*/
public void printNotice(String msg) {
printMessage(Diagnostic.Kind.NOTE, msg);
}
public boolean errorRaised() {
return errorCount > 0;
}
public int errorCount() {
return errorCount;
}
public int warningCount() {
return warningCount;
}
public void newRound(Context context) {
log = Log.instance(context);
errorCount = 0;
}
public String toString() {
return "javac Messager";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
/*
* Copyright (c) 2005, 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.processing;
import java.lang.annotation.Annotation;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.lang.model.util.*;
import java.util.*;
/**
* Object providing state about a prior round of annotation processing.
*
* <p>The methods in this class do not take type annotations into account,
* as target types, not java elements.
*
* <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 JavacRoundEnvironment implements RoundEnvironment {
// Default equals and hashCode methods are okay.
private final boolean processingOver;
private final boolean errorRaised;
private final ProcessingEnvironment processingEnv;
// Caller must pass in an immutable set
private final Set<? extends Element> rootElements;
JavacRoundEnvironment(boolean processingOver,
boolean errorRaised,
Set<? extends Element> rootElements,
ProcessingEnvironment processingEnv) {
this.processingOver = processingOver;
this.errorRaised = errorRaised;
this.rootElements = rootElements;
this.processingEnv = processingEnv;
}
public String toString() {
return String.format("[errorRaised=%b, rootElements=%s, processingOver=%b]",
errorRaised,
rootElements,
processingOver);
}
public boolean processingOver() {
return processingOver;
}
/**
* Returns {@code true} if an error was raised in the prior round
* of processing; returns {@code false} otherwise.
*
* @return {@code true} if an error was raised in the prior round
* of processing; returns {@code false} otherwise.
*/
public boolean errorRaised() {
return errorRaised;
}
/**
* Returns the type elements specified by the prior round.
*
* @return the types elements specified by the prior round, or an
* empty set if there were none
*/
public Set<? extends Element> getRootElements() {
return rootElements;
}
private static final String NOT_AN_ANNOTATION_TYPE =
"The argument does not represent an annotation type: ";
/**
* Returns the elements annotated with the given annotation type.
* Only type elements <i>included</i> in this round of annotation
* processing, or declarations of members, parameters, or type
* parameters declared within those, are returned. Included type
* elements are {@linkplain #getRootElements specified
* types} and any types nested within them.
*
* @param a annotation type being requested
* @return the elements annotated with the given annotation type,
* or an empty set if there are none
*/
public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) {
Set<Element> result = Collections.emptySet();
if (a.getKind() != ElementKind.ANNOTATION_TYPE)
throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
ElementScanner8<Set<Element>, TypeElement> scanner =
new AnnotationSetScanner(result);
for (Element element : rootElements)
result = scanner.scan(element, a);
return result;
}
// Could be written as a local class inside getElementsAnnotatedWith
private class AnnotationSetScanner extends
ElementScanner8<Set<Element>, TypeElement> {
// Insertion-order preserving set
Set<Element> annotatedElements = new LinkedHashSet<Element>();
AnnotationSetScanner(Set<Element> defaultSet) {
super(defaultSet);
}
@Override
public Set<Element> visitType(TypeElement e, TypeElement p) {
// Type parameters are not considered to be enclosed by a type
scan(e.getTypeParameters(), p);
return super.visitType(e, p);
}
@Override
public Set<Element> visitExecutable(ExecutableElement e, TypeElement p) {
// Type parameters are not considered to be enclosed by an executable
scan(e.getTypeParameters(), p);
return super.visitExecutable(e, p);
}
@Override
public Set<Element> scan(Element e, TypeElement p) {
java.util.List<? extends AnnotationMirror> annotationMirrors =
processingEnv.getElementUtils().getAllAnnotationMirrors(e);
for (AnnotationMirror annotationMirror : annotationMirrors) {
if (p.equals(annotationMirror.getAnnotationType().asElement()))
annotatedElements.add(e);
}
e.accept(this, p);
return annotatedElements;
}
}
/**
* {@inheritdoc}
*/
public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
if (!a.isAnnotation())
throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
String name = a.getCanonicalName();
if (name == null)
return Collections.emptySet();
else {
TypeElement annotationType = processingEnv.getElementUtils().getTypeElement(name);
if (annotationType == null)
return Collections.emptySet();
else
return getElementsAnnotatedWith(annotationType);
}
}
}

View File

@@ -0,0 +1,545 @@
/*
* 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.processing;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import static javax.lang.model.element.ElementKind.*;
import static javax.lang.model.element.NestingKind.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.*;
import com.sun.tools.javac.util.StringUtils;
/**
* A processor which prints out elements. Used to implement the
* -Xprint option; the included visitor class is used to implement
* Elements.printElements.
*
* <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>
*/
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class PrintingProcessor extends AbstractProcessor {
PrintWriter writer;
public PrintingProcessor() {
super();
writer = new PrintWriter(System.out);
}
public void setWriter(Writer w) {
writer = new PrintWriter(w);
}
@Override
public boolean process(Set<? extends TypeElement> tes,
RoundEnvironment renv) {
for(Element element : renv.getRootElements()) {
print(element);
}
// Just print the elements, nothing more to do.
return true;
}
void print(Element element) {
new PrintingElementVisitor(writer, processingEnv.getElementUtils()).
visit(element).flush();
}
/**
* Used for the -Xprint option and called by Elements.printElements
*/
public static class PrintingElementVisitor
extends SimpleElementVisitor8<PrintingElementVisitor, Boolean> {
int indentation; // Indentation level;
final PrintWriter writer;
final Elements elementUtils;
public PrintingElementVisitor(Writer w, Elements elementUtils) {
super();
this.writer = new PrintWriter(w);
this.elementUtils = elementUtils;
indentation = 0;
}
@Override
protected PrintingElementVisitor defaultAction(Element e, Boolean newLine) {
if (newLine != null && newLine)
writer.println();
printDocComment(e);
printModifiers(e);
return this;
}
@Override
public PrintingElementVisitor visitExecutable(ExecutableElement e, Boolean p) {
ElementKind kind = e.getKind();
if (kind != STATIC_INIT &&
kind != INSTANCE_INIT) {
Element enclosing = e.getEnclosingElement();
// Don't print out the constructor of an anonymous class
if (kind == CONSTRUCTOR &&
enclosing != null &&
NestingKind.ANONYMOUS ==
// Use an anonymous class to determine anonymity!
(new SimpleElementVisitor7<NestingKind, Void>() {
@Override
public NestingKind visitType(TypeElement e, Void p) {
return e.getNestingKind();
}
}).visit(enclosing))
return this;
defaultAction(e, true);
printFormalTypeParameters(e, true);
switch(kind) {
case CONSTRUCTOR:
// Print out simple name of the class
writer.print(e.getEnclosingElement().getSimpleName());
break;
case METHOD:
writer.print(e.getReturnType().toString());
writer.print(" ");
writer.print(e.getSimpleName().toString());
break;
}
writer.print("(");
printParameters(e);
writer.print(")");
AnnotationValue defaultValue = e.getDefaultValue();
if (defaultValue != null)
writer.print(" default " + defaultValue);
printThrows(e);
writer.println(";");
}
return this;
}
@Override
public PrintingElementVisitor visitType(TypeElement e, Boolean p) {
ElementKind kind = e.getKind();
NestingKind nestingKind = e.getNestingKind();
if (NestingKind.ANONYMOUS == nestingKind) {
// Print out an anonymous class in the style of a
// class instance creation expression rather than a
// class declaration.
writer.print("new ");
// If the anonymous class implements an interface
// print that name, otherwise print the superclass.
List<? extends TypeMirror> interfaces = e.getInterfaces();
if (!interfaces.isEmpty())
writer.print(interfaces.get(0));
else
writer.print(e.getSuperclass());
writer.print("(");
// Anonymous classes that implement an interface can't
// have any constructor arguments.
if (interfaces.isEmpty()) {
// Print out the parameter list from the sole
// constructor. For now, don't try to elide any
// synthetic parameters by determining if the
// anonymous class is in a static context, etc.
List<? extends ExecutableElement> constructors =
ElementFilter.constructorsIn(e.getEnclosedElements());
if (!constructors.isEmpty())
printParameters(constructors.get(0));
}
writer.print(")");
} else {
if (nestingKind == TOP_LEVEL) {
PackageElement pkg = elementUtils.getPackageOf(e);
if (!pkg.isUnnamed())
writer.print("package " + pkg.getQualifiedName() + ";\n");
}
defaultAction(e, true);
switch(kind) {
case ANNOTATION_TYPE:
writer.print("@interface");
break;
default:
writer.print(StringUtils.toLowerCase(kind.toString()));
}
writer.print(" ");
writer.print(e.getSimpleName());
printFormalTypeParameters(e, false);
// Print superclass information if informative
if (kind == CLASS) {
TypeMirror supertype = e.getSuperclass();
if (supertype.getKind() != TypeKind.NONE) {
TypeElement e2 = (TypeElement)
((DeclaredType) supertype).asElement();
if (e2.getSuperclass().getKind() != TypeKind.NONE)
writer.print(" extends " + supertype);
}
}
printInterfaces(e);
}
writer.println(" {");
indentation++;
if (kind == ENUM) {
List<Element> enclosedElements =
new ArrayList<Element>(e.getEnclosedElements());
// Handle any enum constants specially before other entities.
List<Element> enumConstants = new ArrayList<Element>();
for(Element element : enclosedElements) {
if (element.getKind() == ENUM_CONSTANT)
enumConstants.add(element);
}
if (!enumConstants.isEmpty()) {
int i;
for(i = 0; i < enumConstants.size()-1; i++) {
this.visit(enumConstants.get(i), true);
writer.print(",");
}
this.visit(enumConstants.get(i), true);
writer.println(";\n");
enclosedElements.removeAll(enumConstants);
}
for(Element element : enclosedElements)
this.visit(element);
} else {
for(Element element : e.getEnclosedElements())
this.visit(element);
}
indentation--;
indent();
writer.println("}");
return this;
}
@Override
public PrintingElementVisitor visitVariable(VariableElement e, Boolean newLine) {
ElementKind kind = e.getKind();
defaultAction(e, newLine);
if (kind == ENUM_CONSTANT)
writer.print(e.getSimpleName());
else {
writer.print(e.asType().toString() + " " + e.getSimpleName() );
Object constantValue = e.getConstantValue();
if (constantValue != null) {
writer.print(" = ");
writer.print(elementUtils.getConstantExpression(constantValue));
}
writer.println(";");
}
return this;
}
@Override
public PrintingElementVisitor visitTypeParameter(TypeParameterElement e, Boolean p) {
writer.print(e.getSimpleName());
return this;
}
// Should we do more here?
@Override
public PrintingElementVisitor visitPackage(PackageElement e, Boolean p) {
defaultAction(e, false);
if (!e.isUnnamed())
writer.println("package " + e.getQualifiedName() + ";");
else
writer.println("// Unnamed package");
return this;
}
public void flush() {
writer.flush();
}
private void printDocComment(Element e) {
String docComment = elementUtils.getDocComment(e);
if (docComment != null) {
// Break comment into lines
java.util.StringTokenizer st = new StringTokenizer(docComment,
"\n\r");
indent();
writer.println("/**");
while(st.hasMoreTokens()) {
indent();
writer.print(" *");
writer.println(st.nextToken());
}
indent();
writer.println(" */");
}
}
private void printModifiers(Element e) {
ElementKind kind = e.getKind();
if (kind == PARAMETER) {
printAnnotationsInline(e);
} else {
printAnnotations(e);
indent();
}
if (kind == ENUM_CONSTANT)
return;
Set<Modifier> modifiers = new LinkedHashSet<Modifier>();
modifiers.addAll(e.getModifiers());
switch (kind) {
case ANNOTATION_TYPE:
case INTERFACE:
modifiers.remove(Modifier.ABSTRACT);
break;
case ENUM:
modifiers.remove(Modifier.FINAL);
modifiers.remove(Modifier.ABSTRACT);
break;
case METHOD:
case FIELD:
Element enclosingElement = e.getEnclosingElement();
if (enclosingElement != null &&
enclosingElement.getKind().isInterface()) {
modifiers.remove(Modifier.PUBLIC);
modifiers.remove(Modifier.ABSTRACT); // only for methods
modifiers.remove(Modifier.STATIC); // only for fields
modifiers.remove(Modifier.FINAL); // only for fields
}
break;
}
for(Modifier m: modifiers) {
writer.print(m.toString() + " ");
}
}
private void printFormalTypeParameters(Parameterizable e,
boolean pad) {
List<? extends TypeParameterElement> typeParams = e.getTypeParameters();
if (typeParams.size() > 0) {
writer.print("<");
boolean first = true;
for(TypeParameterElement tpe: typeParams) {
if (!first)
writer.print(", ");
printAnnotationsInline(tpe);
writer.print(tpe.toString());
first = false;
}
writer.print(">");
if (pad)
writer.print(" ");
}
}
private void printAnnotationsInline(Element e) {
List<? extends AnnotationMirror> annots = e.getAnnotationMirrors();
for(AnnotationMirror annotationMirror : annots) {
writer.print(annotationMirror);
writer.print(" ");
}
}
private void printAnnotations(Element e) {
List<? extends AnnotationMirror> annots = e.getAnnotationMirrors();
for(AnnotationMirror annotationMirror : annots) {
indent();
writer.println(annotationMirror);
}
}
// TODO: Refactor
private void printParameters(ExecutableElement e) {
List<? extends VariableElement> parameters = e.getParameters();
int size = parameters.size();
switch (size) {
case 0:
break;
case 1:
for(VariableElement parameter: parameters) {
printModifiers(parameter);
if (e.isVarArgs() ) {
TypeMirror tm = parameter.asType();
if (tm.getKind() != TypeKind.ARRAY)
throw new AssertionError("Var-args parameter is not an array type: " + tm);
writer.print((ArrayType.class.cast(tm)).getComponentType() );
writer.print("...");
} else
writer.print(parameter.asType());
writer.print(" " + parameter.getSimpleName());
}
break;
default:
{
int i = 1;
for(VariableElement parameter: parameters) {
if (i == 2)
indentation++;
if (i > 1)
indent();
printModifiers(parameter);
if (i == size && e.isVarArgs() ) {
TypeMirror tm = parameter.asType();
if (tm.getKind() != TypeKind.ARRAY)
throw new AssertionError("Var-args parameter is not an array type: " + tm);
writer.print((ArrayType.class.cast(tm)).getComponentType() );
writer.print("...");
} else
writer.print(parameter.asType());
writer.print(" " + parameter.getSimpleName());
if (i < size)
writer.println(",");
i++;
}
if (parameters.size() >= 2)
indentation--;
}
break;
}
}
private void printInterfaces(TypeElement e) {
ElementKind kind = e.getKind();
if(kind != ANNOTATION_TYPE) {
List<? extends TypeMirror> interfaces = e.getInterfaces();
if (interfaces.size() > 0) {
writer.print((kind.isClass() ? " implements" : " extends"));
boolean first = true;
for(TypeMirror interf: interfaces) {
if (!first)
writer.print(",");
writer.print(" ");
writer.print(interf.toString());
first = false;
}
}
}
}
private void printThrows(ExecutableElement e) {
List<? extends TypeMirror> thrownTypes = e.getThrownTypes();
final int size = thrownTypes.size();
if (size != 0) {
writer.print(" throws");
int i = 1;
for(TypeMirror thrownType: thrownTypes) {
if (i == 1)
writer.print(" ");
if (i == 2)
indentation++;
if (i >= 2)
indent();
writer.print(thrownType);
if (i != size)
writer.println(", ");
i++;
}
if (size >= 2)
indentation--;
}
}
private static final String [] spaces = {
"",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" "
};
private void indent() {
int indentation = this.indentation;
if (indentation < 0)
return;
final int maxIndex = spaces.length - 1;
while (indentation > maxIndex) {
writer.print(spaces[maxIndex]);
indentation -= maxIndex;
}
writer.print(spaces[indentation]);
}
}
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2006, 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.processing;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Utility class to determine if a service can be found on the
* path that might be used to create a class loader.
*
* <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>
*
*/
// based on sun.misc.Service
class ServiceProxy {
static class ServiceConfigurationError extends Error {
static final long serialVersionUID = 7732091036771098303L;
ServiceConfigurationError(String msg) {
super(msg);
}
}
private static final String prefix = "META-INF/services/";
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 the content of the given URL as a provider-configuration file.
*
* @param service
* The service class for which providers are being sought;
* used to construct error detail strings
*
* @param u
* The URL naming the configuration file to be parsed
*
* @return true if the name of a service is found
*
* @throws ServiceConfigurationError
* If an I/O error occurs while reading from the given URL, or
* if a configuration-file format error is detected
*/
private static boolean parse(Class<?> service, URL u) throws ServiceConfigurationError {
InputStream in = null;
BufferedReader r = null;
try {
in = u.openStream();
r = new BufferedReader(new InputStreamReader(in, "utf-8"));
int lc = 1;
String ln;
while ((ln = r.readLine()) != null) {
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);
}
return true;
}
}
} catch (FileNotFoundException x) {
return false;
} catch (IOException x) {
fail(service, ": " + x);
} finally {
try {
if (r != null) r.close();
} catch (IOException y) {
fail(service, ": " + y);
}
try {
if (in != null) in.close();
} catch (IOException y) {
fail(service, ": " + y);
}
}
return false;
}
/**
* Return true if a description for at least one service is found in the
* service configuration files in the given URLs.
*/
public static boolean hasService(Class<?> service, URL[] urls)
throws ServiceConfigurationError {
for (URL url: urls) {
try {
String fullName = prefix + service.getName();
URL u = new URL(url, fullName);
boolean found = parse(service, u);
if (found)
return true;
} catch (MalformedURLException e) {
// should not happen; ignore it if it does
}
}
return false;
}
}