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