55import semmle.code.cpp.Element
66import semmle.code.cpp.Declaration
77import 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 ( ) {
0 commit comments