diff --git a/config/identical-files.json b/config/identical-files.json index cde68f43caf..a24b5a3a618 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -431,13 +431,6 @@ "java/ql/src/experimental/Security/CWE/CWE-400/LocalThreadResourceAbuse.qhelp", "java/ql/src/experimental/Security/CWE/CWE-400/ThreadResourceAbuse.qhelp" ], - "IDE Contextual Queries": [ - "cpp/ql/lib/IDEContextual.qll", - "csharp/ql/lib/IDEContextual.qll", - "java/ql/lib/IDEContextual.qll", - "javascript/ql/lib/IDEContextual.qll", - "python/ql/lib/analysis/IDEContextual.qll" - ], "CryptoAlgorithms Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll", "python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll", diff --git a/cpp/ql/lib/IDEContextual.qll b/cpp/ql/lib/IDEContextual.qll index f4e6267fdcf..f26956bcca0 100644 --- a/cpp/ql/lib/IDEContextual.qll +++ b/cpp/ql/lib/IDEContextual.qll @@ -3,6 +3,7 @@ */ import semmle.files.FileSystem +private import codeql.util.FileSystem /** * Returns the `File` matching the given source file name as encoded by the VS @@ -10,13 +11,5 @@ import semmle.files.FileSystem */ cached File getFileBySourceArchiveName(string name) { - // The name provided for a file in the source archive by the VS Code extension - // has some differences from the absolute path in the database: - // 1. colons are replaced by underscores - // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> - // "/C_/foo/bar" - // 3. double slashes in UNC prefixes are replaced with a single slash - // We can handle 2 and 3 together by unconditionally adding a leading slash - // before replacing double slashes. - name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + result = IdeContextual::getFileBySourceArchiveName(name) } diff --git a/csharp/ql/lib/IDEContextual.qll b/csharp/ql/lib/IDEContextual.qll index f4e6267fdcf..f26956bcca0 100644 --- a/csharp/ql/lib/IDEContextual.qll +++ b/csharp/ql/lib/IDEContextual.qll @@ -3,6 +3,7 @@ */ import semmle.files.FileSystem +private import codeql.util.FileSystem /** * Returns the `File` matching the given source file name as encoded by the VS @@ -10,13 +11,5 @@ import semmle.files.FileSystem */ cached File getFileBySourceArchiveName(string name) { - // The name provided for a file in the source archive by the VS Code extension - // has some differences from the absolute path in the database: - // 1. colons are replaced by underscores - // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> - // "/C_/foo/bar" - // 3. double slashes in UNC prefixes are replaced with a single slash - // We can handle 2 and 3 together by unconditionally adding a leading slash - // before replacing double slashes. - name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + result = IdeContextual::getFileBySourceArchiveName(name) } diff --git a/go/ql/lib/ideContextual.qll b/go/ql/lib/ideContextual.qll index b729aa81c8f..b28a23a6e00 100644 --- a/go/ql/lib/ideContextual.qll +++ b/go/ql/lib/ideContextual.qll @@ -4,6 +4,7 @@ */ import go +private import codeql.util.FileSystem /** * Returns the `File` matching the given source file name as encoded by the VS @@ -11,13 +12,5 @@ import go */ cached File getFileBySourceArchiveName(string name) { - // The name provided for a file in the source archive by the VS Code extension - // has some differences from the absolute path in the database: - // 1. colons are replaced by underscores - // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> - // "/C_/foo/bar" - // 3. double slashes in UNC prefixes are replaced with a single slash - // We can handle 2 and 3 together by unconditionally adding a leading slash - // before replacing double slashes. - name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + result = IdeContextual::getFileBySourceArchiveName(name) } diff --git a/java/ql/lib/IDEContextual.qll b/java/ql/lib/IDEContextual.qll index f4e6267fdcf..f26956bcca0 100644 --- a/java/ql/lib/IDEContextual.qll +++ b/java/ql/lib/IDEContextual.qll @@ -3,6 +3,7 @@ */ import semmle.files.FileSystem +private import codeql.util.FileSystem /** * Returns the `File` matching the given source file name as encoded by the VS @@ -10,13 +11,5 @@ import semmle.files.FileSystem */ cached File getFileBySourceArchiveName(string name) { - // The name provided for a file in the source archive by the VS Code extension - // has some differences from the absolute path in the database: - // 1. colons are replaced by underscores - // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> - // "/C_/foo/bar" - // 3. double slashes in UNC prefixes are replaced with a single slash - // We can handle 2 and 3 together by unconditionally adding a leading slash - // before replacing double slashes. - name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + result = IdeContextual::getFileBySourceArchiveName(name) } diff --git a/javascript/ql/lib/IDEContextual.qll b/javascript/ql/lib/IDEContextual.qll index f4e6267fdcf..f26956bcca0 100644 --- a/javascript/ql/lib/IDEContextual.qll +++ b/javascript/ql/lib/IDEContextual.qll @@ -3,6 +3,7 @@ */ import semmle.files.FileSystem +private import codeql.util.FileSystem /** * Returns the `File` matching the given source file name as encoded by the VS @@ -10,13 +11,5 @@ import semmle.files.FileSystem */ cached File getFileBySourceArchiveName(string name) { - // The name provided for a file in the source archive by the VS Code extension - // has some differences from the absolute path in the database: - // 1. colons are replaced by underscores - // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> - // "/C_/foo/bar" - // 3. double slashes in UNC prefixes are replaced with a single slash - // We can handle 2 and 3 together by unconditionally adding a leading slash - // before replacing double slashes. - name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + result = IdeContextual::getFileBySourceArchiveName(name) } diff --git a/python/ql/lib/analysis/IDEContextual.qll b/python/ql/lib/analysis/IDEContextual.qll index f4e6267fdcf..f26956bcca0 100644 --- a/python/ql/lib/analysis/IDEContextual.qll +++ b/python/ql/lib/analysis/IDEContextual.qll @@ -3,6 +3,7 @@ */ import semmle.files.FileSystem +private import codeql.util.FileSystem /** * Returns the `File` matching the given source file name as encoded by the VS @@ -10,13 +11,5 @@ import semmle.files.FileSystem */ cached File getFileBySourceArchiveName(string name) { - // The name provided for a file in the source archive by the VS Code extension - // has some differences from the absolute path in the database: - // 1. colons are replaced by underscores - // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> - // "/C_/foo/bar" - // 3. double slashes in UNC prefixes are replaced with a single slash - // We can handle 2 and 3 together by unconditionally adding a leading slash - // before replacing double slashes. - name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + result = IdeContextual::getFileBySourceArchiveName(name) } diff --git a/ql/ql/src/codeql/IDEContextual.qll b/ql/ql/src/codeql/IDEContextual.qll index 0e58b1d878b..1c267d8f164 100644 --- a/ql/ql/src/codeql/IDEContextual.qll +++ b/ql/ql/src/codeql/IDEContextual.qll @@ -1,4 +1,5 @@ private import codeql.files.FileSystem +private import codeql.util.FileSystem /** * Returns an appropriately encoded version of a filename `name` @@ -7,13 +8,5 @@ private import codeql.files.FileSystem */ cached File getFileBySourceArchiveName(string name) { - // The name provided for a file in the source archive by the VS Code extension - // has some differences from the absolute path in the database: - // 1. colons are replaced by underscores - // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> - // "/C_/foo/bar" - // 3. double slashes in UNC prefixes are replaced with a single slash - // We can handle 2 and 3 together by unconditionally adding a leading slash - // before replacing double slashes. - name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + result = IdeContextual::getFileBySourceArchiveName(name) } diff --git a/ruby/ql/lib/codeql/IDEContextual.qll b/ruby/ql/lib/codeql/IDEContextual.qll index 0e58b1d878b..3b8486b4526 100644 --- a/ruby/ql/lib/codeql/IDEContextual.qll +++ b/ruby/ql/lib/codeql/IDEContextual.qll @@ -1,4 +1,9 @@ +/** + * Provides shared predicates related to contextual queries in the code viewer. + */ + private import codeql.files.FileSystem +private import codeql.util.FileSystem /** * Returns an appropriately encoded version of a filename `name` @@ -7,13 +12,5 @@ private import codeql.files.FileSystem */ cached File getFileBySourceArchiveName(string name) { - // The name provided for a file in the source archive by the VS Code extension - // has some differences from the absolute path in the database: - // 1. colons are replaced by underscores - // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> - // "/C_/foo/bar" - // 3. double slashes in UNC prefixes are replaced with a single slash - // We can handle 2 and 3 together by unconditionally adding a leading slash - // before replacing double slashes. - name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + result = IdeContextual::getFileBySourceArchiveName(name) } diff --git a/shared/util/codeql/util/FileSystem.qll b/shared/util/codeql/util/FileSystem.qll index e742ad87c40..a9eb21279b6 100644 --- a/shared/util/codeql/util/FileSystem.qll +++ b/shared/util/codeql/util/FileSystem.qll @@ -219,3 +219,140 @@ module Make { override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } } } + +/** A file. */ +signature class FileSig { + /** + * Gets the absolute, canonical path of this container, using forward slashes + * as path separator. + * + * The path starts with a _root prefix_ followed by zero or more _path + * segments_ separated by forward slashes. + * + * The root prefix is of one of the following forms: + * + * 1. A single forward slash `/` (Unix-style) + * 2. An upper-case drive letter followed by a colon and a forward slash, + * such as `C:/` (Windows-style) + * 3. Two forward slashes, a computer name, and then another forward slash, + * such as `//FileServer/` (UNC-style) + * + * Path segments are never empty (that is, absolute paths never contain two + * contiguous slashes, except as part of a UNC-style root prefix). Also, path + * segments never contain forward slashes, and no path segment is of the + * form `.` (one dot) or `..` (two dots). + * + * Note that an absolute path never ends with a forward slash, except if it is + * a bare root prefix, that is, the path has no path segments. A container + * whose absolute path has no segments is always a `Folder`, not a `File`. + */ + string getAbsolutePath(); + + /** + * Gets the base name of this container including extension, that is, the last + * segment of its absolute path, or the empty string if it has no segments. + * + * Here are some examples of absolute paths and the corresponding base names + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + * + *
Absolute pathBase name
"/tmp/tst.txt""tst.txt"
"C:/Program Files (x86)""Program Files (x86)"
"/"""
"C:/"""
"D:/"""
"//FileServer/"""
+ */ + string getBaseName(); + + /** + * Gets the extension of this container, that is, the suffix of its base name + * after the last dot character, if any. + * + * In particular, + * + * - if the name does not include a dot, there is no extension, so this + * predicate has no result; + * - if the name ends in a dot, the extension is the empty string; + * - if the name contains multiple dots, the extension follows the last dot. + * + * Here are some examples of absolute paths and the corresponding extensions + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + *
Absolute pathExtension
"/tmp/tst.txt""txt"
"/tmp/.classpath""classpath"
"/bin/bash"not defined
"/tmp/tst2."""
"/tmp/x.tar.gz""gz"
+ */ + string getExtension(); + + /** + * Gets the relative path of this file or folder from the root folder of the + * analyzed source location. The relative path of the root folder itself is + * the empty string. + * + * This has no result if the container is outside the source root, that is, + * if the root folder is not a reflexive, transitive parent of this container. + */ + string getRelativePath(); + + /** + * Gets the stem of this container, that is, the prefix of its base name up to + * (but not including) the last dot character if there is one, or the entire + * base name if there is not. + * + * Here are some examples of absolute paths and the corresponding stems + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + *
Absolute pathStem
"/tmp/tst.txt""tst"
"/tmp/.classpath"""
"/bin/bash""bash"
"/tmp/tst2.""tst2"
"/tmp/x.tar.gz""x.tar"
+ */ + string getStem(); + + /** + * Gets a URL representing the location of this container. + * + * For more information see https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls. + */ + string getURL(); + + /** + * Gets a textual representation of the path of this container. + * + * This is the absolute path of the container. + */ + string toString(); +} + +/** + * Provides shared predicates related to contextual queries in the code viewer. + */ +module IdeContextual { + /** + * Returns the `File` matching the given source file name as encoded by the VS + * Code extension. + */ + File getFileBySourceArchiveName(string name) { + // The name provided for a file in the source archive by the VS Code extension + // has some differences from the absolute path in the database: + // 1. colons are replaced by underscores + // 2. there's a leading slash, even for Windows paths: "C:/foo/bar" -> + // "/C_/foo/bar" + // 3. double slashes in UNC prefixes are replaced with a single slash + // We can handle 2 and 3 together by unconditionally adding a leading slash + // before replacing double slashes. + name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/") + } +}