src/share/classes/com/sun/tools/javac/processing/JavacFiler.java

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 1092
826ae6a2f27d
parent 0
959103a6100f
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.tools.javac.processing;
aoqi@0 27
aoqi@0 28 import java.io.Closeable;
aoqi@0 29 import java.io.FileNotFoundException;
aoqi@0 30 import java.io.InputStream;
aoqi@0 31 import java.io.OutputStream;
aoqi@0 32 import java.io.FilterOutputStream;
aoqi@0 33 import java.io.Reader;
aoqi@0 34 import java.io.Writer;
aoqi@0 35 import java.io.FilterWriter;
aoqi@0 36 import java.io.PrintWriter;
aoqi@0 37 import java.io.IOException;
aoqi@0 38 import java.util.*;
aoqi@0 39
aoqi@0 40 import static java.util.Collections.*;
aoqi@0 41
aoqi@0 42 import javax.annotation.processing.*;
aoqi@0 43 import javax.lang.model.SourceVersion;
aoqi@0 44 import javax.lang.model.element.NestingKind;
aoqi@0 45 import javax.lang.model.element.Modifier;
aoqi@0 46 import javax.lang.model.element.Element;
aoqi@0 47 import javax.tools.*;
aoqi@0 48 import javax.tools.JavaFileManager.Location;
aoqi@0 49
aoqi@0 50 import static javax.tools.StandardLocation.SOURCE_OUTPUT;
aoqi@0 51 import static javax.tools.StandardLocation.CLASS_OUTPUT;
aoqi@0 52
aoqi@0 53 import com.sun.tools.javac.code.Lint;
aoqi@0 54 import com.sun.tools.javac.util.*;
aoqi@0 55
aoqi@0 56 import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING;
aoqi@0 57
aoqi@0 58 /**
aoqi@0 59 * The FilerImplementation class must maintain a number of
aoqi@0 60 * constraints. First, multiple attempts to open the same path within
aoqi@0 61 * the same invocation of the tool results in an IOException being
aoqi@0 62 * thrown. For example, trying to open the same source file twice:
aoqi@0 63 *
aoqi@0 64 * <pre>
aoqi@0 65 * createSourceFile("foo.Bar")
aoqi@0 66 * ...
aoqi@0 67 * createSourceFile("foo.Bar")
aoqi@0 68 * </pre>
aoqi@0 69 *
aoqi@0 70 * is disallowed as is opening a text file that happens to have
aoqi@0 71 * the same name as a source file:
aoqi@0 72 *
aoqi@0 73 * <pre>
aoqi@0 74 * createSourceFile("foo.Bar")
aoqi@0 75 * ...
aoqi@0 76 * createTextFile(SOURCE_TREE, "foo", new File("Bar"), null)
aoqi@0 77 * </pre>
aoqi@0 78 *
aoqi@0 79 * <p>Additionally, creating a source file that corresponds to an
aoqi@0 80 * already created class file (or vice versa) also results in an
aoqi@0 81 * IOException since each type can only be created once. However, if
aoqi@0 82 * the Filer is used to create a text file named *.java that happens
aoqi@0 83 * to correspond to an existing class file, a warning is *not*
aoqi@0 84 * generated. Similarly, a warning is not generated for a binary file
aoqi@0 85 * named *.class and an existing source file.
aoqi@0 86 *
aoqi@0 87 * <p>The reason for this difference is that source files and class
aoqi@0 88 * files are registered with the tool and can get passed on as
aoqi@0 89 * declarations to the next round of processing. Files that are just
aoqi@0 90 * named *.java and *.class are not processed in that manner; although
aoqi@0 91 * having extra source files and class files on the source path and
aoqi@0 92 * class path can alter the behavior of the tool and any final
aoqi@0 93 * compile.
aoqi@0 94 *
aoqi@0 95 * <p><b>This is NOT part of any supported API.
aoqi@0 96 * If you write code that depends on this, you do so at your own risk.
aoqi@0 97 * This code and its internal interfaces are subject to change or
aoqi@0 98 * deletion without notice.</b>
aoqi@0 99 */
aoqi@0 100 public class JavacFiler implements Filer, Closeable {
aoqi@0 101 // TODO: Implement different transaction model for updating the
aoqi@0 102 // Filer's record keeping on file close.
aoqi@0 103
aoqi@0 104 private static final String ALREADY_OPENED =
aoqi@0 105 "Output stream or writer has already been opened.";
aoqi@0 106 private static final String NOT_FOR_READING =
aoqi@0 107 "FileObject was not opened for reading.";
aoqi@0 108 private static final String NOT_FOR_WRITING =
aoqi@0 109 "FileObject was not opened for writing.";
aoqi@0 110
aoqi@0 111 /**
aoqi@0 112 * Wrap a JavaFileObject to manage writing by the Filer.
aoqi@0 113 */
aoqi@0 114 private class FilerOutputFileObject extends ForwardingFileObject<FileObject> {
aoqi@0 115 private boolean opened = false;
aoqi@0 116 private String name;
aoqi@0 117
aoqi@0 118 FilerOutputFileObject(String name, FileObject fileObject) {
aoqi@0 119 super(fileObject);
aoqi@0 120 this.name = name;
aoqi@0 121 }
aoqi@0 122
aoqi@0 123 @Override
aoqi@0 124 public synchronized OutputStream openOutputStream() throws IOException {
aoqi@0 125 if (opened)
aoqi@0 126 throw new IOException(ALREADY_OPENED);
aoqi@0 127 opened = true;
aoqi@0 128 return new FilerOutputStream(name, fileObject);
aoqi@0 129 }
aoqi@0 130
aoqi@0 131 @Override
aoqi@0 132 public synchronized Writer openWriter() throws IOException {
aoqi@0 133 if (opened)
aoqi@0 134 throw new IOException(ALREADY_OPENED);
aoqi@0 135 opened = true;
aoqi@0 136 return new FilerWriter(name, fileObject);
aoqi@0 137 }
aoqi@0 138
aoqi@0 139 // Three anti-literacy methods
aoqi@0 140 @Override
aoqi@0 141 public InputStream openInputStream() throws IOException {
aoqi@0 142 throw new IllegalStateException(NOT_FOR_READING);
aoqi@0 143 }
aoqi@0 144
aoqi@0 145 @Override
aoqi@0 146 public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
aoqi@0 147 throw new IllegalStateException(NOT_FOR_READING);
aoqi@0 148 }
aoqi@0 149
aoqi@0 150 @Override
aoqi@0 151 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
aoqi@0 152 throw new IllegalStateException(NOT_FOR_READING);
aoqi@0 153 }
aoqi@0 154
aoqi@0 155 @Override
aoqi@0 156 public boolean delete() {
aoqi@0 157 return false;
aoqi@0 158 }
aoqi@0 159 }
aoqi@0 160
aoqi@0 161 private class FilerOutputJavaFileObject extends FilerOutputFileObject implements JavaFileObject {
aoqi@0 162 private final JavaFileObject javaFileObject;
aoqi@0 163 FilerOutputJavaFileObject(String name, JavaFileObject javaFileObject) {
aoqi@0 164 super(name, javaFileObject);
aoqi@0 165 this.javaFileObject = javaFileObject;
aoqi@0 166 }
aoqi@0 167
aoqi@0 168 public JavaFileObject.Kind getKind() {
aoqi@0 169 return javaFileObject.getKind();
aoqi@0 170 }
aoqi@0 171
aoqi@0 172 public boolean isNameCompatible(String simpleName,
aoqi@0 173 JavaFileObject.Kind kind) {
aoqi@0 174 return javaFileObject.isNameCompatible(simpleName, kind);
aoqi@0 175 }
aoqi@0 176
aoqi@0 177 public NestingKind getNestingKind() {
aoqi@0 178 return javaFileObject.getNestingKind();
aoqi@0 179 }
aoqi@0 180
aoqi@0 181 public Modifier getAccessLevel() {
aoqi@0 182 return javaFileObject.getAccessLevel();
aoqi@0 183 }
aoqi@0 184 }
aoqi@0 185
aoqi@0 186 /**
aoqi@0 187 * Wrap a JavaFileObject to manage reading by the Filer.
aoqi@0 188 */
aoqi@0 189 private class FilerInputFileObject extends ForwardingFileObject<FileObject> {
aoqi@0 190 FilerInputFileObject(FileObject fileObject) {
aoqi@0 191 super(fileObject);
aoqi@0 192 }
aoqi@0 193
aoqi@0 194 @Override
aoqi@0 195 public OutputStream openOutputStream() throws IOException {
aoqi@0 196 throw new IllegalStateException(NOT_FOR_WRITING);
aoqi@0 197 }
aoqi@0 198
aoqi@0 199 @Override
aoqi@0 200 public Writer openWriter() throws IOException {
aoqi@0 201 throw new IllegalStateException(NOT_FOR_WRITING);
aoqi@0 202 }
aoqi@0 203
aoqi@0 204 @Override
aoqi@0 205 public boolean delete() {
aoqi@0 206 return false;
aoqi@0 207 }
aoqi@0 208 }
aoqi@0 209
aoqi@0 210 private class FilerInputJavaFileObject extends FilerInputFileObject implements JavaFileObject {
aoqi@0 211 private final JavaFileObject javaFileObject;
aoqi@0 212 FilerInputJavaFileObject(JavaFileObject javaFileObject) {
aoqi@0 213 super(javaFileObject);
aoqi@0 214 this.javaFileObject = javaFileObject;
aoqi@0 215 }
aoqi@0 216
aoqi@0 217 public JavaFileObject.Kind getKind() {
aoqi@0 218 return javaFileObject.getKind();
aoqi@0 219 }
aoqi@0 220
aoqi@0 221 public boolean isNameCompatible(String simpleName,
aoqi@0 222 JavaFileObject.Kind kind) {
aoqi@0 223 return javaFileObject.isNameCompatible(simpleName, kind);
aoqi@0 224 }
aoqi@0 225
aoqi@0 226 public NestingKind getNestingKind() {
aoqi@0 227 return javaFileObject.getNestingKind();
aoqi@0 228 }
aoqi@0 229
aoqi@0 230 public Modifier getAccessLevel() {
aoqi@0 231 return javaFileObject.getAccessLevel();
aoqi@0 232 }
aoqi@0 233 }
aoqi@0 234
aoqi@0 235
aoqi@0 236 /**
aoqi@0 237 * Wrap a {@code OutputStream} returned from the {@code
aoqi@0 238 * JavaFileManager} to properly register source or class files
aoqi@0 239 * when they are closed.
aoqi@0 240 */
aoqi@0 241 private class FilerOutputStream extends FilterOutputStream {
aoqi@0 242 String typeName;
aoqi@0 243 FileObject fileObject;
aoqi@0 244 boolean closed = false;
aoqi@0 245
aoqi@0 246 /**
aoqi@0 247 * @param typeName name of class or {@code null} if just a
aoqi@0 248 * binary file
aoqi@0 249 */
aoqi@0 250 FilerOutputStream(String typeName, FileObject fileObject) throws IOException {
aoqi@0 251 super(fileObject.openOutputStream());
aoqi@0 252 this.typeName = typeName;
aoqi@0 253 this.fileObject = fileObject;
aoqi@0 254 }
aoqi@0 255
aoqi@0 256 public synchronized void close() throws IOException {
aoqi@0 257 if (!closed) {
aoqi@0 258 closed = true;
aoqi@0 259 /*
aoqi@0 260 * If an IOException occurs when closing the underlying
aoqi@0 261 * stream, still try to process the file.
aoqi@0 262 */
aoqi@0 263
aoqi@0 264 closeFileObject(typeName, fileObject);
aoqi@0 265 out.close();
aoqi@0 266 }
aoqi@0 267 }
aoqi@0 268 }
aoqi@0 269
aoqi@0 270 /**
aoqi@0 271 * Wrap a {@code Writer} returned from the {@code JavaFileManager}
aoqi@0 272 * to properly register source or class files when they are
aoqi@0 273 * closed.
aoqi@0 274 */
aoqi@0 275 private class FilerWriter extends FilterWriter {
aoqi@0 276 String typeName;
aoqi@0 277 FileObject fileObject;
aoqi@0 278 boolean closed = false;
aoqi@0 279
aoqi@0 280 /**
aoqi@0 281 * @param fileObject the fileObject to be written to
aoqi@0 282 * @param typeName name of source file or {@code null} if just a
aoqi@0 283 * text file
aoqi@0 284 */
aoqi@0 285 FilerWriter(String typeName, FileObject fileObject) throws IOException {
aoqi@0 286 super(fileObject.openWriter());
aoqi@0 287 this.typeName = typeName;
aoqi@0 288 this.fileObject = fileObject;
aoqi@0 289 }
aoqi@0 290
aoqi@0 291 public synchronized void close() throws IOException {
aoqi@0 292 if (!closed) {
aoqi@0 293 closed = true;
aoqi@0 294 /*
aoqi@0 295 * If an IOException occurs when closing the underlying
aoqi@0 296 * Writer, still try to process the file.
aoqi@0 297 */
aoqi@0 298
aoqi@0 299 closeFileObject(typeName, fileObject);
aoqi@0 300 out.close();
aoqi@0 301 }
aoqi@0 302 }
aoqi@0 303 }
aoqi@0 304
aoqi@0 305 JavaFileManager fileManager;
aoqi@0 306 Log log;
aoqi@0 307 Context context;
aoqi@0 308 boolean lastRound;
aoqi@0 309
aoqi@0 310 private final boolean lint;
aoqi@0 311
aoqi@0 312 /**
aoqi@0 313 * Logical names of all created files. This set must be
aoqi@0 314 * synchronized.
aoqi@0 315 */
aoqi@0 316 private final Set<FileObject> fileObjectHistory;
aoqi@0 317
aoqi@0 318 /**
aoqi@0 319 * Names of types that have had files created but not closed.
aoqi@0 320 */
aoqi@0 321 private final Set<String> openTypeNames;
aoqi@0 322
aoqi@0 323 /**
aoqi@0 324 * Names of source files closed in this round. This set must be
aoqi@0 325 * synchronized. Its iterators should preserve insertion order.
aoqi@0 326 */
aoqi@0 327 private Set<String> generatedSourceNames;
aoqi@0 328
aoqi@0 329 /**
aoqi@0 330 * Names and class files of the class files closed in this round.
aoqi@0 331 * This set must be synchronized. Its iterators should preserve
aoqi@0 332 * insertion order.
aoqi@0 333 */
aoqi@0 334 private final Map<String, JavaFileObject> generatedClasses;
aoqi@0 335
aoqi@0 336 /**
aoqi@0 337 * JavaFileObjects for source files closed in this round. This
aoqi@0 338 * set must be synchronized. Its iterators should preserve
aoqi@0 339 * insertion order.
aoqi@0 340 */
aoqi@0 341 private Set<JavaFileObject> generatedSourceFileObjects;
aoqi@0 342
aoqi@0 343 /**
aoqi@0 344 * Names of all created source files. Its iterators should
aoqi@0 345 * preserve insertion order.
aoqi@0 346 */
aoqi@0 347 private final Set<String> aggregateGeneratedSourceNames;
aoqi@0 348
aoqi@0 349 /**
aoqi@0 350 * Names of all created class files. Its iterators should
aoqi@0 351 * preserve insertion order.
aoqi@0 352 */
aoqi@0 353 private final Set<String> aggregateGeneratedClassNames;
aoqi@0 354
aoqi@0 355
aoqi@0 356 JavacFiler(Context context) {
aoqi@0 357 this.context = context;
aoqi@0 358 fileManager = context.get(JavaFileManager.class);
aoqi@0 359
aoqi@0 360 log = Log.instance(context);
aoqi@0 361
aoqi@0 362 fileObjectHistory = synchronizedSet(new LinkedHashSet<FileObject>());
aoqi@0 363 generatedSourceNames = synchronizedSet(new LinkedHashSet<String>());
aoqi@0 364 generatedSourceFileObjects = synchronizedSet(new LinkedHashSet<JavaFileObject>());
aoqi@0 365
aoqi@0 366 generatedClasses = synchronizedMap(new LinkedHashMap<String, JavaFileObject>());
aoqi@0 367
aoqi@0 368 openTypeNames = synchronizedSet(new LinkedHashSet<String>());
aoqi@0 369
aoqi@0 370 aggregateGeneratedSourceNames = new LinkedHashSet<String>();
aoqi@0 371 aggregateGeneratedClassNames = new LinkedHashSet<String>();
aoqi@0 372
aoqi@0 373 lint = (Lint.instance(context)).isEnabled(PROCESSING);
aoqi@0 374 }
aoqi@0 375
aoqi@0 376 public JavaFileObject createSourceFile(CharSequence name,
aoqi@0 377 Element... originatingElements) throws IOException {
aoqi@0 378 return createSourceOrClassFile(true, name.toString());
aoqi@0 379 }
aoqi@0 380
aoqi@0 381 public JavaFileObject createClassFile(CharSequence name,
aoqi@0 382 Element... originatingElements) throws IOException {
aoqi@0 383 return createSourceOrClassFile(false, name.toString());
aoqi@0 384 }
aoqi@0 385
aoqi@0 386 private JavaFileObject createSourceOrClassFile(boolean isSourceFile, String name) throws IOException {
aoqi@0 387 if (lint) {
aoqi@0 388 int periodIndex = name.lastIndexOf(".");
aoqi@0 389 if (periodIndex != -1) {
aoqi@0 390 String base = name.substring(periodIndex);
aoqi@0 391 String extn = (isSourceFile ? ".java" : ".class");
aoqi@0 392 if (base.equals(extn))
aoqi@0 393 log.warning("proc.suspicious.class.name", name, extn);
aoqi@0 394 }
aoqi@0 395 }
aoqi@0 396 checkNameAndExistence(name, isSourceFile);
aoqi@0 397 Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT);
aoqi@0 398 JavaFileObject.Kind kind = (isSourceFile ?
aoqi@0 399 JavaFileObject.Kind.SOURCE :
aoqi@0 400 JavaFileObject.Kind.CLASS);
aoqi@0 401
aoqi@0 402 JavaFileObject fileObject =
aoqi@0 403 fileManager.getJavaFileForOutput(loc, name, kind, null);
aoqi@0 404 checkFileReopening(fileObject, true);
aoqi@0 405
aoqi@0 406 if (lastRound)
aoqi@0 407 log.warning("proc.file.create.last.round", name);
aoqi@0 408
aoqi@0 409 if (isSourceFile)
aoqi@0 410 aggregateGeneratedSourceNames.add(name);
aoqi@0 411 else
aoqi@0 412 aggregateGeneratedClassNames.add(name);
aoqi@0 413 openTypeNames.add(name);
aoqi@0 414
aoqi@0 415 return new FilerOutputJavaFileObject(name, fileObject);
aoqi@0 416 }
aoqi@0 417
aoqi@0 418 public FileObject createResource(JavaFileManager.Location location,
aoqi@0 419 CharSequence pkg,
aoqi@0 420 CharSequence relativeName,
aoqi@0 421 Element... originatingElements) throws IOException {
aoqi@0 422 locationCheck(location);
aoqi@0 423
aoqi@0 424 String strPkg = pkg.toString();
aoqi@0 425 if (strPkg.length() > 0)
aoqi@0 426 checkName(strPkg);
aoqi@0 427
aoqi@0 428 FileObject fileObject =
aoqi@0 429 fileManager.getFileForOutput(location, strPkg,
aoqi@0 430 relativeName.toString(), null);
aoqi@0 431 checkFileReopening(fileObject, true);
aoqi@0 432
aoqi@0 433 if (fileObject instanceof JavaFileObject)
aoqi@0 434 return new FilerOutputJavaFileObject(null, (JavaFileObject)fileObject);
aoqi@0 435 else
aoqi@0 436 return new FilerOutputFileObject(null, fileObject);
aoqi@0 437 }
aoqi@0 438
aoqi@0 439 private void locationCheck(JavaFileManager.Location location) {
aoqi@0 440 if (location instanceof StandardLocation) {
aoqi@0 441 StandardLocation stdLoc = (StandardLocation) location;
aoqi@0 442 if (!stdLoc.isOutputLocation())
aoqi@0 443 throw new IllegalArgumentException("Resource creation not supported in location " +
aoqi@0 444 stdLoc);
aoqi@0 445 }
aoqi@0 446 }
aoqi@0 447
aoqi@0 448 public FileObject getResource(JavaFileManager.Location location,
aoqi@0 449 CharSequence pkg,
aoqi@0 450 CharSequence relativeName) throws IOException {
aoqi@0 451 String strPkg = pkg.toString();
aoqi@0 452 if (strPkg.length() > 0)
aoqi@0 453 checkName(strPkg);
aoqi@0 454
aoqi@0 455 // TODO: Only support reading resources in selected output
aoqi@0 456 // locations? Only allow reading of non-source, non-class
aoqi@0 457 // files from the supported input locations?
aoqi@0 458
aoqi@0 459 // In the following, getFileForInput is the "obvious" method
aoqi@0 460 // to use, but it does not have the "obvious" semantics for
aoqi@0 461 // SOURCE_OUTPUT and CLASS_OUTPUT. Conversely, getFileForOutput
aoqi@0 462 // does not have the correct semantics for any "path" location
aoqi@0 463 // with more than one component. So, for now, we use a hybrid
aoqi@0 464 // invocation.
aoqi@0 465 FileObject fileObject;
aoqi@0 466 if (location.isOutputLocation()) {
aoqi@0 467 fileObject = fileManager.getFileForOutput(location,
aoqi@0 468 pkg.toString(),
aoqi@0 469 relativeName.toString(),
aoqi@0 470 null);
aoqi@0 471 } else {
aoqi@0 472 fileObject = fileManager.getFileForInput(location,
aoqi@0 473 pkg.toString(),
aoqi@0 474 relativeName.toString());
aoqi@0 475 }
aoqi@0 476 if (fileObject == null) {
aoqi@0 477 String name = (pkg.length() == 0)
aoqi@0 478 ? relativeName.toString() : (pkg + "/" + relativeName);
aoqi@0 479 throw new FileNotFoundException(name);
aoqi@0 480 }
aoqi@0 481
aoqi@0 482 // If the path was already opened for writing, throw an exception.
aoqi@0 483 checkFileReopening(fileObject, false);
aoqi@0 484 return new FilerInputFileObject(fileObject);
aoqi@0 485 }
aoqi@0 486
aoqi@0 487 private void checkName(String name) throws FilerException {
aoqi@0 488 checkName(name, false);
aoqi@0 489 }
aoqi@0 490
aoqi@0 491 private void checkName(String name, boolean allowUnnamedPackageInfo) throws FilerException {
aoqi@0 492 if (!SourceVersion.isName(name) && !isPackageInfo(name, allowUnnamedPackageInfo)) {
aoqi@0 493 if (lint)
aoqi@0 494 log.warning("proc.illegal.file.name", name);
aoqi@0 495 throw new FilerException("Illegal name " + name);
aoqi@0 496 }
aoqi@0 497 }
aoqi@0 498
aoqi@0 499 private boolean isPackageInfo(String name, boolean allowUnnamedPackageInfo) {
aoqi@0 500 // Is the name of the form "package-info" or
aoqi@0 501 // "foo.bar.package-info"?
aoqi@0 502 final String PKG_INFO = "package-info";
aoqi@0 503 int periodIndex = name.lastIndexOf(".");
aoqi@0 504 if (periodIndex == -1) {
aoqi@0 505 return allowUnnamedPackageInfo ? name.equals(PKG_INFO) : false;
aoqi@0 506 } else {
aoqi@0 507 // "foo.bar.package-info." illegal
aoqi@0 508 String prefix = name.substring(0, periodIndex);
aoqi@0 509 String simple = name.substring(periodIndex+1);
aoqi@0 510 return SourceVersion.isName(prefix) && simple.equals(PKG_INFO);
aoqi@0 511 }
aoqi@0 512 }
aoqi@0 513
aoqi@0 514 private void checkNameAndExistence(String typename, boolean allowUnnamedPackageInfo) throws FilerException {
aoqi@0 515 // TODO: Check if type already exists on source or class path?
aoqi@0 516 // If so, use warning message key proc.type.already.exists
aoqi@0 517 checkName(typename, allowUnnamedPackageInfo);
aoqi@0 518 if (aggregateGeneratedSourceNames.contains(typename) ||
aoqi@0 519 aggregateGeneratedClassNames.contains(typename)) {
aoqi@0 520 if (lint)
aoqi@0 521 log.warning("proc.type.recreate", typename);
aoqi@0 522 throw new FilerException("Attempt to recreate a file for type " + typename);
aoqi@0 523 }
aoqi@0 524 }
aoqi@0 525
aoqi@0 526 /**
aoqi@0 527 * Check to see if the file has already been opened; if so, throw
aoqi@0 528 * an exception, otherwise add it to the set of files.
aoqi@0 529 */
aoqi@0 530 private void checkFileReopening(FileObject fileObject, boolean addToHistory) throws FilerException {
aoqi@0 531 for(FileObject veteran : fileObjectHistory) {
aoqi@0 532 if (fileManager.isSameFile(veteran, fileObject)) {
aoqi@0 533 if (lint)
aoqi@0 534 log.warning("proc.file.reopening", fileObject.getName());
aoqi@0 535 throw new FilerException("Attempt to reopen a file for path " + fileObject.getName());
aoqi@0 536 }
aoqi@0 537 }
aoqi@0 538 if (addToHistory)
aoqi@0 539 fileObjectHistory.add(fileObject);
aoqi@0 540 }
aoqi@0 541
aoqi@0 542 public boolean newFiles() {
aoqi@0 543 return (!generatedSourceNames.isEmpty())
aoqi@0 544 || (!generatedClasses.isEmpty());
aoqi@0 545 }
aoqi@0 546
aoqi@0 547 public Set<String> getGeneratedSourceNames() {
aoqi@0 548 return generatedSourceNames;
aoqi@0 549 }
aoqi@0 550
aoqi@0 551 public Set<JavaFileObject> getGeneratedSourceFileObjects() {
aoqi@0 552 return generatedSourceFileObjects;
aoqi@0 553 }
aoqi@0 554
aoqi@0 555 public Map<String, JavaFileObject> getGeneratedClasses() {
aoqi@0 556 return generatedClasses;
aoqi@0 557 }
aoqi@0 558
aoqi@0 559 public void warnIfUnclosedFiles() {
aoqi@0 560 if (!openTypeNames.isEmpty())
aoqi@0 561 log.warning("proc.unclosed.type.files", openTypeNames.toString());
aoqi@0 562 }
aoqi@0 563
aoqi@0 564 /**
aoqi@0 565 * Update internal state for a new round.
aoqi@0 566 */
aoqi@0 567 public void newRound(Context context) {
aoqi@0 568 this.context = context;
aoqi@0 569 this.log = Log.instance(context);
aoqi@0 570 clearRoundState();
aoqi@0 571 }
aoqi@0 572
aoqi@0 573 void setLastRound(boolean lastRound) {
aoqi@0 574 this.lastRound = lastRound;
aoqi@0 575 }
aoqi@0 576
aoqi@0 577 public void close() {
aoqi@0 578 clearRoundState();
aoqi@0 579 // Cross-round state
aoqi@0 580 fileObjectHistory.clear();
aoqi@0 581 openTypeNames.clear();
aoqi@0 582 aggregateGeneratedSourceNames.clear();
aoqi@0 583 aggregateGeneratedClassNames.clear();
aoqi@0 584 }
aoqi@0 585
aoqi@0 586 private void clearRoundState() {
aoqi@0 587 generatedSourceNames.clear();
aoqi@0 588 generatedSourceFileObjects.clear();
aoqi@0 589 generatedClasses.clear();
aoqi@0 590 }
aoqi@0 591
aoqi@0 592 /**
aoqi@0 593 * Debugging function to display internal state.
aoqi@0 594 */
aoqi@0 595 public void displayState() {
aoqi@0 596 PrintWriter xout = context.get(Log.outKey);
aoqi@0 597 xout.println("File Object History : " + fileObjectHistory);
aoqi@0 598 xout.println("Open Type Names : " + openTypeNames);
aoqi@0 599 xout.println("Gen. Src Names : " + generatedSourceNames);
aoqi@0 600 xout.println("Gen. Cls Names : " + generatedClasses.keySet());
aoqi@0 601 xout.println("Agg. Gen. Src Names : " + aggregateGeneratedSourceNames);
aoqi@0 602 xout.println("Agg. Gen. Cls Names : " + aggregateGeneratedClassNames);
aoqi@0 603 }
aoqi@0 604
aoqi@0 605 public String toString() {
aoqi@0 606 return "javac Filer";
aoqi@0 607 }
aoqi@0 608
aoqi@0 609 /**
aoqi@0 610 * Upon close, register files opened by create{Source, Class}File
aoqi@0 611 * for annotation processing.
aoqi@0 612 */
aoqi@0 613 private void closeFileObject(String typeName, FileObject fileObject) {
aoqi@0 614 /*
aoqi@0 615 * If typeName is non-null, the file object was opened as a
aoqi@0 616 * source or class file by the user. If a file was opened as
aoqi@0 617 * a resource, typeName will be null and the file is *not*
aoqi@0 618 * subject to annotation processing.
aoqi@0 619 */
aoqi@0 620 if ((typeName != null)) {
aoqi@0 621 if (!(fileObject instanceof JavaFileObject))
aoqi@0 622 throw new AssertionError("JavaFileOject not found for " + fileObject);
aoqi@0 623 JavaFileObject javaFileObject = (JavaFileObject)fileObject;
aoqi@0 624 switch(javaFileObject.getKind()) {
aoqi@0 625 case SOURCE:
aoqi@0 626 generatedSourceNames.add(typeName);
aoqi@0 627 generatedSourceFileObjects.add(javaFileObject);
aoqi@0 628 openTypeNames.remove(typeName);
aoqi@0 629 break;
aoqi@0 630
aoqi@0 631 case CLASS:
aoqi@0 632 generatedClasses.put(typeName, javaFileObject);
aoqi@0 633 openTypeNames.remove(typeName);
aoqi@0 634 break;
aoqi@0 635
aoqi@0 636 default:
aoqi@0 637 break;
aoqi@0 638 }
aoqi@0 639 }
aoqi@0 640 }
aoqi@0 641
aoqi@0 642 }

mercurial