Skip to content

Commit 73521ca

Browse files
committed
Python: Use shared FileSystem library.
1 parent a08fe5b commit 73521ca

File tree

1 file changed

+30
-163
lines changed

1 file changed

+30
-163
lines changed

python/ql/lib/semmle/python/Files.qll

Lines changed: 30 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,32 @@
1+
/** Provides classes for working with files and folders. */
2+
13
import python
4+
private import codeql.util.FileSystem
5+
6+
private module Input implements InputSig {
7+
abstract class ContainerBase extends @container {
8+
abstract string getAbsolutePath();
9+
10+
ContainerBase getParentContainer() { containerparent(result, this) }
11+
12+
string toString() { result = this.getAbsolutePath() }
13+
}
14+
15+
class FolderBase extends ContainerBase, @folder {
16+
override string getAbsolutePath() { folders(this, result) }
17+
}
18+
19+
class FileBase extends ContainerBase, @file {
20+
override string getAbsolutePath() { files(this, result) }
21+
}
22+
23+
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
24+
}
25+
26+
private module Impl = Make<Input>;
227

328
/** A file */
4-
class File extends Container, @file {
29+
class File extends Container, Impl::File {
530
/**
631
* Holds if this element is at the specified location.
732
* The location spans column `startcolumn` of line `startline` to
@@ -45,11 +70,6 @@ class File extends Container, @file {
4570
)
4671
}
4772

48-
override string getAbsolutePath() { files(this, result) }
49-
50-
/** Gets the URL of this file. */
51-
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
52-
5373
override Container getImportRoot(int n) {
5474
/* File stem must be a legal Python identifier */
5575
this.getStem().regexpMatch("[^\\d\\W]\\w*") and
@@ -108,7 +128,7 @@ private predicate occupied_line(File f, int n) {
108128
}
109129

110130
/** A folder (directory) */
111-
class Folder extends Container, @folder {
131+
class Folder extends Container, Impl::Folder {
112132
/**
113133
* Holds if this element is at the specified location.
114134
* The location spans column `startcolumn` of line `startline` to
@@ -126,11 +146,6 @@ class Folder extends Container, @folder {
126146
endcolumn = 0
127147
}
128148

129-
override string getAbsolutePath() { folders(this, result) }
130-
131-
/** Gets the URL of this folder. */
132-
override string getURL() { result = "folder://" + this.getAbsolutePath() }
133-
134149
override Container getImportRoot(int n) {
135150
this.isImportRoot(n) and result = this
136151
or
@@ -144,34 +159,8 @@ class Folder extends Container, @folder {
144159
* A container is an abstract representation of a file system object that can
145160
* hold elements of interest.
146161
*/
147-
abstract class Container extends @container {
148-
Container getParent() { containerparent(result, this) }
149-
150-
/**
151-
* Gets a textual representation of the path of this container.
152-
*
153-
* This is the absolute path of the container.
154-
*/
155-
string toString() { result = this.getAbsolutePath() }
156-
157-
/**
158-
* Gets the relative path of this file or folder from the root folder of the
159-
* analyzed source location. The relative path of the root folder itself is
160-
* the empty string.
161-
*
162-
* This has no result if the container is outside the source root, that is,
163-
* if the root folder is not a reflexive, transitive parent of this container.
164-
*/
165-
string getRelativePath() {
166-
exists(string absPath, string pref |
167-
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
168-
|
169-
absPath = pref and result = ""
170-
or
171-
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
172-
not result.matches("/%")
173-
)
174-
}
162+
class Container extends Impl::Container {
163+
Container getParent() { result = this.getParentContainer() }
175164

176165
/** Whether this file or folder is part of the standard library */
177166
predicate inStdlib() { this.inStdlib(_, _) }
@@ -187,135 +176,13 @@ abstract class Container extends @container {
187176
)
188177
}
189178

190-
/* Standard cross-language API */
191-
/** Gets a file or sub-folder in this container. */
192-
Container getAChildContainer() { containerparent(this, result) }
193-
194-
/** Gets a file in this container. */
195-
File getAFile() { result = this.getAChildContainer() }
196-
197-
/** Gets a sub-folder in this container. */
198-
Folder getAFolder() { result = this.getAChildContainer() }
199-
200-
/**
201-
* Gets the absolute, canonical path of this container, using forward slashes
202-
* as path separator.
203-
*
204-
* The path starts with a _root prefix_ followed by zero or more _path
205-
* segments_ separated by forward slashes.
206-
*
207-
* The root prefix is of one of the following forms:
208-
*
209-
* 1. A single forward slash `/` (Unix-style)
210-
* 2. An upper-case drive letter followed by a colon and a forward slash,
211-
* such as `C:/` (Windows-style)
212-
* 3. Two forward slashes, a computer name, and then another forward slash,
213-
* such as `//FileServer/` (UNC-style)
214-
*
215-
* Path segments are never empty (that is, absolute paths never contain two
216-
* contiguous slashes, except as part of a UNC-style root prefix). Also, path
217-
* segments never contain forward slashes, and no path segment is of the
218-
* form `.` (one dot) or `..` (two dots).
219-
*
220-
* Note that an absolute path never ends with a forward slash, except if it is
221-
* a bare root prefix, that is, the path has no path segments. A container
222-
* whose absolute path has no segments is always a `Folder`, not a `File`.
223-
*/
224-
abstract string getAbsolutePath();
225-
226-
/**
227-
* Gets the base name of this container including extension, that is, the last
228-
* segment of its absolute path, or the empty string if it has no segments.
229-
*
230-
* Here are some examples of absolute paths and the corresponding base names
231-
* (surrounded with quotes to avoid ambiguity):
232-
*
233-
* <table border="1">
234-
* <tr><th>Absolute path</th><th>Base name</th></tr>
235-
* <tr><td>"/tmp/tst.py"</td><td>"tst.py"</td></tr>
236-
* <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr>
237-
* <tr><td>"/"</td><td>""</td></tr>
238-
* <tr><td>"C:/"</td><td>""</td></tr>
239-
* <tr><td>"D:/"</td><td>""</td></tr>
240-
* <tr><td>"//FileServer/"</td><td>""</td></tr>
241-
* </table>
242-
*/
243-
string getBaseName() {
244-
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
245-
}
246-
247-
/**
248-
* Gets the extension of this container, that is, the suffix of its base name
249-
* after the last dot character, if any.
250-
*
251-
* In particular,
252-
*
253-
* - if the name does not include a dot, there is no extension, so this
254-
* predicate has no result;
255-
* - if the name ends in a dot, the extension is the empty string;
256-
* - if the name contains multiple dots, the extension follows the last dot.
257-
*
258-
* Here are some examples of absolute paths and the corresponding extensions
259-
* (surrounded with quotes to avoid ambiguity):
260-
*
261-
* <table border="1">
262-
* <tr><th>Absolute path</th><th>Extension</th></tr>
263-
* <tr><td>"/tmp/tst.py"</td><td>"py"</td></tr>
264-
* <tr><td>"/tmp/.gitignore"</td><td>"gitignore"</td></tr>
265-
* <tr><td>"/bin/bash"</td><td>not defined</td></tr>
266-
* <tr><td>"/tmp/tst2."</td><td>""</td></tr>
267-
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
268-
* </table>
269-
*/
270-
string getExtension() {
271-
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
272-
}
273-
274-
/**
275-
* Gets the stem of this container, that is, the prefix of its base name up to
276-
* (but not including) the last dot character if there is one, or the entire
277-
* base name if there is not.
278-
*
279-
* Here are some examples of absolute paths and the corresponding stems
280-
* (surrounded with quotes to avoid ambiguity):
281-
*
282-
* <table border="1">
283-
* <tr><th>Absolute path</th><th>Stem</th></tr>
284-
* <tr><td>"/tmp/tst.py"</td><td>"tst"</td></tr>
285-
* <tr><td>"/tmp/.gitignore"</td><td>""</td></tr>
286-
* <tr><td>"/bin/bash"</td><td>"bash"</td></tr>
287-
* <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr>
288-
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
289-
* </table>
290-
*/
291-
string getStem() {
292-
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
293-
}
294-
295-
File getFile(string baseName) {
296-
result = this.getAFile() and
297-
result.getBaseName() = baseName
298-
}
299-
300-
Folder getFolder(string baseName) {
301-
result = this.getAFolder() and
302-
result.getBaseName() = baseName
303-
}
304-
305-
Container getParentContainer() { this = result.getAChildContainer() }
179+
override Container getParentContainer() { result = super.getParentContainer() }
306180

307181
Container getChildContainer(string baseName) {
308182
result = this.getAChildContainer() and
309183
result.getBaseName() = baseName
310184
}
311185

312-
/**
313-
* Gets a URL representing the location of this container.
314-
*
315-
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
316-
*/
317-
abstract string getURL();
318-
319186
/** Holds if this folder is on the import path. */
320187
predicate isImportRoot() { this.isImportRoot(_) }
321188

0 commit comments

Comments
 (0)