|
1 | 1 | /** Provides classes for working with files and folders. */ |
2 | 2 |
|
3 | 3 | private import codeql.Locations |
| 4 | +private import codeql.util.FileSystem |
4 | 5 |
|
5 | | -/** A file or folder. */ |
6 | | -abstract class Container extends @container { |
7 | | - /** Gets a file or sub-folder in this container. */ |
8 | | - Container getAChildContainer() { this = result.getParentContainer() } |
| 6 | +private module Input implements InputSig { |
| 7 | + abstract class ContainerBase extends @container { |
| 8 | + abstract string getAbsolutePath(); |
9 | 9 |
|
10 | | - /** Gets a file in this container. */ |
11 | | - File getAFile() { result = this.getAChildContainer() } |
| 10 | + ContainerBase getParentContainer() { containerparent(result, this) } |
12 | 11 |
|
13 | | - /** Gets a sub-folder in this container. */ |
14 | | - Folder getAFolder() { result = this.getAChildContainer() } |
15 | | - |
16 | | - /** |
17 | | - * Gets the absolute, canonical path of this container, using forward slashes |
18 | | - * as path separator. |
19 | | - * |
20 | | - * The path starts with a _root prefix_ followed by zero or more _path |
21 | | - * segments_ separated by forward slashes. |
22 | | - * |
23 | | - * The root prefix is of one of the following forms: |
24 | | - * |
25 | | - * 1. A single forward slash `/` (Unix-style) |
26 | | - * 2. An upper-case drive letter followed by a colon and a forward slash, |
27 | | - * such as `C:/` (Windows-style) |
28 | | - * 3. Two forward slashes, a computer name, and then another forward slash, |
29 | | - * such as `//FileServer/` (UNC-style) |
30 | | - * |
31 | | - * Path segments are never empty (that is, absolute paths never contain two |
32 | | - * contiguous slashes, except as part of a UNC-style root prefix). Also, path |
33 | | - * segments never contain forward slashes, and no path segment is of the |
34 | | - * form `.` (one dot) or `..` (two dots). |
35 | | - * |
36 | | - * Note that an absolute path never ends with a forward slash, except if it is |
37 | | - * a bare root prefix, that is, the path has no path segments. A container |
38 | | - * whose absolute path has no segments is always a `Folder`, not a `File`. |
39 | | - */ |
40 | | - abstract string getAbsolutePath(); |
41 | | - |
42 | | - /** |
43 | | - * Gets the base name of this container including extension, that is, the last |
44 | | - * segment of its absolute path, or the empty string if it has no segments. |
45 | | - * |
46 | | - * Here are some examples of absolute paths and the corresponding base names |
47 | | - * (surrounded with quotes to avoid ambiguity): |
48 | | - * |
49 | | - * <table border="1"> |
50 | | - * <tr><th>Absolute path</th><th>Base name</th></tr> |
51 | | - * <tr><td>"/tmp/tst.go"</td><td>"tst.go"</td></tr> |
52 | | - * <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr> |
53 | | - * <tr><td>"/"</td><td>""</td></tr> |
54 | | - * <tr><td>"C:/"</td><td>""</td></tr> |
55 | | - * <tr><td>"D:/"</td><td>""</td></tr> |
56 | | - * <tr><td>"//FileServer/"</td><td>""</td></tr> |
57 | | - * </table> |
58 | | - */ |
59 | | - string getBaseName() { |
60 | | - result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) |
61 | | - } |
62 | | - |
63 | | - /** |
64 | | - * Gets the extension of this container, that is, the suffix of its base name |
65 | | - * after the last dot character, if any. |
66 | | - * |
67 | | - * In particular, |
68 | | - * |
69 | | - * - if the name does not include a dot, there is no extension, so this |
70 | | - * predicate has no result; |
71 | | - * - if the name ends in a dot, the extension is the empty string; |
72 | | - * - if the name contains multiple dots, the extension follows the last dot. |
73 | | - * |
74 | | - * Here are some examples of absolute paths and the corresponding extensions |
75 | | - * (surrounded with quotes to avoid ambiguity): |
76 | | - * |
77 | | - * <table border="1"> |
78 | | - * <tr><th>Absolute path</th><th>Extension</th></tr> |
79 | | - * <tr><td>"/tmp/tst.go"</td><td>"go"</td></tr> |
80 | | - * <tr><td>"/tmp/.classpath"</td><td>"classpath"</td></tr> |
81 | | - * <tr><td>"/bin/bash"</td><td>not defined</td></tr> |
82 | | - * <tr><td>"/tmp/tst2."</td><td>""</td></tr> |
83 | | - * <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr> |
84 | | - * </table> |
85 | | - */ |
86 | | - string getExtension() { |
87 | | - result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) |
| 12 | + string toString() { result = this.getAbsolutePath() } |
88 | 13 | } |
89 | 14 |
|
90 | | - /** Gets the file in this container that has the given `baseName`, if any. */ |
91 | | - File getFile(string baseName) { |
92 | | - result = this.getAFile() and |
93 | | - result.getBaseName() = baseName |
| 15 | + class FolderBase extends ContainerBase, @folder { |
| 16 | + override string getAbsolutePath() { folders(this, result) } |
94 | 17 | } |
95 | 18 |
|
96 | | - /** Gets the sub-folder in this container that has the given `baseName`, if any. */ |
97 | | - Folder getFolder(string baseName) { |
98 | | - result = this.getAFolder() and |
99 | | - result.getBaseName() = baseName |
100 | | - } |
101 | | - |
102 | | - /** Gets the parent container of this file or folder, if any. */ |
103 | | - Container getParentContainer() { containerparent(result, this) } |
104 | | - |
105 | | - /** |
106 | | - * Gets the relative path of this file or folder from the root folder of the |
107 | | - * analyzed source location. The relative path of the root folder itself is |
108 | | - * the empty string. |
109 | | - * |
110 | | - * This has no result if the container is outside the source root, that is, |
111 | | - * if the root folder is not a reflexive, transitive parent of this container. |
112 | | - */ |
113 | | - string getRelativePath() { |
114 | | - exists(string absPath, string pref | |
115 | | - absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) |
116 | | - | |
117 | | - absPath = pref and result = "" |
118 | | - or |
119 | | - absPath = pref.regexpReplaceAll("/$", "") + "/" + result and |
120 | | - not result.matches("/%") |
121 | | - ) |
| 19 | + class FileBase extends ContainerBase, @file { |
| 20 | + override string getAbsolutePath() { files(this, result) } |
122 | 21 | } |
123 | 22 |
|
124 | | - /** |
125 | | - * Gets the stem of this container, that is, the prefix of its base name up to |
126 | | - * (but not including) the last dot character if there is one, or the entire |
127 | | - * base name if there is not. |
128 | | - * |
129 | | - * Here are some examples of absolute paths and the corresponding stems |
130 | | - * (surrounded with quotes to avoid ambiguity): |
131 | | - * |
132 | | - * <table border="1"> |
133 | | - * <tr><th>Absolute path</th><th>Stem</th></tr> |
134 | | - * <tr><td>"/tmp/tst.go"</td><td>"tst"</td></tr> |
135 | | - * <tr><td>"/tmp/.classpath"</td><td>""</td></tr> |
136 | | - * <tr><td>"/bin/bash"</td><td>"bash"</td></tr> |
137 | | - * <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr> |
138 | | - * <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr> |
139 | | - * </table> |
140 | | - */ |
141 | | - string getStem() { |
142 | | - result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) |
143 | | - } |
| 23 | + predicate hasSourceLocationPrefix = sourceLocationPrefix/1; |
| 24 | +} |
144 | 25 |
|
145 | | - /** |
146 | | - * Gets a URL representing the location of this container. |
147 | | - * |
148 | | - * For more information see https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls. |
149 | | - */ |
150 | | - abstract string getURL(); |
| 26 | +private module Impl = Make<Input>; |
151 | 27 |
|
152 | | - /** |
153 | | - * Gets a textual representation of the path of this container. |
154 | | - * |
155 | | - * This is the absolute path of the container. |
156 | | - */ |
157 | | - string toString() { result = this.getAbsolutePath() } |
158 | | -} |
| 28 | +class Container = Impl::Container; |
159 | 29 |
|
160 | 30 | /** A folder. */ |
161 | | -class Folder extends Container, @folder { |
162 | | - override string getAbsolutePath() { folders(this, result) } |
163 | | - |
164 | | - /** Gets the URL of this folder. */ |
165 | | - override string getURL() { result = "folder://" + this.getAbsolutePath() } |
166 | | -} |
| 31 | +class Folder extends Container, Impl::Folder { } |
167 | 32 |
|
168 | 33 | /** A file. */ |
169 | | -class File extends Container, @file { |
170 | | - override string getAbsolutePath() { files(this, result) } |
171 | | - |
172 | | - /** Gets the URL of this file. */ |
173 | | - override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } |
174 | | - |
| 34 | +class File extends Container, Impl::File { |
175 | 35 | /** Holds if this file was extracted from ordinary source code. */ |
176 | 36 | predicate fromSource() { any() } |
177 | 37 | } |
0 commit comments