Mergin jlahoda's fix of #8182450: javac aborts when generating ct.sym intermittently - Initialize the module system model even in presence of missing/broken module-infos; BadClassFiles should not immediatelly abort compilation anymore, but should be handled as if the classfile did not exist.
2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
25 package com.sun.tools.javac.code;
27 import java.io.IOException;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.Iterator;
32 import java.util.NoSuchElementException;
35 import javax.tools.JavaFileManager;
36 import javax.tools.JavaFileManager.Location;
37 import javax.tools.JavaFileObject;
38 import javax.tools.JavaFileObject.Kind;
39 import javax.tools.StandardLocation;
41 import com.sun.tools.javac.code.Symbol.ClassSymbol;
42 import com.sun.tools.javac.code.Symbol.Completer;
43 import com.sun.tools.javac.code.Symbol.CompletionFailure;
44 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
45 import com.sun.tools.javac.jvm.ModuleNameReader;
46 import com.sun.tools.javac.jvm.ModuleNameReader.BadClassFile;
47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
48 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
49 import com.sun.tools.javac.util.Assert;
50 import com.sun.tools.javac.util.Context;
51 import com.sun.tools.javac.util.JCDiagnostic;
52 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
53 import com.sun.tools.javac.util.List;
54 import com.sun.tools.javac.util.ListBuffer;
55 import com.sun.tools.javac.util.Log;
56 import com.sun.tools.javac.util.Name;
57 import com.sun.tools.javac.util.Names;
59 import static com.sun.tools.javac.code.Kinds.Kind.*;
60 import com.sun.tools.javac.comp.Check;
63 * This class provides operations to locate module definitions
64 * from the source and class files on the paths provided to javac.
66 * <p><b>This is NOT part of any supported API.
67 * If you write code that depends on this, you do so at your own risk.
68 * This code and its internal interfaces are subject to change or
69 * deletion without notice.</b>
71 public class ModuleFinder {
72 /** The context key for the module finder. */
73 protected static final Context.Key<ModuleFinder> moduleFinderKey = new Context.Key<>();
75 /** The log to use for verbose output. */
76 private final Log log;
78 /** The symbol table. */
79 private final Symtab syms;
81 /** The name table. */
82 private final Names names;
84 private final ClassFinder classFinder;
85 private final Check chk;
89 private final JavaFileManager fileManager;
91 private final JCDiagnostic.Factory diags;
93 private ModuleNameReader moduleNameReader;
95 public ModuleNameFromSourceReader moduleNameFromSourceReader;
97 /** Get the ModuleFinder instance for this invocation. */
98 public static ModuleFinder instance(Context context) {
99 ModuleFinder instance = context.get(moduleFinderKey);
100 if (instance == null)
101 instance = new ModuleFinder(context);
105 /** Construct a new module finder. */
106 protected ModuleFinder(Context context) {
107 context.put(moduleFinderKey, this);
108 names = Names.instance(context);
109 syms = Symtab.instance(context);
110 fileManager = context.get(JavaFileManager.class);
111 log = Log.instance(context);
112 classFinder = ClassFinder.instance(context);
113 chk = Check.instance(context);
115 diags = JCDiagnostic.Factory.instance(context);
118 class ModuleLocationIterator implements Iterator<Set<Location>> {
119 StandardLocation outer;
120 Set<Location> next = null;
122 Iterator<StandardLocation> outerIter = Arrays.asList(
123 StandardLocation.MODULE_SOURCE_PATH,
124 StandardLocation.UPGRADE_MODULE_PATH,
125 StandardLocation.SYSTEM_MODULES,
126 StandardLocation.MODULE_PATH
128 Iterator<Set<Location>> innerIter = null;
131 public boolean hasNext() {
132 while (next == null) {
133 while (innerIter == null || !innerIter.hasNext()) {
134 if (outerIter.hasNext()) {
135 outer = outerIter.next();
137 innerIter = fileManager.listLocationsForModules(outer).iterator();
138 } catch (IOException e) {
139 System.err.println("error listing module locations for " + outer + ": " + e); // FIXME
145 if (innerIter.hasNext())
146 next = innerIter.next();
152 public Set<Location> next() {
155 Set<Location> result = next;
159 throw new NoSuchElementException();
164 ModuleLocationIterator moduleLocationIterator = new ModuleLocationIterator();
166 public ModuleSymbol findModule(Name name) {
167 return findModule(syms.enterModule(name));
170 public ModuleSymbol findModule(ModuleSymbol msym) {
171 if (msym.kind != ERR && msym.sourceLocation == null && msym.classLocation == null) {
173 List<ModuleSymbol> list = scanModulePath(msym);
174 if (list.isEmpty()) {
178 if (msym.kind != ERR && msym.module_info.sourcefile == null && msym.module_info.classfile == null) {
179 // fill in module-info
180 findModuleInfo(msym);
185 public List<ModuleSymbol> findAllModules() {
186 List<ModuleSymbol> list = scanModulePath(null);
187 for (ModuleSymbol msym: list) {
188 if (msym.kind != ERR && msym.module_info.sourcefile == null && msym.module_info.classfile == null) {
189 // fill in module-info
190 findModuleInfo(msym);
196 public ModuleSymbol findSingleModule() {
198 JavaFileObject src_fo = getModuleInfoFromLocation(StandardLocation.SOURCE_PATH, Kind.SOURCE);
199 JavaFileObject class_fo = getModuleInfoFromLocation(StandardLocation.CLASS_OUTPUT, Kind.CLASS);
200 JavaFileObject fo = (src_fo == null) ? class_fo
201 : (class_fo == null) ? src_fo
202 : classFinder.preferredFileObject(src_fo, class_fo);
206 msym = syms.unnamedModule;
209 msym = readModule(fo);
210 } catch (CompletionFailure ex) {
211 chk.completionError(null, ex);
212 msym = syms.unnamedModule;
217 if (msym.patchLocation == null) {
218 msym.classLocation = StandardLocation.CLASS_OUTPUT;
220 msym.patchOutputLocation = StandardLocation.CLASS_OUTPUT;
224 } catch (IOException e) {
225 throw new Error(e); // FIXME
229 private ModuleSymbol readModule(JavaFileObject fo) throws IOException {
231 switch (fo.getKind()) {
233 name = moduleNameFromSourceReader.readModuleName(fo);
236 diags.fragment("file.does.not.contain.module");
237 ClassSymbol errModuleInfo = syms.defineClass(names.module_info, syms.errModule);
238 throw new ClassFinder.BadClassFile(errModuleInfo, fo, diag, diags);
243 name = names.fromString(readModuleName(fo));
244 } catch (BadClassFile | IOException ex) {
245 //fillIn will report proper errors:
255 ModuleSymbol msym = syms.enterModule(name);
256 msym.module_info.classfile = fo;
257 if (fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH) && name != names.error) {
258 msym.patchLocation = fileManager.getLocationForModule(StandardLocation.PATCH_MODULE_PATH, name.toString());
260 if (msym.patchLocation != null) {
261 JavaFileObject patchFO = getModuleInfoFromLocation(StandardLocation.CLASS_OUTPUT, Kind.CLASS);
262 patchFO = preferredFileObject(getModuleInfoFromLocation(msym.patchLocation, Kind.CLASS), patchFO);
263 patchFO = preferredFileObject(getModuleInfoFromLocation(msym.patchLocation, Kind.SOURCE), patchFO);
265 if (patchFO != null) {
266 msym.module_info.classfile = patchFO;
271 msym.completer = Completer.NULL_COMPLETER;
272 classFinder.fillIn(msym.module_info);
277 private String readModuleName(JavaFileObject jfo) throws IOException, ModuleNameReader.BadClassFile {
278 if (moduleNameReader == null)
279 moduleNameReader = new ModuleNameReader();
280 return moduleNameReader.readModuleName(jfo);
283 private JavaFileObject getModuleInfoFromLocation(Location location, Kind kind) throws IOException {
284 if (location == null || !fileManager.hasLocation(location))
287 return fileManager.getJavaFileForInput(location,
288 names.module_info.toString(),
292 private List<ModuleSymbol> scanModulePath(ModuleSymbol toFind) {
293 ListBuffer<ModuleSymbol> results = new ListBuffer<>();
294 Map<Name, Location> namesInSet = new HashMap<>();
295 boolean multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH);
296 while (moduleLocationIterator.hasNext()) {
297 Set<Location> locns = (moduleLocationIterator.next());
299 for (Location l: locns) {
301 Name n = names.fromString(fileManager.inferModuleName(l));
302 if (namesInSet.put(n, l) == null) {
303 ModuleSymbol msym = syms.enterModule(n);
304 if (msym.sourceLocation != null || msym.classLocation != null) {
305 // module has already been found, so ignore this instance
308 if (fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH) &&
309 msym.patchLocation == null) {
311 fileManager.getLocationForModule(StandardLocation.PATCH_MODULE_PATH,
312 msym.name.toString());
313 if (msym.patchLocation != null &&
315 fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) {
316 msym.patchOutputLocation =
317 fileManager.getLocationForModule(StandardLocation.CLASS_OUTPUT,
318 msym.name.toString());
321 if (moduleLocationIterator.outer == StandardLocation.MODULE_SOURCE_PATH) {
322 msym.sourceLocation = l;
323 if (fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) {
325 fileManager.getLocationForModule(StandardLocation.CLASS_OUTPUT,
326 msym.name.toString());
329 msym.classLocation = l;
331 if (moduleLocationIterator.outer == StandardLocation.SYSTEM_MODULES ||
332 moduleLocationIterator.outer == StandardLocation.UPGRADE_MODULE_PATH) {
333 msym.flags_field |= Flags.SYSTEM_MODULE;
335 if (toFind == null ||
336 (toFind == msym && (msym.sourceLocation != null || msym.classLocation != null))) {
337 // Note: cannot return msym directly, because we must finish
338 // processing this set first
342 log.error(Errors.DuplicateModuleOnPath(
343 getDescription(moduleLocationIterator.outer), n));
345 } catch (IOException e) {
346 // skip location for now? log error?
349 if (toFind != null && results.nonEmpty())
350 return results.toList();
353 return results.toList();
356 private void findModuleInfo(ModuleSymbol msym) {
360 fo = getModuleInfoFromLocation(msym.patchOutputLocation, Kind.CLASS);
361 fo = preferredFileObject(getModuleInfoFromLocation(msym.patchLocation, Kind.CLASS), fo);
362 fo = preferredFileObject(getModuleInfoFromLocation(msym.patchLocation, Kind.SOURCE), fo);
365 fo = getModuleInfoFromLocation(msym.classLocation, Kind.CLASS);
366 fo = preferredFileObject(getModuleInfoFromLocation(msym.sourceLocation, Kind.SOURCE), fo);
370 String moduleName = msym.sourceLocation == null && msym.classLocation != null ?
371 fileManager.inferModuleName(msym.classLocation) : null;
372 if (moduleName != null) {
373 msym.module_info.classfile = null;
374 msym.flags_field |= Flags.AUTOMATIC_MODULE;
379 msym.module_info.classfile = fo;
380 msym.module_info.completer = new Symbol.Completer() {
382 public void complete(Symbol sym) throws CompletionFailure {
384 classFinder.fillIn(msym.module_info);
385 } catch (Exception ex) {
387 //make sure the module is initialized:
388 msym.directives = List.nil();
389 msym.exports = List.nil();
390 msym.provides = List.nil();
391 msym.requires = List.nil();
392 msym.uses = List.nil();
396 public String toString() {
397 return "ModuleInfoCompleter";
401 } catch (IOException e) {
406 private JavaFileObject preferredFileObject(JavaFileObject fo1, JavaFileObject fo2) {
407 if (fo1 == null) return fo2;
408 if (fo2 == null) return fo1;
409 return classFinder.preferredFileObject(fo1, fo2);
412 Fragment getDescription(StandardLocation l) {
414 case MODULE_PATH: return Fragments.LocnModule_path;
415 case MODULE_SOURCE_PATH: return Fragments.LocnModule_source_path;
416 case SYSTEM_MODULES: return Fragments.LocnSystem_modules;
417 case UPGRADE_MODULE_PATH: return Fragments.LocnUpgrade_module_path;
419 throw new AssertionError();
423 public interface ModuleNameFromSourceReader {
424 public Name readModuleName(JavaFileObject file);