ModuleFinder.java revision 3294:9adfb22ff08f
1176669Spiso/* 2176669Spiso * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3176669Spiso * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4176669Spiso * 5176669Spiso * This code is free software; you can redistribute it and/or modify it 6176669Spiso * under the terms of the GNU General Public License version 2 only, as 7176669Spiso * published by the Free Software Foundation. Oracle designates this 8176669Spiso * particular file as subject to the "Classpath" exception as provided 9176669Spiso * by Oracle in the LICENSE file that accompanied this code. 10176669Spiso * 11176669Spiso * This code is distributed in the hope that it will be useful, but WITHOUT 12176669Spiso * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13176669Spiso * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14176669Spiso * version 2 for more details (a copy is included in the LICENSE file that 15176669Spiso * accompanied this code). 16176669Spiso * 17176669Spiso * You should have received a copy of the GNU General Public License version 18176669Spiso * 2 along with this work; if not, write to the Free Software Foundation, 19176669Spiso * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20176669Spiso * 21176669Spiso * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22176669Spiso * or visit www.oracle.com if you need additional information or have any 23176669Spiso * questions. 24176669Spiso */ 25176669Spisopackage com.sun.tools.javac.code; 26176669Spiso 27176669Spisoimport java.io.IOException; 28176669Spisoimport java.util.Arrays; 29176669Spisoimport java.util.HashMap; 30176669Spisoimport java.util.Iterator; 31176669Spisoimport java.util.Map; 32176669Spisoimport java.util.NoSuchElementException; 33176669Spisoimport java.util.Set; 34176669Spiso 35176669Spisoimport javax.tools.JavaFileManager; 36176669Spisoimport javax.tools.JavaFileManager.Location; 37176669Spisoimport javax.tools.JavaFileObject; 38176669Spisoimport javax.tools.JavaFileObject.Kind; 39200580Sluigiimport javax.tools.StandardLocation; 40200580Sluigi 41176669Spisoimport com.sun.tools.javac.code.Symbol.CompletionFailure; 42176669Spisoimport com.sun.tools.javac.code.Symbol.ModuleSymbol; 43176669Spisoimport com.sun.tools.javac.resources.CompilerProperties.Errors; 44176669Spisoimport com.sun.tools.javac.resources.CompilerProperties.Fragments; 45176669Spisoimport com.sun.tools.javac.util.Context; 46176669Spisoimport com.sun.tools.javac.util.JCDiagnostic; 47176669Spisoimport com.sun.tools.javac.util.JCDiagnostic.Fragment; 48176669Spisoimport com.sun.tools.javac.util.List; 49176669Spisoimport com.sun.tools.javac.util.ListBuffer; 50176669Spisoimport com.sun.tools.javac.util.Log; 51176669Spisoimport com.sun.tools.javac.util.Name; 52243401Sglebiusimport com.sun.tools.javac.util.Names; 53243401Sglebiusimport com.sun.tools.javac.util.StringUtils; 54176669Spiso 55176669Spisoimport static com.sun.tools.javac.code.Kinds.Kind.*; 56255395Strociny 57176669Spiso/** 58200909Sluigi * This class provides operations to locate module definitions 59176669Spiso * from the source and class files on the paths provided to javac. 60176669Spiso * 61176669Spiso * <p><b>This is NOT part of any supported API. 62176669Spiso * If you write code that depends on this, you do so at your own risk. 63200897Sluigi * This code and its internal interfaces are subject to change or 64176669Spiso * deletion without notice.</b> 65255395Strociny */ 66255395Strocinypublic class ModuleFinder { 67200897Sluigi /** The context key for the module finder. */ 68200909Sluigi protected static final Context.Key<ModuleFinder> moduleFinderKey = new Context.Key<>(); 69176669Spiso 70200897Sluigi /** The log to use for verbose output. */ 71176669Spiso private final Log log; 72200909Sluigi 73200909Sluigi /** The symbol table. */ 74200909Sluigi private final Symtab syms; 75200909Sluigi 76200909Sluigi /** The name table. */ 77200909Sluigi private final Names names; 78200909Sluigi 79200909Sluigi private final ClassFinder classFinder; 80200909Sluigi 81200909Sluigi /** Access to files 82200909Sluigi */ 83176669Spiso private final JavaFileManager fileManager; 84200909Sluigi 85176669Spiso private final JCDiagnostic.Factory diags; 86200909Sluigi 87176669Spiso /** Get the ModuleFinder instance for this invocation. */ 88176669Spiso public static ModuleFinder instance(Context context) { 89200897Sluigi ModuleFinder instance = context.get(moduleFinderKey); 90200897Sluigi if (instance == null) 91200897Sluigi instance = new ModuleFinder(context); 92176669Spiso return instance; 93200897Sluigi } 94176669Spiso 95200897Sluigi /** Construct a new module finder. */ 96200909Sluigi protected ModuleFinder(Context context) { 97176669Spiso context.put(moduleFinderKey, this); 98200897Sluigi names = Names.instance(context); 99200897Sluigi syms = Symtab.instance(context); 100200909Sluigi fileManager = context.get(JavaFileManager.class); 101200909Sluigi log = Log.instance(context); 102200897Sluigi classFinder = ClassFinder.instance(context); 103200897Sluigi 104176669Spiso diags = JCDiagnostic.Factory.instance(context); 105176669Spiso } 106176669Spiso 107176669Spiso class ModuleLocationIterator implements Iterator<Set<Location>> { 108176669Spiso StandardLocation outer; 109176669Spiso Set<Location> next = null; 110176669Spiso 111176669Spiso Iterator<StandardLocation> outerIter = Arrays.asList( 112176669Spiso StandardLocation.MODULE_SOURCE_PATH, 113176669Spiso StandardLocation.UPGRADE_MODULE_PATH, 114176669Spiso StandardLocation.SYSTEM_MODULES, 115176669Spiso StandardLocation.MODULE_PATH 116176669Spiso ).iterator(); 117176669Spiso Iterator<Set<Location>> innerIter = null; 118176669Spiso 119176669Spiso @Override 120176669Spiso public boolean hasNext() { 121176669Spiso while (next == null) { 122176669Spiso while (innerIter == null || !innerIter.hasNext()) { 123176669Spiso if (outerIter.hasNext()) { 124176669Spiso outer = outerIter.next(); 125176669Spiso try { 126176669Spiso innerIter = fileManager.listModuleLocations(outer).iterator(); 127176669Spiso } catch (IOException e) { 128176669Spiso System.err.println("error listing module locations for " + outer + ": " + e); // FIXME 129176669Spiso } 130176669Spiso } else 131176669Spiso return false; 132176669Spiso } 133176669Spiso 134176669Spiso if (innerIter.hasNext()) 135176669Spiso next = innerIter.next(); 136200909Sluigi } 137176669Spiso return true; 138200909Sluigi } 139176669Spiso 140176669Spiso @Override 141176669Spiso public Set<Location> next() { 142176669Spiso hasNext(); 143220837Sglebius if (next != null) { 144176669Spiso Set<Location> result = next; 145176669Spiso next = null; 146176669Spiso return result; 147176669Spiso } 148176669Spiso throw new NoSuchElementException(); 149176669Spiso } 150176669Spiso 151176669Spiso } 152176669Spiso 153176669Spiso ModuleLocationIterator moduleLocationIterator = new ModuleLocationIterator(); 154176669Spiso 155176669Spiso public ModuleSymbol findModule(Name name) { 156176669Spiso return findModule(syms.enterModule(name)); 157176669Spiso } 158176669Spiso 159176669Spiso public ModuleSymbol findModule(ModuleSymbol msym) { 160176669Spiso if (msym.kind != ERR && msym.sourceLocation == null && msym.classLocation == null) { 161176669Spiso // fill in location 162176669Spiso List<ModuleSymbol> list = scanModulePath(msym); 163176669Spiso if (list.isEmpty()) { 164176669Spiso msym.kind = ERR; 165176669Spiso } 166176669Spiso } 167176669Spiso if (msym.kind != ERR && msym.module_info.sourcefile == null && msym.module_info.classfile == null) { 168176669Spiso // fill in module-info 169176669Spiso findModuleInfo(msym); 170176669Spiso } 171200909Sluigi return msym; 172176669Spiso } 173176669Spiso 174176669Spiso public List<ModuleSymbol> findAllModules() { 175176669Spiso List<ModuleSymbol> list = scanModulePath(null); 176176669Spiso for (ModuleSymbol msym: list) { 177176669Spiso if (msym.kind != ERR && msym.module_info.sourcefile == null && msym.module_info.classfile == null) { 178176669Spiso // fill in module-info 179176669Spiso findModuleInfo(msym); 180176669Spiso } 181176669Spiso } 182176669Spiso return list; 183176669Spiso } 184176669Spiso 185200909Sluigi public ModuleSymbol findSingleModule() { 186176669Spiso try { 187200909Sluigi JavaFileObject src_fo = getModuleInfoFromLocation(StandardLocation.SOURCE_PATH, Kind.SOURCE); 188200909Sluigi JavaFileObject class_fo = getModuleInfoFromLocation(StandardLocation.CLASS_OUTPUT, Kind.CLASS); 189200909Sluigi JavaFileObject fo = (src_fo == null) ? class_fo 190200909Sluigi : (class_fo == null) ? src_fo 191200909Sluigi : classFinder.preferredFileObject(src_fo, class_fo); 192200909Sluigi 193200909Sluigi ModuleSymbol msym; 194200909Sluigi if (fo == null) { 195200909Sluigi msym = syms.unnamedModule; 196200909Sluigi } else { 197200909Sluigi // Note: the following may trigger a re-entrant call to Modules.enter 198200909Sluigi// msym = new ModuleSymbol(); 199200909Sluigi// ClassSymbol info = new ClassSymbol(Flags.MODULE, names.module_info, msym); 200200909Sluigi// info.modle = msym; 201176669Spiso// info.classfile = fo; 202200897Sluigi// info.members_field = WriteableScope.create(info); 203176669Spiso// msym.module_info = info; 204176669Spiso msym = ModuleSymbol.create(null, names.module_info); 205176669Spiso msym.module_info.classfile = fo; 206244569Smelifaro msym.completer = sym -> classFinder.fillIn(msym.module_info); 207244569Smelifaro// // TODO: should we do the following here, or as soon as we find the name in 208244569Smelifaro// // the source or class file? 209244569Smelifaro// // Consider the case when the class/source path module shadows one on the 210244569Smelifaro// // module source path 211244569Smelifaro// if (syms.modules.get(msym.name) != null) { 212244569Smelifaro// // error: module already defined 213176669Spiso// System.err.println("ERROR: module already defined: " + msym); 214176669Spiso// } else { 215176669Spiso// syms.modules.put(msym.name, msym); 216176669Spiso// } 217176669Spiso } 218176669Spiso 219223080Sae msym.classLocation = StandardLocation.CLASS_OUTPUT; 220223080Sae return msym; 221176669Spiso 222176669Spiso } catch (IOException e) { 223176669Spiso throw new Error(e); // FIXME 224176669Spiso } 225200909Sluigi } 226200909Sluigi 227200909Sluigi private JavaFileObject getModuleInfoFromLocation(Location location, Kind kind) throws IOException { 228200909Sluigi if (!fileManager.hasLocation(location)) 229200909Sluigi return null; 230176669Spiso 231176669Spiso return fileManager.getJavaFileForInput(location, 232200909Sluigi names.module_info.toString(), 233176669Spiso kind); 234176669Spiso } 235200909Sluigi 236200909Sluigi private List<ModuleSymbol> scanModulePath(ModuleSymbol toFind) { 237200909Sluigi ListBuffer<ModuleSymbol> results = new ListBuffer<>(); 238200909Sluigi Map<Name, Location> namesInSet = new HashMap<>(); 239176669Spiso while (moduleLocationIterator.hasNext()) { 240200909Sluigi Set<Location> locns = (moduleLocationIterator.next()); 241200909Sluigi namesInSet.clear(); 242200909Sluigi for (Location l: locns) { 243200909Sluigi try { 244200909Sluigi Name n = names.fromString(fileManager.inferModuleName(l)); 245200909Sluigi if (namesInSet.put(n, l) == null) { 246176669Spiso ModuleSymbol msym = syms.enterModule(n); 247200909Sluigi if (msym.sourceLocation != null || msym.classLocation != null) { 248200909Sluigi // module has already been found, so ignore this instance 249200909Sluigi continue; 250200909Sluigi } 251200909Sluigi if (moduleLocationIterator.outer == StandardLocation.MODULE_SOURCE_PATH) { 252200909Sluigi msym.sourceLocation = l; 253200909Sluigi if (fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) { 254200909Sluigi msym.classLocation = fileManager.getModuleLocation(StandardLocation.CLASS_OUTPUT, msym.name.toString()); 255200909Sluigi } 256200909Sluigi } else { 257200909Sluigi msym.classLocation = l; 258200909Sluigi } 259200909Sluigi if (moduleLocationIterator.outer == StandardLocation.SYSTEM_MODULES || 260176669Spiso moduleLocationIterator.outer == StandardLocation.UPGRADE_MODULE_PATH) { 261176669Spiso msym.flags_field |= Flags.SYSTEM_MODULE; 262176669Spiso } 263176669Spiso if (toFind == msym || toFind == null) { 264200909Sluigi // Note: cannot return msym directly, because we must finish 265200909Sluigi // processing this set first 266176669Spiso results.add(msym); 267176669Spiso } 268176669Spiso } else { 269222806Sae log.error(Errors.DuplicateModuleOnPath( 270223080Sae getDescription(moduleLocationIterator.outer), n)); 271223080Sae } 272223080Sae } catch (IOException e) { 273223080Sae // skip location for now? log error? 274223080Sae } 275223080Sae } 276223080Sae if (toFind != null && results.nonEmpty()) 277223080Sae return results.toList(); 278223080Sae } 279223080Sae 280244569Smelifaro return results.toList(); 281223080Sae } 282223080Sae 283223080Sae private void findModuleInfo(ModuleSymbol msym) { 284223080Sae try { 285223080Sae JavaFileObject src_fo = (msym.sourceLocation == null) ? null 286223080Sae : fileManager.getJavaFileForInput(msym.sourceLocation, 287223080Sae names.module_info.toString(), Kind.SOURCE); 288223080Sae 289223080Sae JavaFileObject class_fo = (msym.classLocation == null) ? null 290223080Sae : fileManager.getJavaFileForInput(msym.classLocation, 291223080Sae names.module_info.toString(), Kind.CLASS); 292223080Sae 293223080Sae JavaFileObject fo = (src_fo == null) ? class_fo : 294223080Sae (class_fo == null) ? src_fo : 295223080Sae classFinder.preferredFileObject(src_fo, class_fo); 296223080Sae 297223080Sae if (fo == null) { 298223080Sae String moduleName = msym.sourceLocation == null && msym.classLocation != null ? 299223080Sae fileManager.inferModuleName(msym.classLocation) : null; 300223080Sae if (moduleName != null) { 301223080Sae msym.module_info.classfile = null; 302223080Sae msym.flags_field |= Flags.AUTOMATIC_MODULE; 303223080Sae } else { 304223080Sae msym.kind = ERR; 305223080Sae } 306223080Sae } else { 307222806Sae msym.module_info.classfile = fo; 308222806Sae msym.module_info.completer = new Symbol.Completer() { 309222806Sae @Override 310222806Sae public void complete(Symbol sym) throws CompletionFailure { 311222806Sae classFinder.fillIn(msym.module_info); 312222806Sae } 313222806Sae @Override 314222806Sae public String toString() { 315222806Sae return "ModuleInfoCompleter"; 316222806Sae } 317222806Sae }; 318223080Sae } 319176669Spiso } catch (IOException e) { 320176669Spiso msym.kind = ERR; 321176669Spiso } 322176669Spiso } 323176669Spiso 324222806Sae Fragment getDescription(StandardLocation l) { 325222806Sae switch (l) { 326232171Sae case MODULE_PATH: return Fragments.LocnModule_path; 327200909Sluigi case MODULE_SOURCE_PATH: return Fragments.LocnModule_source_path; 328176669Spiso case SYSTEM_MODULES: return Fragments.LocnSystem_modules; 329200909Sluigi case UPGRADE_MODULE_PATH: return Fragments.LocnUpgrade_module_path; 330200909Sluigi default: 331200909Sluigi throw new AssertionError(); 332176669Spiso } 333176669Spiso } 334200909Sluigi 335176669Spiso} 336200909Sluigi