Skip to content

Commit e00c7f4

Browse files
committed
create a shared implementation for files and locations
1 parent 89ca7e2 commit e00c7f4

File tree

9 files changed

+387
-235
lines changed

9 files changed

+387
-235
lines changed

javascript/ql/lib/qlpack.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ dbscheme: semmlecode.javascript.dbscheme
55
extractor: javascript
66
library: true
77
upgrades: upgrades
8+
dependencies:
9+
codeql/utils: 0.0.1
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Provides an implementation of `LocationsSig` from the `codeql/utils` package.
3+
*/
4+
5+
private import codeql.utils.Locations as Locs
6+
7+
/** An implementation of `LocationsSig`. */
8+
module LocationsImpl implements Locs::LocationsSig {
9+
abstract class Container extends @container {
10+
abstract string getAbsolutePath();
11+
12+
string toString() { result = this.getAbsolutePath() }
13+
14+
Container getParentContainer() { containerparent(result, this) }
15+
}
16+
17+
class File extends @file, Container {
18+
override string getAbsolutePath() { files(this, result) }
19+
}
20+
21+
class Folder extends @folder, Container {
22+
override string getAbsolutePath() { folders(this, result) }
23+
}
24+
25+
string getSourceLocationPrefix() { sourceLocationPrefix(result) }
26+
27+
class Location = @location;
28+
29+
predicate locations(
30+
Location loc, File file, int startLine, int startColum, int endLine, int endColumn
31+
) {
32+
locations_default(loc, file, startLine, startColum, endLine, endColumn)
33+
}
34+
}
35+
36+
/** An instantiation of the shared Locations module. */
37+
module Inst = Locs::Make<LocationsImpl>;

ruby/ql/lib/codeql/Locations.qll

Lines changed: 2 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,5 @@
1-
/** Provides classes for working with locations. */
2-
3-
import files.FileSystem
4-
5-
/**
6-
* A location as given by a file, a start line, a start column,
7-
* an end line, and an end column.
8-
*
9-
* For more information about locations see [LGTM locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
10-
*/
11-
class Location extends @location {
12-
/** Gets the file for this location. */
13-
File getFile() { locations_default(this, result, _, _, _, _) }
14-
15-
/** Gets the 1-based line number (inclusive) where this location starts. */
16-
int getStartLine() { locations_default(this, _, result, _, _, _) }
17-
18-
/** Gets the 1-based column number (inclusive) where this location starts. */
19-
int getStartColumn() { locations_default(this, _, _, result, _, _) }
20-
21-
/** Gets the 1-based line number (inclusive) where this location ends. */
22-
int getEndLine() { locations_default(this, _, _, _, result, _) }
23-
24-
/** Gets the 1-based column number (inclusive) where this location ends. */
25-
int getEndColumn() { locations_default(this, _, _, _, _, result) }
26-
27-
/** Gets the number of lines covered by this location. */
28-
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }
29-
30-
/** Gets a textual representation of this element. */
31-
string toString() {
32-
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
33-
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
34-
result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
35-
)
36-
}
37-
38-
/**
39-
* Holds if this element is at the specified location.
40-
* The location spans column `startcolumn` of line `startline` to
41-
* column `endcolumn` of line `endline` in file `filepath`.
42-
* For more information, see
43-
* [LGTM locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
44-
*/
45-
predicate hasLocationInfo(
46-
string filepath, int startline, int startcolumn, int endline, int endcolumn
47-
) {
48-
exists(File f |
49-
locations_default(this, f, startline, startcolumn, endline, endcolumn) and
50-
filepath = f.getAbsolutePath()
51-
)
52-
}
53-
54-
/** Holds if this location starts strictly before the specified location. */
55-
pragma[inline]
56-
predicate strictlyBefore(Location other) {
57-
this.getStartLine() < other.getStartLine()
58-
or
59-
this.getStartLine() = other.getStartLine() and this.getStartColumn() < other.getStartColumn()
60-
}
61-
}
1+
private import codeql.utils.Locations as Locs
2+
import codeql.ruby.internal.LocationsImpl::Inst
623

634
/** An entity representing an empty location. */
645
class EmptyLocation extends Location {
Lines changed: 4 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,177 +1,7 @@
1-
/** Provides classes for working with files and folders. */
1+
private import codeql.ruby.internal.LocationsImpl
22

3-
private import codeql.Locations
3+
class Container = Inst::Container;
44

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() }
5+
class File = Inst::File;
96

10-
/** Gets a file in this container. */
11-
File getAFile() { result = this.getAChildContainer() }
12-
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)
88-
}
89-
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
94-
}
95-
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-
)
122-
}
123-
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-
}
144-
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();
151-
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-
}
159-
160-
/** 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-
}
167-
168-
/** 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-
175-
/** Holds if this file was extracted from ordinary source code. */
176-
predicate fromSource() { any() }
177-
}
7+
class Folder = Inst::Folder;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Provides an implementation of `LocationsSig` from the `codeql/utils` package.
3+
*/
4+
5+
private import codeql.utils.Locations as Locs
6+
7+
/** An implementation of `LocationsSig`. */
8+
module LocationsImpl implements Locs::LocationsSig {
9+
abstract class Container extends @container {
10+
abstract string getAbsolutePath();
11+
12+
Container getParentContainer() { containerparent(result, this) }
13+
14+
string toString() { result = this.getAbsolutePath() }
15+
}
16+
17+
class File extends @file, Container {
18+
override string getAbsolutePath() { files(this, result) }
19+
}
20+
21+
class Folder extends Container, @folder {
22+
override string getAbsolutePath() { folders(this, result) }
23+
}
24+
25+
string getSourceLocationPrefix() { sourceLocationPrefix(result) }
26+
27+
class Location = @location_default;
28+
29+
predicate locations(
30+
Location loc, File file, int startLine, int startColum, int endLine, int endColumn
31+
) {
32+
locations_default(loc, file, startLine, startColum, endLine, endColumn)
33+
}
34+
}
35+
36+
/** An instantiation of the shared Locations module. */
37+
module Inst = Locs::Make<LocationsImpl>;

ruby/ql/lib/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ upgrades: upgrades
77
library: true
88
dependencies:
99
codeql/ssa: 0.0.1
10+
codeql/utils: 0.0.1
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Initial release. Extracted common file system and locations code into a library pack to share code between languages.

0 commit comments

Comments
 (0)