Skip to content

Commit 5feb2f7

Browse files
authored
Merge pull request github#14321 from aschackmull/shared/filesystem
All languages: Use shared FileSystem library and minor regex performance improvement.
2 parents 10231e9 + 80f00bc commit 5feb2f7

File tree

9 files changed

+139
-949
lines changed

9 files changed

+139
-949
lines changed

cpp/ql/lib/semmle/code/cpp/File.qll

Lines changed: 20 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -5,155 +5,35 @@
55
import semmle.code.cpp.Element
66
import semmle.code.cpp.Declaration
77
import semmle.code.cpp.metrics.MetricFile
8+
private import codeql.util.FileSystem
89

9-
/** A file or folder. */
10-
class Container extends Locatable, @container {
11-
/**
12-
* Gets the absolute, canonical path of this container, using forward slashes
13-
* as path separator.
14-
*
15-
* The path starts with a _root prefix_ followed by zero or more _path
16-
* segments_ separated by forward slashes.
17-
*
18-
* The root prefix is of one of the following forms:
19-
*
20-
* 1. A single forward slash `/` (Unix-style)
21-
* 2. An upper-case drive letter followed by a colon and a forward slash,
22-
* such as `C:/` (Windows-style)
23-
* 3. Two forward slashes, a computer name, and then another forward slash,
24-
* such as `//FileServer/` (UNC-style)
25-
*
26-
* Path segments are never empty (that is, absolute paths never contain two
27-
* contiguous slashes, except as part of a UNC-style root prefix). Also, path
28-
* segments never contain forward slashes, and no path segment is of the
29-
* form `.` (one dot) or `..` (two dots).
30-
*
31-
* Note that an absolute path never ends with a forward slash, except if it is
32-
* a bare root prefix, that is, the path has no path segments. A container
33-
* whose absolute path has no segments is always a `Folder`, not a `File`.
34-
*/
35-
string getAbsolutePath() { none() } // overridden by subclasses
10+
private module Input implements InputSig {
11+
abstract class ContainerBase extends @container {
12+
abstract string getAbsolutePath();
3613

37-
/**
38-
* Gets the relative path of this file or folder from the root folder of the
39-
* analyzed source location. The relative path of the root folder itself is
40-
* the empty string.
41-
*
42-
* This has no result if the container is outside the source root, that is,
43-
* if the root folder is not a reflexive, transitive parent of this container.
44-
*/
45-
string getRelativePath() {
46-
exists(string absPath, string pref |
47-
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
48-
|
49-
absPath = pref and result = ""
50-
or
51-
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
52-
not result.matches("/%")
53-
)
54-
}
14+
ContainerBase getParentContainer() {
15+
containerparent(unresolveElement(result), underlyingElement(this))
16+
}
5517

56-
/**
57-
* Gets the base name of this container including extension, that is, the last
58-
* segment of its absolute path, or the empty string if it has no segments.
59-
*
60-
* Here are some examples of absolute paths and the corresponding base names
61-
* (surrounded with quotes to avoid ambiguity):
62-
*
63-
* <table border="1">
64-
* <tr><th>Absolute path</th><th>Base name</th></tr>
65-
* <tr><td>"/tmp/tst.js"</td><td>"tst.js"</td></tr>
66-
* <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr>
67-
* <tr><td>"/"</td><td>""</td></tr>
68-
* <tr><td>"C:/"</td><td>""</td></tr>
69-
* <tr><td>"D:/"</td><td>""</td></tr>
70-
* <tr><td>"//FileServer/"</td><td>""</td></tr>
71-
* </table>
72-
*/
73-
string getBaseName() {
74-
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
18+
string toString() { result = this.getAbsolutePath() }
7519
}
7620

77-
/**
78-
* Gets the extension of this container, that is, the suffix of its base name
79-
* after the last dot character, if any.
80-
*
81-
* In particular,
82-
*
83-
* - if the name does not include a dot, there is no extension, so this
84-
* predicate has no result;
85-
* - if the name ends in a dot, the extension is the empty string;
86-
* - if the name contains multiple dots, the extension follows the last dot.
87-
*
88-
* Here are some examples of absolute paths and the corresponding extensions
89-
* (surrounded with quotes to avoid ambiguity):
90-
*
91-
* <table border="1">
92-
* <tr><th>Absolute path</th><th>Extension</th></tr>
93-
* <tr><td>"/tmp/tst.js"</td><td>"js"</td></tr>
94-
* <tr><td>"/tmp/.classpath"</td><td>"classpath"</td></tr>
95-
* <tr><td>"/bin/bash"</td><td>not defined</td></tr>
96-
* <tr><td>"/tmp/tst2."</td><td>""</td></tr>
97-
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
98-
* </table>
99-
*/
100-
string getExtension() {
101-
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
102-
}
103-
104-
/**
105-
* Gets the stem of this container, that is, the prefix of its base name up to
106-
* (but not including) the last dot character if there is one, or the entire
107-
* base name if there is not.
108-
*
109-
* Here are some examples of absolute paths and the corresponding stems
110-
* (surrounded with quotes to avoid ambiguity):
111-
*
112-
* <table border="1">
113-
* <tr><th>Absolute path</th><th>Stem</th></tr>
114-
* <tr><td>"/tmp/tst.js"</td><td>"tst"</td></tr>
115-
* <tr><td>"/tmp/.classpath"</td><td>""</td></tr>
116-
* <tr><td>"/bin/bash"</td><td>"bash"</td></tr>
117-
* <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr>
118-
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
119-
* </table>
120-
*/
121-
string getStem() {
122-
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
123-
}
124-
125-
/** Gets the parent container of this file or folder, if any. */
126-
Container getParentContainer() {
127-
containerparent(unresolveElement(result), underlyingElement(this))
21+
class FolderBase extends ContainerBase, @folder {
22+
override string getAbsolutePath() { folders(underlyingElement(this), result) }
12823
}
12924

130-
/** Gets a file or sub-folder in this container. */
131-
Container getAChildContainer() { this = result.getParentContainer() }
132-
133-
/** Gets a file in this container. */
134-
File getAFile() { result = this.getAChildContainer() }
135-
136-
/** Gets the file in this container that has the given `baseName`, if any. */
137-
File getFile(string baseName) {
138-
result = this.getAFile() and
139-
result.getBaseName() = baseName
25+
class FileBase extends ContainerBase, @file {
26+
override string getAbsolutePath() { files(underlyingElement(this), result) }
14027
}
14128

142-
/** Gets a sub-folder in this container. */
143-
Folder getAFolder() { result = this.getAChildContainer() }
29+
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
30+
}
14431

145-
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
146-
Folder getFolder(string baseName) {
147-
result = this.getAFolder() and
148-
result.getBaseName() = baseName
149-
}
32+
private module Impl = Make<Input>;
15033

151-
/**
152-
* Gets a textual representation of the path of this container.
153-
*
154-
* This is the absolute path of the container.
155-
*/
156-
override string toString() { result = this.getAbsolutePath() }
34+
/** A file or folder. */
35+
class Container extends Locatable, Impl::Container {
36+
override string toString() { result = Impl::Container.super.toString() }
15737
}
15838

15939
/**
@@ -166,9 +46,7 @@ class Container extends Locatable, @container {
16646
*
16747
* To get the full path, use `getAbsolutePath`.
16848
*/
169-
class Folder extends Container, @folder {
170-
override string getAbsolutePath() { folders(underlyingElement(this), result) }
171-
49+
class Folder extends Container, Impl::Folder {
17250
override Location getLocation() {
17351
result.getContainer() = this and
17452
result.hasLocationInfo(_, 0, 0, 0, 0)
@@ -189,9 +67,7 @@ class Folder extends Container, @folder {
18967
* The base name further decomposes into the _stem_ and _extension_ -- see
19068
* `getStem` and `getExtension`. To get the full path, use `getAbsolutePath`.
19169
*/
192-
class File extends Container, @file {
193-
override string getAbsolutePath() { files(underlyingElement(this), result) }
194-
70+
class File extends Container, Impl::File {
19571
override string getAPrimaryQlClass() { result = "File" }
19672

19773
override Location getLocation() {

csharp/ql/lib/semmle/code/csharp/File.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ private module Impl = Make<Input>;
2929

3030
class Container = Impl::Container;
3131

32-
/** A folder. */
33-
class Folder extends Container, Impl::Folder { }
32+
class Folder = Impl::Folder;
3433

3534
bindingset[flag]
3635
private predicate fileHasExtractionFlag(File f, int flag) {

0 commit comments

Comments
 (0)