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