aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/file_manager.d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-12-09 18:59:38 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2022-12-11 17:17:58 +0100
commit6d799f0aed18be25a5c908499b6411ab6d06b78c (patch)
tree3e6a91048c7fe3e78bae9f75b24eb37c5504681b /gcc/d/dmd/file_manager.d
parentcc7f509d3c0b3ab63891cf7ca2def0fdfb3642c4 (diff)
downloadgcc-6d799f0aed18be25a5c908499b6411ab6d06b78c.zip
gcc-6d799f0aed18be25a5c908499b6411ab6d06b78c.tar.gz
gcc-6d799f0aed18be25a5c908499b6411ab6d06b78c.tar.bz2
d: Merge upstream dmd, druntime c8ae4adb2e, phobos 792c8b7c1.
D front-end changes: - Import dmd v2.101.0. - Deprecate the ability to call `__traits(getAttributes)' on overload sets. - Deprecate non-empty `for' statement increment clause with no effect. - Array literals assigned to `scope' array variables can now be allocated on the stack. D runtime changes: - Import druntime v2.101.0. Phobos changes: - Import phobos v2.101.0. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd c8ae4adb2e. * typeinfo.cc (check_typeinfo_type): Update for new front-end interface. (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Remove warning that toHash() must be declared 'nothrow @safe`. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime c8ae4adb2e. * src/MERGE: Merge upstream phobos 792c8b7c1.
Diffstat (limited to 'gcc/d/dmd/file_manager.d')
-rw-r--r--gcc/d/dmd/file_manager.d138
1 files changed, 116 insertions, 22 deletions
diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d
index 0ea7303..a941115 100644
--- a/gcc/d/dmd/file_manager.d
+++ b/gcc/d/dmd/file_manager.d
@@ -12,7 +12,7 @@ module dmd.file_manager;
import dmd.root.stringtable : StringTable;
import dmd.root.file : File, Buffer;
-import dmd.root.filename : FileName;
+import dmd.root.filename : FileName, isDirSeparator;
import dmd.root.string : toDString;
import dmd.globals;
import dmd.identifier;
@@ -26,14 +26,86 @@ bool isPackageFileName(scope FileName fileName) nothrow
return FileName.equals(fileName.name, package_d) || FileName.equals(fileName.name, package_di);
}
+// A path stack that allows one to go up and down the path using directory
+// separators. `cur` is the current path, `up` goes up one path, `down` goes
+// down one path. if `up` or `down` return false, there are no further paths.
+private struct PathStack
+{
+ private const(char)[] path;
+ private size_t pos;
+
+ @safe @nogc nothrow pure:
+
+ this(const(char)[] p)
+ {
+ path = p;
+ pos = p.length;
+ }
+
+ const(char)[] cur()
+ {
+ return path[0 .. pos];
+ }
+
+ bool up()
+ {
+ if (pos == 0)
+ return false;
+ while (--pos != 0)
+ if (isDirSeparator(path[pos]))
+ return true;
+ return false;
+ }
+
+ bool down()
+ {
+ if (pos == path.length)
+ return false;
+ while (++pos != path.length)
+ if (isDirSeparator(path[pos]))
+ return true;
+ return false;
+ }
+}
+
final class FileManager
{
private StringTable!(const(ubyte)[]) files;
+ private StringTable!(bool) packageStatus;
+
+ // check if the package path of the given path exists. The input path is
+ // expected to contain the full path to the module, so the parent
+ // directories of that path are checked.
+ private bool packageExists(const(char)[] p) nothrow
+ {
+ // step 1, look for the closest parent path that is cached
+ bool exists = true;
+ auto st = PathStack(p);
+ while (st.up) {
+ if (auto cached = packageStatus.lookup(st.cur)) {
+ exists = cached.value;
+ break;
+ }
+ }
+ // found a parent that is cached (or reached the end of the stack).
+ // step 2, traverse back up the stack storing either false if the
+ // parent doesn't exist, or the result of the `exists` call if it does.
+ while (st.down) {
+ if (!exists)
+ packageStatus.insert(st.cur, false);
+ else
+ exists = packageStatus.insert(st.cur, FileName.exists(st.cur) == 2).value;
+ }
+
+ // at this point, exists should be the answer.
+ return exists;
+ }
///
public this () nothrow
{
this.files._init();
+ this.packageStatus._init();
}
nothrow:
@@ -48,13 +120,15 @@ nothrow:
* the found file name or
* `null` if it is not different from filename.
*/
- static const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
+ const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
{
//printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
/* Search along path[] for .di file, then .d file, then .i file, then .c file.
*/
+ // see if we should check for the module locally.
+ bool checkLocal = packageExists(filename);
const sdi = FileName.forceExt(filename, hdr_ext);
- if (FileName.exists(sdi) == 1)
+ if (checkLocal && FileName.exists(sdi) == 1)
return sdi;
scope(exit) FileName.free(sdi.ptr);
@@ -62,36 +136,43 @@ nothrow:
// Special file name representing `stdin`, always assume its presence
if (sd == "__stdin.d")
return sd;
- if (FileName.exists(sd) == 1)
+ if (checkLocal && FileName.exists(sd) == 1)
return sd;
scope(exit) FileName.free(sd.ptr);
const si = FileName.forceExt(filename, i_ext);
- if (FileName.exists(si) == 1)
+ if (checkLocal && FileName.exists(si) == 1)
return si;
scope(exit) FileName.free(si.ptr);
const sc = FileName.forceExt(filename, c_ext);
- if (FileName.exists(sc) == 1)
+ if (checkLocal && FileName.exists(sc) == 1)
return sc;
scope(exit) FileName.free(sc.ptr);
- if (FileName.exists(filename) == 2)
+ if (checkLocal)
{
- /* The filename exists and it's a directory.
- * Therefore, the result should be: filename/package.d
- * iff filename/package.d is a file
- */
- const ni = FileName.combine(filename, package_di);
- if (FileName.exists(ni) == 1)
- return ni;
- FileName.free(ni.ptr);
-
- const n = FileName.combine(filename, package_d);
- if (FileName.exists(n) == 1)
- return n;
- FileName.free(n.ptr);
+ auto cached = packageStatus.lookup(filename);
+ if (!cached)
+ cached = packageStatus.insert(filename, FileName.exists(filename) == 2);
+ if (cached.value)
+ {
+ /* The filename exists and it's a directory.
+ * Therefore, the result should be: filename/package.d
+ * iff filename/package.d is a file
+ */
+ const ni = FileName.combine(filename, package_di);
+ if (FileName.exists(ni) == 1)
+ return ni;
+ FileName.free(ni.ptr);
+
+ const n = FileName.combine(filename, package_d);
+ if (FileName.exists(n) == 1)
+ return n;
+ FileName.free(n.ptr);
+ }
}
+
if (FileName.absolute(filename))
return null;
if (!path.length)
@@ -101,6 +182,11 @@ nothrow:
const p = entry.toDString();
const(char)[] n = FileName.combine(p, sdi);
+
+ if (!packageExists(n)) {
+ FileName.free(n.ptr);
+ continue; // no need to check for anything else.
+ }
if (FileName.exists(n) == 1) {
return n;
}
@@ -127,7 +213,16 @@ nothrow:
const b = FileName.removeExt(filename);
n = FileName.combine(p, b);
FileName.free(b.ptr);
- if (FileName.exists(n) == 2)
+
+ scope(exit) FileName.free(n.ptr);
+
+ // also cache this if we are looking for package.d[i]
+ auto cached = packageStatus.lookup(n);
+ if (!cached) {
+ cached = packageStatus.insert(n, FileName.exists(n) == 2);
+ }
+
+ if (cached.value)
{
const n2i = FileName.combine(n, package_di);
if (FileName.exists(n2i) == 1)
@@ -139,7 +234,6 @@ nothrow:
}
FileName.free(n2.ptr);
}
- FileName.free(n.ptr);
}
return null;
}