diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index e488566..c1e9fce 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -359,28 +359,26 @@ final class FirstPass : ASTVisitor dec.accept(this); } - override void visit(const Module mod) - { - rootSymbol = allocateSemanticSymbol(null, CompletionKind.moduleName, - symbolFile); - currentSymbol = rootSymbol; - moduleScope = GCAllocator.instance.make!Scope(0, uint.max); - currentScope = moduleScope; - auto objectLocation = cache.resolveImportLocation("object"); - if (objectLocation is null) - warning("Could not locate object.d or object.di"); - else - { - auto objectImport = allocateSemanticSymbol(IMPORT_SYMBOL_NAME, - CompletionKind.importSymbol, objectLocation); - objectImport.acSymbol.skipOver = true; - currentSymbol.addChild(objectImport, true); - currentScope.addSymbol(objectImport.acSymbol, false); - } - foreach (s; builtinSymbols[]) - currentScope.addSymbol(s, false); - mod.accept(this); - } + override void visit(const Module mod) + { + rootSymbol = allocateSemanticSymbol(null, CompletionKind.moduleName, + symbolFile); + currentSymbol = rootSymbol; + moduleScope = GCAllocator.instance.make!Scope(0, uint.max); + currentScope = moduleScope; + auto numResolved = cache.resolveImportLocations("object", (objectLocation) { + auto objectImport = allocateSemanticSymbol(IMPORT_SYMBOL_NAME, + CompletionKind.importSymbol, objectLocation); + objectImport.acSymbol.skipOver = true; + currentSymbol.addChild(objectImport, true); + currentScope.addSymbol(objectImport.acSymbol, false); + }); + if (numResolved == 0) + warning("Could not locate any object.d or object.di"); + foreach (s; builtinSymbols[]) + currentScope.addSymbol(s, false); + mod.accept(this); + } override void visit(const EnumDeclaration dec) { diff --git a/dsymbol/src/dsymbol/modulecache.d b/dsymbol/src/dsymbol/modulecache.d index ca1ba9f..ede8864 100644 --- a/dsymbol/src/dsymbol/modulecache.d +++ b/dsymbol/src/dsymbol/modulecache.d @@ -329,6 +329,80 @@ struct ModuleCache return alternative.length > 0 ? istring(alternative) : istring(null); } + /** + * Params: + * moduleName = the name of the module being imported, in "a/b/c" style + * cb = the callback used to be called whenever a module is found, + * the absolute path is passed as parameter + * Returns: + * The number of resolved paths + */ + size_t resolveImportLocations(string moduleName, scope void delegate(istring) cb) + { + assert(moduleName !is null, "module name is null"); + if (isRooted(moduleName)) + { + cb(istring(moduleName)); + return 1; + } + + size_t count = 0; + string alternative; + foreach (importPath; importPaths[]) + { + auto path = importPath.path; + // import path is a filename + // first check string if this is a feasable path (no filesystem usage) + if (path.stripExtension.endsWith(moduleName) + && path.existsAnd!isFile) + { + // prefer exact import names above .di/package.d files + cb(istring(path)); + count++; + } + // no exact matches and no .di/package.d matches either + else if (!alternative.length) + { + string dotDi = buildPath(path, moduleName) ~ ".di"; + string dotD = dotDi[0 .. $ - 1]; + string withoutSuffix = dotDi[0 .. $ - 3]; + if (existsAnd!isFile(dotD)) + { + cb(istring(dotD)); + count++; + } + else if (existsAnd!isFile(dotDi)) + alternative = dotDi; + else if (existsAnd!isDir(withoutSuffix)) + { + string packagePath = buildPath(withoutSuffix, "package.di"); + if (existsAnd!isFile(packagePath[0 .. $ - 1])) + alternative = packagePath[0 .. $ - 1]; + else if (existsAnd!isFile(packagePath)) + alternative = packagePath; + } + } + // we have a potential .di/package.d file but continue searching for + // exact .d file matches to use instead + else + { + string dotD = buildPath(path, moduleName) ~ ".d"; + if (existsAnd!isFile(dotD)) + { + cb(istring(dotD)); + count++; + } + } + } + if (alternative.length > 0) + { + cb(istring(alternative)); + count++; + alternative = ""; + } + return count; + } + auto getImportPaths() const { return importPaths[].map!(a => a.path);