From 18c629639b2e3f7ab2640223b82677e69283a2c8 Mon Sep 17 00:00:00 2001 From: agius Date: Wed, 2 Sep 2020 11:22:11 -0400 Subject: [PATCH 1/2] Add location metadata for LeafNode type Adds location-fetching methods to LeafNode, allowing you to click through from a node selection to the source location in VS Code. Adds CodeQL classes for File, Folder, Location, and Locatable, all basically ripped from the JS CodeQL library. Also adds a CodeQL tests/ dir which can be run using `codeql test run ql/test` , and added that to the CI suite. This may replace the existing e2e CodeQL runner currently in Ruby, following [PoLA](https://en.wikipedia.org/wiki/Principle_of_least_astonishment) for CodeQL development. See [Semmle help documentation](https://help.semmle.com/codeql/codeql-cli/procedures/test-queries.html) on testing CodeQL custom queries and libraries. --- .codeqlmanifest.json | 13 +- .github/workflows/continuous-integration.yml | 9 +- extractor/codeql-extractor.yml | 2 +- extractor/tools/index.sh | 20 ++ lib/codeql_ruby/extractor_file.rb | 1 + ql/src/Files.qll | 203 ++++++++++++++++++ ql/src/LeafNode.qll | 6 +- ql/src/Locations.qll | 110 ++++++++++ ql/src/ruby.qll | 2 + .../leaf_node_location.expected | 4 + .../leaf_node_location/leaf_node_location.ql | 4 + .../leaf_node_location/leaf_node_location.rb | 1 + ql/test/qlpack.yml | 4 + 13 files changed, 372 insertions(+), 7 deletions(-) create mode 100755 extractor/tools/index.sh create mode 100644 ql/src/Files.qll create mode 100644 ql/src/Locations.qll create mode 100644 ql/test/leaf_node_location/leaf_node_location.expected create mode 100644 ql/test/leaf_node_location/leaf_node_location.ql create mode 100644 ql/test/leaf_node_location/leaf_node_location.rb create mode 100644 ql/test/qlpack.yml diff --git a/.codeqlmanifest.json b/.codeqlmanifest.json index c467eb1..ea665e8 100644 --- a/.codeqlmanifest.json +++ b/.codeqlmanifest.json @@ -1,3 +1,10 @@ -{ "provide": [ "ql/src/qlpack.yml", - "extractor/codeql-extractor.yml" ], - "ignore": [ "the-extractor-which-needs-to-be-built" ] } +{ + "provide": [ + "ql/src/qlpack.yml", + "ql/test/qlpack.yml", + "extractor/codeql-extractor.yml" + ], + "ignore": [ + "the-extractor-which-needs-to-be-built" + ] +} diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index a7157a5..f858511 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -80,12 +80,19 @@ jobs: bundle config path vendor/bundle bundle install --jobs 4 --retry 3 - - name: Build & run specs + - name: Build & run Ruby specs env: CODEQL_PATH: "$GITHUB_WORKSPACE/codeql/codeql" working-directory: ./codeql-ruby run: | bundle exec rake spec:ci + + - name: Run CodeQL Tests + env: + CODEQL_PATH: "$GITHUB_WORKSPACE/codeql/codeql" + working-directory: ./codeql-ruby + run: | + codeql test run ql/test # - name: Setup tmate session # uses: mxschmitt/action-tmate@v2 diff --git a/extractor/codeql-extractor.yml b/extractor/codeql-extractor.yml index a52bba6..1d3ab21 100644 --- a/extractor/codeql-extractor.yml +++ b/extractor/codeql-extractor.yml @@ -8,4 +8,4 @@ file_types: display_name: Ruby extensions: - .rb -legacy_qltest_extraction: false +legacy_qltest_extraction: true diff --git a/extractor/tools/index.sh b/extractor/tools/index.sh new file mode 100755 index 0000000..af20d8e --- /dev/null +++ b/extractor/tools/index.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +#################################################################################### +# +# Required for running `codeql test run my/test/dir` +# when legacy_qltest_extraction is set to true in ruby/codeql-extractor.yml +# +# +# FIXME: figure out what "non-legacy" test extraction looks like and how it works +# +#################################################################################### + +set -eu + +if [ "$CODEQL_PLATFORM" != "linux64" ] && [ "$CODEQL_PLATFORM" != "osx64" ] ; then + echo "Automatic build detection for $CODEQL_PLATFORM is not implemented." + exit 1 +fi + +"$CODEQL_EXTRACTOR_RUBY_ROOT/tools/$CODEQL_PLATFORM/ruby-autobuilder" diff --git a/lib/codeql_ruby/extractor_file.rb b/lib/codeql_ruby/extractor_file.rb index 04e0271..c149c3e 100644 --- a/lib/codeql_ruby/extractor_file.rb +++ b/lib/codeql_ruby/extractor_file.rb @@ -1,4 +1,5 @@ require 'forwardable' +require 'pathname' module CodeqlRuby class ExtractorFile diff --git a/ql/src/Files.qll b/ql/src/Files.qll new file mode 100644 index 0000000..1956395 --- /dev/null +++ b/ql/src/Files.qll @@ -0,0 +1,203 @@ +/** + * Provides classes for working with files and folders. + * + * Stolen liberally from the Javascript QLL + * https://github.com/github/codeql/blob/813d14791d6bea399bc96fa9b7143603eef6e6c4/javascript/ql/src/semmle/javascript/Files.qll + * + */ + +import ruby + +/** A file or folder. */ +abstract class Container extends @container { + /** + * 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`. + */ + abstract string getAbsolutePath(); + + /** + * Gets a URL representing the location of this container. + * + * For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls). + */ + abstract string getURL(); + + /** + * 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() { + exists(string absPath, string pref | + absPath = getAbsolutePath() and sourceLocationPrefix(pref) + | + absPath = pref and result = "" + or + absPath = pref.regexpReplaceAll("/$", "") + "/" + result and + not result.matches("/%") + ) + } + + /** + * 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.js""tst.js"
"C:/Program Files (x86)""Program Files (x86)"
"/"""
"C:/"""
"D:/"""
"//FileServer/"""
+ */ + string getBaseName() { result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 1) } + + /** + * 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.js""js"
"/tmp/.classpath""classpath"
"/bin/bash"not defined
"/tmp/tst2."""
"/tmp/x.tar.gz""gz"
+ */ + string getExtension() { + result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 4) + } + + /** + * 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.js""tst"
"/tmp/.classpath"""
"/bin/bash""bash"
"/tmp/tst2.""tst2"
"/tmp/x.tar.gz""x.tar"
+ */ + string getStem() { result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 2) } + + /** Gets the parent container of this file or folder, if any. */ + Container getParentContainer() { containerparent(result, this) } + + /** Gets a file or sub-folder in this container. */ + Container getAChildContainer() { this = result.getParentContainer() } + + /** Gets a file in this container. */ + File getAFile() { result = getAChildContainer() } + + /** Gets the file in this container that has the given `baseName`, if any. */ + File getFile(string baseName) { + result = getAFile() and + result.getBaseName() = baseName + } + + /** Gets a sub-folder in this container. */ + Folder getAFolder() { result = getAChildContainer() } + + /** Gets the sub-folder in this container that has the given `baseName`, if any. */ + Folder getFolder(string baseName) { + result = getAFolder() and + result.getBaseName() = baseName + } + + /** + * Gets a textual representation of the path of this container. + * + * This is the absolute path of the container. + */ + string toString() { result = getAbsolutePath() } +} + +/** A folder. */ +class Folder extends Container, @folder { + override string getAbsolutePath() { folders(this, result, _) } + + /** Gets the file or subfolder in this folder that has the given `name`, if any. */ + Container getChildContainer(string name) { + result = getAChildContainer() and + result.getBaseName() = name + } + + /** Gets the file in this folder that has the given `stem` and `extension`, if any. */ + File getFile(string stem, string extension) { + result = getAChildContainer() and + result.getStem() = stem and + result.getExtension() = extension + } + + /** Gets a subfolder contained in this folder. */ + Folder getASubFolder() { result = getAChildContainer() } + + /** Gets the URL of this folder. */ + override string getURL() { result = "folder://" + getAbsolutePath() } +} + +/** A file. */ +class File extends Container, @file { + override string getAbsolutePath() { files(this, result, _, _, _) } + + /** Gets the number of lines in this file. */ + int getNumberOfLines() { result = sum(int loc | numlines(this, loc, _, _) | loc) } + + /** Gets the number of lines containing code in this file. */ + int getNumberOfLinesOfCode() { result = sum(int loc | numlines(this, _, loc, _) | loc) } + + /** Gets the number of lines containing comments in this file. */ + int getNumberOfLinesOfComments() { result = sum(int loc | numlines(this, _, _, loc) | loc) } + + override string toString() { result = Container.super.toString() } + + /** Gets the URL of this file. */ + override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } +} \ No newline at end of file diff --git a/ql/src/LeafNode.qll b/ql/src/LeafNode.qll index e3c369c..db967b6 100644 --- a/ql/src/LeafNode.qll +++ b/ql/src/LeafNode.qll @@ -14,8 +14,10 @@ import ruby * 1 * ``` */ -class LeafNode extends @leaf_node { +class LeafNode extends @leaf_node, Locatable { string getText() { leaf_nodes(this, result, _, _) } - string toString() { result = "LeafNode" } + override Location getLocation() { has_location(this, result) } + + override string toString() { result = "LeafNode" } } diff --git a/ql/src/Locations.qll b/ql/src/Locations.qll new file mode 100644 index 0000000..b26f3d7 --- /dev/null +++ b/ql/src/Locations.qll @@ -0,0 +1,110 @@ +/** + * Provides classes for working with locations and program elements that have locations. + * + * Stolen liberally from the Javascript QL library: + * https://github.com/github/codeql/blob/813d14791d6bea399bc96fa9b7143603eef6e6c4/javascript/ql/src/semmle/javascript/Locations.qll + * + */ + +import ruby + +/** + * A location as given by a file, a start line, a start column, + * an end line, and an end column. + * + * For more information about locations see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +class Location extends @location { + /** Gets the file for this location. */ + File getFile() { locations_default(this, result, _, _, _, _) } + + /** Gets the 1-based line number (inclusive) where this location starts. */ + int getStartLine() { locations_default(this, _, result, _, _, _) } + + /** Gets the 1-based column number (inclusive) where this location starts. */ + int getStartColumn() { locations_default(this, _, _, result, _, _) } + + /** Gets the 1-based line number (inclusive) where this location ends. */ + int getEndLine() { locations_default(this, _, _, _, result, _) } + + /** Gets the 1-based column number (inclusive) where this location ends. */ + int getEndColumn() { locations_default(this, _, _, _, _, result) } + + /** Gets the number of lines covered by this location. */ + int getNumLines() { result = getEndLine() - getStartLine() + 1 } + + /** Holds if this location starts before location `that`. */ + pragma[inline] + predicate startsBefore(Location that) { + exists(File f, int sl1, int sc1, int sl2, int sc2 | + locations_default(this, f, sl1, sc1, _, _) and + locations_default(that, f, sl2, sc2, _, _) + | + sl1 < sl2 + or + sl1 = sl2 and sc1 < sc2 + ) + } + + /** Holds if this location ends after location `that`. */ + pragma[inline] + predicate endsAfter(Location that) { + exists(File f, int el1, int ec1, int el2, int ec2 | + locations_default(this, f, _, _, el1, ec1) and + locations_default(that, f, _, _, el2, ec2) + | + el1 > el2 + or + el1 = el2 and ec1 > ec2 + ) + } + + /** + * Holds if this location contains location `that`, meaning that it starts + * before and ends after it. + */ + predicate contains(Location that) { this.startsBefore(that) and this.endsAfter(that) } + + /** Holds if this location is empty. */ + predicate isEmpty() { exists(int l, int c | locations_default(this, _, l, c, l, c - 1)) } + + /** Gets a textual representation of this element. */ + string toString() { result = this.getFile().getBaseName() + ":" + this.getStartLine().toString() } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(File f | + locations_default(this, f, startline, startcolumn, endline, endcolumn) and + filepath = f.getAbsolutePath() + ) + } +} + +/** A program element with a location. */ +class Locatable extends @locatable { + /** Gets the file this program element comes from. */ + File getFile() { result = getLocation().getFile() } + + /** Gets this element's location. */ + Location getLocation() { + // overridden by subclasses + none() + } + + /** Gets the number of lines covered by this element. */ + int getNumLines() { result = getLocation().getNumLines() } + + /** Gets a textual representation of this element. */ + string toString() { + // to be overridden by subclasses + none() + } +} \ No newline at end of file diff --git a/ql/src/ruby.qll b/ql/src/ruby.qll index ccb590d..421d107 100644 --- a/ql/src/ruby.qll +++ b/ql/src/ruby.qll @@ -1,2 +1,4 @@ +import Files +import Locations import LeafNode \ No newline at end of file diff --git a/ql/test/leaf_node_location/leaf_node_location.expected b/ql/test/leaf_node_location/leaf_node_location.expected new file mode 100644 index 0000000..e871bb8 --- /dev/null +++ b/ql/test/leaf_node_location/leaf_node_location.expected @@ -0,0 +1,4 @@ +| leaf_node_location.rb:1:0:1:4 | LeafNode | puts | leaf_node_location.rb:1 | +| leaf_node_location.rb:1:0:1:4 | LeafNode | puts | leaf_node_location.rb:1 | +| leaf_node_location.rb:1:6:1:40 | LeafNode | this file contains some leaf nodes | leaf_node_location.rb:1 | +| leaf_node_location.rb:1:6:1:40 | LeafNode | this file contains some leaf nodes | leaf_node_location.rb:1 | diff --git a/ql/test/leaf_node_location/leaf_node_location.ql b/ql/test/leaf_node_location/leaf_node_location.ql new file mode 100644 index 0000000..bcc9f67 --- /dev/null +++ b/ql/test/leaf_node_location/leaf_node_location.ql @@ -0,0 +1,4 @@ +import ruby + +from LeafNode n +select n, n.getText(), n.getLocation().toString() \ No newline at end of file diff --git a/ql/test/leaf_node_location/leaf_node_location.rb b/ql/test/leaf_node_location/leaf_node_location.rb new file mode 100644 index 0000000..2d8e36d --- /dev/null +++ b/ql/test/leaf_node_location/leaf_node_location.rb @@ -0,0 +1 @@ +puts 'this file contains some leaf nodes' \ No newline at end of file diff --git a/ql/test/qlpack.yml b/ql/test/qlpack.yml new file mode 100644 index 0000000..6a5b743 --- /dev/null +++ b/ql/test/qlpack.yml @@ -0,0 +1,4 @@ +name: codeql-ruby-tests +version: 0.0.0 +libraryPathDependencies: codeql-ruby +extractor: ruby \ No newline at end of file From 26ad66679303a4270f252de141fa515a90406b47 Mon Sep 17 00:00:00 2001 From: agius Date: Fri, 4 Sep 2020 13:36:56 -0400 Subject: [PATCH 2/2] Remove codeql CLI-based testing, fix editorconfig issues --- .codeqlmanifest.json | 13 ++++++------ .github/workflows/continuous-integration.yml | 7 ------- extractor/codeql-extractor.yml | 2 +- extractor/tools/index.sh | 20 ------------------- ql/src/Files.qll | 10 +++++----- ql/src/Locations.qll | 10 +++++----- ql/src/ruby.qll | 2 +- .../leaf_node_location.expected | 4 ---- .../leaf_node_location/leaf_node_location.ql | 4 ---- .../leaf_node_location/leaf_node_location.rb | 1 - spec/codeql_ruby_spec.rb | 7 +++++++ spec/leaf_node_location/example.ql | 4 ++++ spec/leaf_node_location/leaf_node_location.rb | 1 + .../leaf_node_location}/qlpack.yml | 3 +-- 14 files changed, 31 insertions(+), 57 deletions(-) delete mode 100755 extractor/tools/index.sh delete mode 100644 ql/test/leaf_node_location/leaf_node_location.expected delete mode 100644 ql/test/leaf_node_location/leaf_node_location.ql delete mode 100644 ql/test/leaf_node_location/leaf_node_location.rb create mode 100644 spec/leaf_node_location/example.ql create mode 100644 spec/leaf_node_location/leaf_node_location.rb rename {ql/test => spec/leaf_node_location}/qlpack.yml (57%) diff --git a/.codeqlmanifest.json b/.codeqlmanifest.json index ea665e8..7a76f3a 100644 --- a/.codeqlmanifest.json +++ b/.codeqlmanifest.json @@ -1,10 +1,9 @@ -{ - "provide": [ +{ + "provide": [ "ql/src/qlpack.yml", - "ql/test/qlpack.yml", - "extractor/codeql-extractor.yml" + "extractor/codeql-extractor.yml" ], - "ignore": [ - "the-extractor-which-needs-to-be-built" - ] + "ignore": [ + "the-extractor-which-needs-to-be-built" + ] } diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index f858511..c9c5a40 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -86,13 +86,6 @@ jobs: working-directory: ./codeql-ruby run: | bundle exec rake spec:ci - - - name: Run CodeQL Tests - env: - CODEQL_PATH: "$GITHUB_WORKSPACE/codeql/codeql" - working-directory: ./codeql-ruby - run: | - codeql test run ql/test # - name: Setup tmate session # uses: mxschmitt/action-tmate@v2 diff --git a/extractor/codeql-extractor.yml b/extractor/codeql-extractor.yml index 1d3ab21..a52bba6 100644 --- a/extractor/codeql-extractor.yml +++ b/extractor/codeql-extractor.yml @@ -8,4 +8,4 @@ file_types: display_name: Ruby extensions: - .rb -legacy_qltest_extraction: true +legacy_qltest_extraction: false diff --git a/extractor/tools/index.sh b/extractor/tools/index.sh deleted file mode 100755 index af20d8e..0000000 --- a/extractor/tools/index.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -#################################################################################### -# -# Required for running `codeql test run my/test/dir` -# when legacy_qltest_extraction is set to true in ruby/codeql-extractor.yml -# -# -# FIXME: figure out what "non-legacy" test extraction looks like and how it works -# -#################################################################################### - -set -eu - -if [ "$CODEQL_PLATFORM" != "linux64" ] && [ "$CODEQL_PLATFORM" != "osx64" ] ; then - echo "Automatic build detection for $CODEQL_PLATFORM is not implemented." - exit 1 -fi - -"$CODEQL_EXTRACTOR_RUBY_ROOT/tools/$CODEQL_PLATFORM/ruby-autobuilder" diff --git a/ql/src/Files.qll b/ql/src/Files.qll index 1956395..8518b1c 100644 --- a/ql/src/Files.qll +++ b/ql/src/Files.qll @@ -1,9 +1,9 @@ -/** - * Provides classes for working with files and folders. - * +/** + * Provides classes for working with files and folders. + * * Stolen liberally from the Javascript QLL * https://github.com/github/codeql/blob/813d14791d6bea399bc96fa9b7143603eef6e6c4/javascript/ql/src/semmle/javascript/Files.qll - * + * */ import ruby @@ -200,4 +200,4 @@ class File extends Container, @file { /** Gets the URL of this file. */ override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } -} \ No newline at end of file +} diff --git a/ql/src/Locations.qll b/ql/src/Locations.qll index b26f3d7..7b64ac5 100644 --- a/ql/src/Locations.qll +++ b/ql/src/Locations.qll @@ -1,9 +1,9 @@ -/** - * Provides classes for working with locations and program elements that have locations. - * +/** + * Provides classes for working with locations and program elements that have locations. + * * Stolen liberally from the Javascript QL library: * https://github.com/github/codeql/blob/813d14791d6bea399bc96fa9b7143603eef6e6c4/javascript/ql/src/semmle/javascript/Locations.qll - * + * */ import ruby @@ -107,4 +107,4 @@ class Locatable extends @locatable { // to be overridden by subclasses none() } -} \ No newline at end of file +} diff --git a/ql/src/ruby.qll b/ql/src/ruby.qll index 421d107..34ae5bf 100644 --- a/ql/src/ruby.qll +++ b/ql/src/ruby.qll @@ -1,4 +1,4 @@ import Files import Locations -import LeafNode \ No newline at end of file +import LeafNode diff --git a/ql/test/leaf_node_location/leaf_node_location.expected b/ql/test/leaf_node_location/leaf_node_location.expected deleted file mode 100644 index e871bb8..0000000 --- a/ql/test/leaf_node_location/leaf_node_location.expected +++ /dev/null @@ -1,4 +0,0 @@ -| leaf_node_location.rb:1:0:1:4 | LeafNode | puts | leaf_node_location.rb:1 | -| leaf_node_location.rb:1:0:1:4 | LeafNode | puts | leaf_node_location.rb:1 | -| leaf_node_location.rb:1:6:1:40 | LeafNode | this file contains some leaf nodes | leaf_node_location.rb:1 | -| leaf_node_location.rb:1:6:1:40 | LeafNode | this file contains some leaf nodes | leaf_node_location.rb:1 | diff --git a/ql/test/leaf_node_location/leaf_node_location.ql b/ql/test/leaf_node_location/leaf_node_location.ql deleted file mode 100644 index bcc9f67..0000000 --- a/ql/test/leaf_node_location/leaf_node_location.ql +++ /dev/null @@ -1,4 +0,0 @@ -import ruby - -from LeafNode n -select n, n.getText(), n.getLocation().toString() \ No newline at end of file diff --git a/ql/test/leaf_node_location/leaf_node_location.rb b/ql/test/leaf_node_location/leaf_node_location.rb deleted file mode 100644 index 2d8e36d..0000000 --- a/ql/test/leaf_node_location/leaf_node_location.rb +++ /dev/null @@ -1 +0,0 @@ -puts 'this file contains some leaf nodes' \ No newline at end of file diff --git a/spec/codeql_ruby_spec.rb b/spec/codeql_ruby_spec.rb index 88da23c..4333f25 100644 --- a/spec/codeql_ruby_spec.rb +++ b/spec/codeql_ruby_spec.rb @@ -26,4 +26,11 @@ expect(results).to be_a(String) end + + it "extracts Location info from LeafNodes" do + results = CodeqlRunner.results_for_db('leaf_node_location') + tuples = results.dig('#select', 'tuples') + + expect(tuples).to include([{'label'=>'LeafNode'}, 'puts', 'leaf_node_location.rb:1']) + end end diff --git a/spec/leaf_node_location/example.ql b/spec/leaf_node_location/example.ql new file mode 100644 index 0000000..2f7ab02 --- /dev/null +++ b/spec/leaf_node_location/example.ql @@ -0,0 +1,4 @@ +import ruby + +from LeafNode n +select n, n.getText(), n.getLocation().toString() diff --git a/spec/leaf_node_location/leaf_node_location.rb b/spec/leaf_node_location/leaf_node_location.rb new file mode 100644 index 0000000..910b705 --- /dev/null +++ b/spec/leaf_node_location/leaf_node_location.rb @@ -0,0 +1 @@ +puts 'this file contains some leaf nodes' diff --git a/ql/test/qlpack.yml b/spec/leaf_node_location/qlpack.yml similarity index 57% rename from ql/test/qlpack.yml rename to spec/leaf_node_location/qlpack.yml index 6a5b743..d18b613 100644 --- a/ql/test/qlpack.yml +++ b/spec/leaf_node_location/qlpack.yml @@ -1,4 +1,3 @@ -name: codeql-ruby-tests +name: leaf-node-location-ruby-queries version: 0.0.0 libraryPathDependencies: codeql-ruby -extractor: ruby \ No newline at end of file