mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Rust: first running tests
This commit is contained in:
6
rust/.generated.list
generated
6
rust/.generated.list
generated
@@ -3,8 +3,6 @@ ql/lib/codeql/rust/elements/DbFileConstructor.qll ea93dc49b23b1c6d800ab9d0b9cacf
|
|||||||
ql/lib/codeql/rust/elements/DbLocation.qll 1f694594e8e4ab65a8781cd443ad4f864447ca88e2cb65504aee5a779393c84d 003ec72275406eb8f5ddd6ccc2b258fb7c906d4bb2c0ef1ba235f291624321ca
|
ql/lib/codeql/rust/elements/DbLocation.qll 1f694594e8e4ab65a8781cd443ad4f864447ca88e2cb65504aee5a779393c84d 003ec72275406eb8f5ddd6ccc2b258fb7c906d4bb2c0ef1ba235f291624321ca
|
||||||
ql/lib/codeql/rust/elements/DbLocationConstructor.qll 8848abace985818a5d3a6eddfc4cb200795970146d282b037b4f22ae6230b894 44dba880e17bb1072fa12451ccaae4830fd04dcc61f7403d35510309fde6906e
|
ql/lib/codeql/rust/elements/DbLocationConstructor.qll 8848abace985818a5d3a6eddfc4cb200795970146d282b037b4f22ae6230b894 44dba880e17bb1072fa12451ccaae4830fd04dcc61f7403d35510309fde6906e
|
||||||
ql/lib/codeql/rust/elements/Declaration.qll d4ec5c83728f1837243caf2f27d06fd05ecdd2ca440112accff99bfd37b45e5f c1cd9b297be8b69207e75d24b29949b9f71c78406ee0ffd38d0b0810288d6140
|
ql/lib/codeql/rust/elements/Declaration.qll d4ec5c83728f1837243caf2f27d06fd05ecdd2ca440112accff99bfd37b45e5f c1cd9b297be8b69207e75d24b29949b9f71c78406ee0ffd38d0b0810288d6140
|
||||||
ql/lib/codeql/rust/elements/Element.qll 2bffdeb8863a9853d019e56afa268b3d39fb3687785ad636b159656c199997ca 18020582c7d1b89f4073b6deaf793c3072fdc52503a6cc53172c96282f141de4
|
|
||||||
ql/lib/codeql/rust/elements/File.qll 75144234638417347107b75db80c561379e6372859ebc463276aef716e0ed42b 55bb468873acf24e6828faf7be3ff8963c9a4eb344bfedd95328a51b6f00a226
|
|
||||||
ql/lib/codeql/rust/elements/Function.qll 220eb1d0e6b49e83b7674a9f505d3f529cf7f4d022ddca44fa6367e0d75daa0f d156cff59ecdcffc0d62041b801025b1aaedbc92d44efd107f93f6fd06c34a6d
|
ql/lib/codeql/rust/elements/Function.qll 220eb1d0e6b49e83b7674a9f505d3f529cf7f4d022ddca44fa6367e0d75daa0f d156cff59ecdcffc0d62041b801025b1aaedbc92d44efd107f93f6fd06c34a6d
|
||||||
ql/lib/codeql/rust/elements/FunctionConstructor.qll a9269b37182c0bf432f9b2b015691da5dbd64819b9bd25445af229d873014a91 69107a7503af14a51e091e6918094a4e9fc316a72de2e1514f001872ce0f2c0c
|
ql/lib/codeql/rust/elements/FunctionConstructor.qll a9269b37182c0bf432f9b2b015691da5dbd64819b9bd25445af229d873014a91 69107a7503af14a51e091e6918094a4e9fc316a72de2e1514f001872ce0f2c0c
|
||||||
ql/lib/codeql/rust/elements/Locatable.qll dfc0235cf5aff0ec91d85375ac03998b0e6a69f3722b099330ab0a2161af988a bb1055f59ef7e95e89748765c79f1b5832aa18226f227e689a6801adfc6247ad
|
ql/lib/codeql/rust/elements/Locatable.qll dfc0235cf5aff0ec91d85375ac03998b0e6a69f3722b099330ab0a2161af988a bb1055f59ef7e95e89748765c79f1b5832aa18226f227e689a6801adfc6247ad
|
||||||
@@ -30,6 +28,6 @@ ql/lib/codeql/rust/generated/Synth.qll d278de9c2d06cb7549cd8f2e10ed186827a2ceab6
|
|||||||
ql/lib/codeql/rust/generated/SynthConstructors.qll 35b36df0c4fff05bcbd4ed10b1e6fa2e58fe8d8c818e7805111044825788fc01 35b36df0c4fff05bcbd4ed10b1e6fa2e58fe8d8c818e7805111044825788fc01
|
ql/lib/codeql/rust/generated/SynthConstructors.qll 35b36df0c4fff05bcbd4ed10b1e6fa2e58fe8d8c818e7805111044825788fc01 35b36df0c4fff05bcbd4ed10b1e6fa2e58fe8d8c818e7805111044825788fc01
|
||||||
ql/lib/codeql/rust/generated/UnknownFile.qll ec9d1a3f15ecbf1743d4e39cb3b2f217aa9b54951c93302c2c4c238c3f0ce595 ec9d1a3f15ecbf1743d4e39cb3b2f217aa9b54951c93302c2c4c238c3f0ce595
|
ql/lib/codeql/rust/generated/UnknownFile.qll ec9d1a3f15ecbf1743d4e39cb3b2f217aa9b54951c93302c2c4c238c3f0ce595 ec9d1a3f15ecbf1743d4e39cb3b2f217aa9b54951c93302c2c4c238c3f0ce595
|
||||||
ql/lib/codeql/rust/generated/UnknownLocation.qll a19e2838c52d702d268ae530f3dbd6fcd8bb28a237a52636a960f225454103cf a19e2838c52d702d268ae530f3dbd6fcd8bb28a237a52636a960f225454103cf
|
ql/lib/codeql/rust/generated/UnknownLocation.qll a19e2838c52d702d268ae530f3dbd6fcd8bb28a237a52636a960f225454103cf a19e2838c52d702d268ae530f3dbd6fcd8bb28a237a52636a960f225454103cf
|
||||||
ql/test/extractor-tests/generated/File/MISSING_SOURCE.txt cc7c395e7c651d62596826b1a0bedf10f35d01b8afeef47600b4ddaf804f406e cc7c395e7c651d62596826b1a0bedf10f35d01b8afeef47600b4ddaf804f406e
|
ql/test/extractor-tests/generated/File/File.ql dec43be882fad904fab0c6447ca93633d801cb08ff8bec309befde7d2b9e5dda 74e1f1d698558c35fa03935cc34f4c8145d376b56d7657b18aeb338f5ca752cf
|
||||||
ql/test/extractor-tests/generated/Function/MISSING_SOURCE.txt cc7c395e7c651d62596826b1a0bedf10f35d01b8afeef47600b4ddaf804f406e cc7c395e7c651d62596826b1a0bedf10f35d01b8afeef47600b4ddaf804f406e
|
ql/test/extractor-tests/generated/Function/Function.ql ae5d44a85047d50d8fbd3b62290c6935f061f07076b0070998173957e54eb43f 3e7fb6fb82463b96577394213915d8deae5332acdec2fcc07aa3eb8560420edd
|
||||||
ql/test/extractor-tests/generated/Module/MISSING_SOURCE.txt cc7c395e7c651d62596826b1a0bedf10f35d01b8afeef47600b4ddaf804f406e cc7c395e7c651d62596826b1a0bedf10f35d01b8afeef47600b4ddaf804f406e
|
ql/test/extractor-tests/generated/Module/MISSING_SOURCE.txt cc7c395e7c651d62596826b1a0bedf10f35d01b8afeef47600b4ddaf804f406e cc7c395e7c651d62596826b1a0bedf10f35d01b8afeef47600b4ddaf804f406e
|
||||||
|
|||||||
6
rust/.gitattributes
generated
vendored
6
rust/.gitattributes
generated
vendored
@@ -5,8 +5,6 @@
|
|||||||
/ql/lib/codeql/rust/elements/DbLocation.qll linguist-generated
|
/ql/lib/codeql/rust/elements/DbLocation.qll linguist-generated
|
||||||
/ql/lib/codeql/rust/elements/DbLocationConstructor.qll linguist-generated
|
/ql/lib/codeql/rust/elements/DbLocationConstructor.qll linguist-generated
|
||||||
/ql/lib/codeql/rust/elements/Declaration.qll linguist-generated
|
/ql/lib/codeql/rust/elements/Declaration.qll linguist-generated
|
||||||
/ql/lib/codeql/rust/elements/Element.qll linguist-generated
|
|
||||||
/ql/lib/codeql/rust/elements/File.qll linguist-generated
|
|
||||||
/ql/lib/codeql/rust/elements/Function.qll linguist-generated
|
/ql/lib/codeql/rust/elements/Function.qll linguist-generated
|
||||||
/ql/lib/codeql/rust/elements/FunctionConstructor.qll linguist-generated
|
/ql/lib/codeql/rust/elements/FunctionConstructor.qll linguist-generated
|
||||||
/ql/lib/codeql/rust/elements/Locatable.qll linguist-generated
|
/ql/lib/codeql/rust/elements/Locatable.qll linguist-generated
|
||||||
@@ -32,6 +30,6 @@
|
|||||||
/ql/lib/codeql/rust/generated/SynthConstructors.qll linguist-generated
|
/ql/lib/codeql/rust/generated/SynthConstructors.qll linguist-generated
|
||||||
/ql/lib/codeql/rust/generated/UnknownFile.qll linguist-generated
|
/ql/lib/codeql/rust/generated/UnknownFile.qll linguist-generated
|
||||||
/ql/lib/codeql/rust/generated/UnknownLocation.qll linguist-generated
|
/ql/lib/codeql/rust/generated/UnknownLocation.qll linguist-generated
|
||||||
/ql/test/extractor-tests/generated/File/MISSING_SOURCE.txt linguist-generated
|
/ql/test/extractor-tests/generated/File/File.ql linguist-generated
|
||||||
/ql/test/extractor-tests/generated/Function/MISSING_SOURCE.txt linguist-generated
|
/ql/test/extractor-tests/generated/Function/Function.ql linguist-generated
|
||||||
/ql/test/extractor-tests/generated/Module/MISSING_SOURCE.txt linguist-generated
|
/ql/test/extractor-tests/generated/Module/MISSING_SOURCE.txt linguist-generated
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
This package aliases [`misc/codegen`](../misc/codegen) providing the Rust-specific options
|
|
||||||
in [`rust/codegen.conf`](../codegen.conf).
|
|
||||||
|
|
||||||
Running `bazel run //rust/codegen` will generate all checked in
|
|
||||||
files ([dbscheme](../ql/lib/swift.dbscheme), [QL generated code](../ql/lib/codeql/swift/generated),
|
|
||||||
[generated QL stubs](../ql/lib/codeql/swift/elements), [generated QL tests](../ql/test/extractor-tests/generated)).
|
|
||||||
@@ -2,6 +2,7 @@ name: "rust"
|
|||||||
display_name: "Rust"
|
display_name: "Rust"
|
||||||
version: 0.1.0
|
version: 0.1.0
|
||||||
column_kind: "utf8"
|
column_kind: "utf8"
|
||||||
|
legacy_qltest_extraction: true
|
||||||
build_modes:
|
build_modes:
|
||||||
- none
|
- none
|
||||||
github_api_languages:
|
github_api_languages:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use anyhow::Context;
|
||||||
use serde::{Deserialize, Serialize, Serializer, Deserializer};
|
use serde::{Deserialize, Serialize, Serializer, Deserializer};
|
||||||
use serde_with;
|
use serde_with;
|
||||||
use figment::{Figment, providers::{Env, Serialized}};
|
use figment::{Figment, providers::{Env, Serialized}};
|
||||||
@@ -48,7 +49,9 @@ struct CliArgs {
|
|||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
compression: Option<Compression>,
|
compression: Option<Compression>,
|
||||||
#[arg(short, long, action = ArgAction::Count)]
|
#[arg(short, long, action = ArgAction::Count)]
|
||||||
pub verbose: u8,
|
verbose: u8,
|
||||||
|
#[arg(long)]
|
||||||
|
inputs_file: Option<PathBuf>,
|
||||||
|
|
||||||
inputs: Vec<PathBuf>,
|
inputs: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
@@ -58,10 +61,15 @@ fn is_default<T: Default + PartialEq>(t: &T) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn extract() -> figment::Result<Config> {
|
pub fn extract() -> anyhow::Result<Config> {
|
||||||
Figment::new()
|
let mut cli_args = CliArgs::parse();
|
||||||
|
if let Some(inputs_file) = cli_args.inputs_file.take() {
|
||||||
|
let inputs_list = std::fs::read_to_string(inputs_file).context("reading file list")?;
|
||||||
|
cli_args.inputs.extend(inputs_list.split("\n").map(PathBuf::from));
|
||||||
|
}
|
||||||
|
Ok(Figment::new()
|
||||||
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_"))
|
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_"))
|
||||||
.merge(Serialized::defaults(CliArgs::parse()))
|
.merge(Serialized::defaults(cli_args))
|
||||||
.extract()
|
.extract().context("loading configuration")?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
prefill_caches: false,
|
prefill_caches: false,
|
||||||
};
|
};
|
||||||
for input in cfg.inputs {
|
for input in cfg.inputs {
|
||||||
load_workspace_at(&input, &config, &load_config, &no_progress)?;
|
let (db, vfs, _macro_server) = load_workspace_at(&input, &config, &load_config, &no_progress).context("loading inputs")?;
|
||||||
let (db, vfs, _macro_server) = load_workspace_at(&input, &config, &load_config, &no_progress)?;
|
|
||||||
let crates = <dyn DefDatabase>::crate_graph(&db);
|
let crates = <dyn DefDatabase>::crate_graph(&db);
|
||||||
for crate_id in crates.iter().take(1) {
|
for crate_id in crates.iter().take(1) {
|
||||||
let krate = Crate::from(crate_id);
|
let krate = Crate::from(crate_id);
|
||||||
@@ -49,7 +48,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
&krate,
|
&krate,
|
||||||
&vfs,
|
&vfs,
|
||||||
&archiver,
|
&archiver,
|
||||||
).emit_crate()?;
|
).emit_crate().context("writing trap file")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
// generated by codegen, remove this comment if you wish to edit this file
|
|
||||||
/**
|
/**
|
||||||
* This module provides a hand-modifiable wrapper around the generated class `Element`.
|
* This module provides a hand-modifiable wrapper around the generated class `Element`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.rust.generated.Element
|
private import codeql.rust.generated.Element
|
||||||
|
|
||||||
class Element extends Generated::Element { }
|
class Element extends Generated::Element {
|
||||||
|
predicate isUnknown() { none() } // compatibility with test generation, to be fixed
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,111 @@
|
|||||||
// generated by codegen, remove this comment if you wish to edit this file
|
|
||||||
/**
|
/**
|
||||||
* This module provides a hand-modifiable wrapper around the generated class `File`.
|
* This module provides a hand-modifiable wrapper around the generated class `File`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.rust.generated.File
|
private import codeql.rust.generated.File
|
||||||
|
private import codeql.rust.elements.Location
|
||||||
|
private import codeql.rust.elements.UnknownLocation
|
||||||
|
|
||||||
class File extends Generated::File { }
|
class File extends Generated::File {
|
||||||
|
/** toString */
|
||||||
|
override string toString() { result = this.getAbsolutePath() }
|
||||||
|
|
||||||
|
/** Gets the absolute path of this file. */
|
||||||
|
string getAbsolutePath() { result = this.getName() }
|
||||||
|
|
||||||
|
/** Gets the full name of this file. */
|
||||||
|
string getFullName() { result = this.getAbsolutePath() }
|
||||||
|
|
||||||
|
/** Gets the URL of this file. */
|
||||||
|
string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if either,
|
||||||
|
* - `part` is the base name of this container and `i = 1`, or
|
||||||
|
* - `part` is the stem of this container and `i = 2`, or
|
||||||
|
* - `part` is the extension of this container and `i = 3`.
|
||||||
|
*/
|
||||||
|
cached
|
||||||
|
private predicate splitAbsolutePath(string part, int i) {
|
||||||
|
part = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the base name of this file. */
|
||||||
|
string getBaseName() { this.splitAbsolutePath(result, 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):
|
||||||
|
*
|
||||||
|
* <table border="1">
|
||||||
|
* <tr><th>Absolute path</th><th>Extension</th></tr>
|
||||||
|
* <tr><td>"/tmp/tst.txt"</td><td>"txt"</td></tr>
|
||||||
|
* <tr><td>"/tmp/.classpath"</td><td>"classpath"</td></tr>
|
||||||
|
* <tr><td>"/bin/bash"</td><td>not defined</td></tr>
|
||||||
|
* <tr><td>"/tmp/tst2."</td><td>""</td></tr>
|
||||||
|
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
|
||||||
|
* </table>
|
||||||
|
*/
|
||||||
|
string getExtension() { this.splitAbsolutePath(result, 3) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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):
|
||||||
|
*
|
||||||
|
* <table border="1">
|
||||||
|
* <tr><th>Absolute path</th><th>Stem</th></tr>
|
||||||
|
* <tr><td>"/tmp/tst.txt"</td><td>"tst"</td></tr>
|
||||||
|
* <tr><td>"/tmp/.classpath"</td><td>""</td></tr>
|
||||||
|
* <tr><td>"/bin/bash"</td><td>"bash"</td></tr>
|
||||||
|
* <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr>
|
||||||
|
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
|
||||||
|
* </table>
|
||||||
|
*/
|
||||||
|
string getStem() { this.splitAbsolutePath(result, 2) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of lines containing code in this file. This value
|
||||||
|
* is approximate.
|
||||||
|
*/
|
||||||
|
int getNumberOfLinesOfCode() {
|
||||||
|
result =
|
||||||
|
count(int line |
|
||||||
|
exists(Location loc |
|
||||||
|
not loc instanceof UnknownLocation and loc.getFile() = this and loc.getStartLine() = line
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the relative path of this file from the root folder of the
|
||||||
|
* analyzed source location. The relative path of the root folder itself
|
||||||
|
* would be the empty string.
|
||||||
|
*
|
||||||
|
* This has no result if the file is outside the source root, that is,
|
||||||
|
* if the root folder is not a reflexive, transitive parent of this file.
|
||||||
|
*/
|
||||||
|
string getRelativePath() {
|
||||||
|
exists(string absPath, string pref |
|
||||||
|
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
|
||||||
|
|
|
||||||
|
absPath = pref and result = ""
|
||||||
|
or
|
||||||
|
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
|
||||||
|
not result.matches("/%")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
5
rust/ql/lib/codeql/rust/elements/Function.qll
generated
5
rust/ql/lib/codeql/rust/elements/Function.qll
generated
@@ -1,8 +1,9 @@
|
|||||||
// generated by codegen, remove this comment if you wish to edit this file
|
|
||||||
/**
|
/**
|
||||||
* This module provides a hand-modifiable wrapper around the generated class `Function`.
|
* This module provides a hand-modifiable wrapper around the generated class `Function`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.rust.generated.Function
|
private import codeql.rust.generated.Function
|
||||||
|
|
||||||
class Function extends Generated::Function { }
|
class Function extends Generated::Function {
|
||||||
|
override string toString() { result = this.getName() }
|
||||||
|
}
|
||||||
|
|||||||
18
rust/ql/lib/codeql/rust/elements/Locatable.qll
generated
18
rust/ql/lib/codeql/rust/elements/Locatable.qll
generated
@@ -1,8 +1,22 @@
|
|||||||
// generated by codegen, remove this comment if you wish to edit this file
|
|
||||||
/**
|
/**
|
||||||
* This module provides a hand-modifiable wrapper around the generated class `Locatable`.
|
* This module provides a hand-modifiable wrapper around the generated class `Locatable`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.rust.generated.Locatable
|
private import codeql.rust.generated.Locatable
|
||||||
|
private import codeql.rust.elements.File
|
||||||
|
private import codeql.rust.elements.UnknownLocation
|
||||||
|
|
||||||
class Locatable extends Generated::Locatable { }
|
class Locatable extends Generated::Locatable {
|
||||||
|
pragma[nomagic]
|
||||||
|
override Location getLocation() {
|
||||||
|
result = Generated::Locatable.super.getLocation()
|
||||||
|
or
|
||||||
|
not exists(Generated::Locatable.super.getLocation()) and
|
||||||
|
result instanceof UnknownLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary file where this element occurs.
|
||||||
|
*/
|
||||||
|
File getFile() { result = this.getLocation().getFile() }
|
||||||
|
}
|
||||||
|
|||||||
25
rust/ql/lib/codeql/rust/elements/Location.qll
generated
25
rust/ql/lib/codeql/rust/elements/Location.qll
generated
@@ -1,8 +1,29 @@
|
|||||||
// generated by codegen, remove this comment if you wish to edit this file
|
|
||||||
/**
|
/**
|
||||||
* This module provides a hand-modifiable wrapper around the generated class `Location`.
|
* This module provides a hand-modifiable wrapper around the generated class `Location`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.rust.generated.Location
|
private import codeql.rust.generated.Location
|
||||||
|
|
||||||
class Location extends Generated::Location { }
|
class Location extends Generated::Location {
|
||||||
|
/**
|
||||||
|
* Holds if this location is described by `path`, `startLine`, `startColumn`, `endLine` and `endColumn`.
|
||||||
|
*/
|
||||||
|
predicate hasLocationInfo(string path, int startLine, int startColumn, int endLine, int endColumn) {
|
||||||
|
path = this.getFile().getFullName() and
|
||||||
|
startLine = this.getStartLine() and
|
||||||
|
startColumn = this.getStartColumn() and
|
||||||
|
endLine = this.getEndLine() and
|
||||||
|
endColumn = this.getEndColumn()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a textual representation of this location.
|
||||||
|
*/
|
||||||
|
override string toString() {
|
||||||
|
exists(string filePath, int startLine, int startColumn, int endLine, int endColumn |
|
||||||
|
this.hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
|
||||||
|
|
|
||||||
|
toUrl(filePath, startLine, startColumn, endLine, endColumn, result)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
5
rust/ql/lib/codeql/rust/elements/UnknownFile.qll
generated
5
rust/ql/lib/codeql/rust/elements/UnknownFile.qll
generated
@@ -1,8 +1,9 @@
|
|||||||
// generated by codegen, remove this comment if you wish to edit this file
|
|
||||||
/**
|
/**
|
||||||
* This module provides a hand-modifiable wrapper around the generated class `UnknownFile`.
|
* This module provides a hand-modifiable wrapper around the generated class `UnknownFile`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.rust.generated.UnknownFile
|
private import codeql.rust.generated.UnknownFile
|
||||||
|
|
||||||
class UnknownFile extends Generated::UnknownFile { }
|
class UnknownFile extends Generated::UnknownFile {
|
||||||
|
override string getName() { result = "" }
|
||||||
|
}
|
||||||
|
|||||||
17
rust/ql/lib/codeql/rust/elements/UnknownLocation.qll
generated
17
rust/ql/lib/codeql/rust/elements/UnknownLocation.qll
generated
@@ -1,8 +1,21 @@
|
|||||||
// generated by codegen, remove this comment if you wish to edit this file
|
|
||||||
/**
|
/**
|
||||||
* This module provides a hand-modifiable wrapper around the generated class `UnknownLocation`.
|
* This module provides a hand-modifiable wrapper around the generated class `UnknownLocation`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.rust.generated.UnknownLocation
|
private import codeql.rust.generated.UnknownLocation
|
||||||
|
private import codeql.rust.elements.File
|
||||||
|
private import codeql.rust.elements.UnknownFile
|
||||||
|
|
||||||
class UnknownLocation extends Generated::UnknownLocation { }
|
class UnknownLocation extends Generated::UnknownLocation {
|
||||||
|
override File getFile() { result instanceof UnknownFile }
|
||||||
|
|
||||||
|
override int getStartLine() { result = 0 }
|
||||||
|
|
||||||
|
override int getStartColumn() { result = 0 }
|
||||||
|
|
||||||
|
override int getEndLine() { result = 0 }
|
||||||
|
|
||||||
|
override int getEndColumn() { result = 0 }
|
||||||
|
|
||||||
|
override string toString() { result = "UnknownLocation" }
|
||||||
|
}
|
||||||
|
|||||||
49
rust/ql/lib/codeql/rust/printast/PrintAst.qll
Normal file
49
rust/ql/lib/codeql/rust/printast/PrintAst.qll
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Provides queries to pretty-print a Swift AST as a graph.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import PrintAstNode
|
||||||
|
|
||||||
|
cached
|
||||||
|
private int getOrder(PrintAstNode node) {
|
||||||
|
node =
|
||||||
|
rank[result](PrintAstNode n, Location loc |
|
||||||
|
loc = n.getLocation()
|
||||||
|
|
|
||||||
|
n
|
||||||
|
order by
|
||||||
|
loc.getFile().getName(), loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(),
|
||||||
|
loc.getEndColumn()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
|
||||||
|
query predicate nodes(PrintAstNode node, string key, string value) {
|
||||||
|
node.shouldBePrinted() and
|
||||||
|
(
|
||||||
|
key = "semmle.label" and value = node.toString()
|
||||||
|
or
|
||||||
|
key = "semmle.order" and value = getOrder(node).toString()
|
||||||
|
or
|
||||||
|
value = node.getProperty(key)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
|
||||||
|
* given `value`.
|
||||||
|
*/
|
||||||
|
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
|
||||||
|
source.shouldBePrinted() and
|
||||||
|
target.shouldBePrinted() and
|
||||||
|
exists(int index, string accessor | source.hasChild(target, index, accessor) |
|
||||||
|
key = "semmle.label" and value = accessor
|
||||||
|
or
|
||||||
|
key = "semmle.order" and value = index.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if property `key` of the graph has the given `value`. */
|
||||||
|
query predicate graphProperties(string key, string value) {
|
||||||
|
key = "semmle.graphKind" and value = "tree"
|
||||||
|
}
|
||||||
129
rust/ql/lib/codeql/rust/printast/PrintAstNode.qll
Normal file
129
rust/ql/lib/codeql/rust/printast/PrintAstNode.qll
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes used to pretty-print a Swift AST as a graph.
|
||||||
|
* This is factored out of `PrintAst.qll` for testing purposes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import rust
|
||||||
|
import codeql.rust.generated.ParentChild
|
||||||
|
|
||||||
|
private newtype TPrintAstConfiguration = TMakePrintAstConfiguration()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hook to customize the files and functions printed by this module.
|
||||||
|
*/
|
||||||
|
class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||||
|
/**
|
||||||
|
* Gets the string representation of this singleton
|
||||||
|
*/
|
||||||
|
string toString() { result = "PrintAstConfiguration" }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the AST for `e` should be printed. By default, holds for all.
|
||||||
|
*/
|
||||||
|
predicate shouldPrint(Locatable e) { not e instanceof Diagnostics and not e instanceof MacroRole }
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate shouldPrint(Locatable e) { any(PrintAstConfiguration config).shouldPrint(e) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An AST node that should be printed.
|
||||||
|
*/
|
||||||
|
private newtype TPrintAstNode = TPrintLocatable(Locatable ast)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node in the output tree.
|
||||||
|
*/
|
||||||
|
class PrintAstNode extends TPrintAstNode {
|
||||||
|
/**
|
||||||
|
* Gets a textual representation of this node.
|
||||||
|
*/
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the child node at index `index`. Child indices must be unique,
|
||||||
|
* but need not be contiguous.
|
||||||
|
*/
|
||||||
|
abstract predicate hasChild(PrintAstNode child, int index, string label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this node should be printed in the output.
|
||||||
|
*/
|
||||||
|
abstract predicate shouldBePrinted();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location of this node in the source code.
|
||||||
|
*/
|
||||||
|
abstract Location getLocation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of an additional property of this node, where the name of
|
||||||
|
* the property is `key`.
|
||||||
|
*/
|
||||||
|
string getProperty(string key) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the underlying AST node, if any.
|
||||||
|
*/
|
||||||
|
abstract Locatable getAstNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string prettyPrint(Locatable e) {
|
||||||
|
result = "[" + concat(e.getPrimaryQlClasses(), ", ") + "] " + e
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Unresolved extends Locatable {
|
||||||
|
Unresolved() { this != this.resolve() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A graph node representing a real Locatable node.
|
||||||
|
*/
|
||||||
|
class PrintLocatable extends PrintAstNode, TPrintLocatable {
|
||||||
|
Locatable ast;
|
||||||
|
|
||||||
|
PrintLocatable() { this = TPrintLocatable(ast) }
|
||||||
|
|
||||||
|
override string toString() { result = prettyPrint(ast) }
|
||||||
|
|
||||||
|
final override predicate shouldBePrinted() { shouldPrint(ast) }
|
||||||
|
|
||||||
|
override predicate hasChild(PrintAstNode child, int index, string label) {
|
||||||
|
exists(Locatable c, int i, string accessor |
|
||||||
|
c = getChildAndAccessor(ast, i, accessor) and
|
||||||
|
(
|
||||||
|
// use even indexes for normal children, leaving odd slots for conversions if any
|
||||||
|
child = TPrintLocatable(c) and index = 2 * i and label = accessor
|
||||||
|
or
|
||||||
|
child = TPrintLocatable(c.getFullyUnresolved().(Unresolved)) and
|
||||||
|
index = 2 * i + 1 and
|
||||||
|
(
|
||||||
|
if c instanceof Expr
|
||||||
|
then label = accessor + ".getFullyConverted()"
|
||||||
|
else label = accessor + ".getFullyUnresolved()"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override Locatable getAstNode() { result = ast }
|
||||||
|
|
||||||
|
final override Location getLocation() { result = ast.getLocation() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specialization of graph node for "unresolved" children, that is nodes in
|
||||||
|
* the parallel conversion AST.
|
||||||
|
*/
|
||||||
|
class PrintUnresolved extends PrintLocatable {
|
||||||
|
override Unresolved ast;
|
||||||
|
|
||||||
|
override predicate hasChild(PrintAstNode child, int index, string label) {
|
||||||
|
// only print immediate unresolved children from the "parallel" AST
|
||||||
|
child = TPrintLocatable(getImmediateChildAndAccessor(ast, index, label).(Unresolved))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate hasPropertyWrapperElement(VarDecl d, Locatable a) {
|
||||||
|
a = [d.getPropertyWrapperBackingVar(), d.getPropertyWrapperProjectionVar()] or
|
||||||
|
a = [d.getPropertyWrapperBackingVarBinding(), d.getPropertyWrapperProjectionVarBinding()]
|
||||||
|
}
|
||||||
4
rust/ql/lib/qlpack.lock.yml
Normal file
4
rust/ql/lib/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
dependencies: {}
|
||||||
|
compiled: false
|
||||||
|
lockVersion: 1.0.0
|
||||||
15
rust/ql/lib/qlpack.yml
Normal file
15
rust/ql/lib/qlpack.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: codeql/rust-all
|
||||||
|
version: 0.1.0-dev
|
||||||
|
groups: rust
|
||||||
|
extractor: rust
|
||||||
|
dbscheme: rust.dbscheme
|
||||||
|
library: true
|
||||||
|
dependencies:
|
||||||
|
codeql/controlflow: ${workspace}
|
||||||
|
codeql/dataflow: ${workspace}
|
||||||
|
codeql/regex: ${workspace}
|
||||||
|
codeql/mad: ${workspace}
|
||||||
|
codeql/ssa: ${workspace}
|
||||||
|
codeql/tutorial: ${workspace}
|
||||||
|
codeql/util: ${workspace}
|
||||||
|
warnOnImplicitThis: true
|
||||||
3
rust/ql/lib/rust.qll
Normal file
3
rust/ql/lib/rust.qll
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/** Top-level import for the Rust language pack */
|
||||||
|
|
||||||
|
import codeql.rust.elements
|
||||||
4
rust/ql/src/qlpack.lock.yml
Normal file
4
rust/ql/src/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
dependencies: {}
|
||||||
|
compiled: false
|
||||||
|
lockVersion: 1.0.0
|
||||||
12
rust/ql/src/qlpack.yml
Normal file
12
rust/ql/src/qlpack.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
name: codeql/rust-queries
|
||||||
|
version: 0.1.0-dev
|
||||||
|
groups:
|
||||||
|
- rust
|
||||||
|
- queries
|
||||||
|
suites: codeql-suites
|
||||||
|
extractor: rust
|
||||||
|
dependencies:
|
||||||
|
codeql/rust-all: ${workspace}
|
||||||
|
codeql/suite-helpers: ${workspace}
|
||||||
|
codeql/util: ${workspace}
|
||||||
|
warnOnImplicitThis: true
|
||||||
33
rust/ql/src/queries/ide-contextual-queries/printAst.ql
Normal file
33
rust/ql/src/queries/ide-contextual-queries/printAst.ql
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* @name Print AST
|
||||||
|
* @description Outputs a representation of a file's Abstract Syntax Tree. This
|
||||||
|
* query is used by the VS Code extension.
|
||||||
|
* @id rust/print-ast
|
||||||
|
* @kind graph
|
||||||
|
* @tags ide-contextual-queries/print-ast
|
||||||
|
*/
|
||||||
|
|
||||||
|
import rust
|
||||||
|
import codeql.rust.printast.PrintAst
|
||||||
|
import codeql.IDEContextual
|
||||||
|
import codeql.rust.generated.ParentChild
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the source file to generate an AST from.
|
||||||
|
*/
|
||||||
|
external string selectedSourceFile();
|
||||||
|
|
||||||
|
class PrintAstConfigurationOverride extends PrintAstConfiguration {
|
||||||
|
/**
|
||||||
|
* Holds if the location matches the selected file in the VS Code extension and
|
||||||
|
* the element is `e`.
|
||||||
|
*/
|
||||||
|
override predicate shouldPrint(Locatable e) {
|
||||||
|
super.shouldPrint(e) and
|
||||||
|
(
|
||||||
|
e.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||||
|
or
|
||||||
|
exists(Locatable parent | this.shouldPrint(parent) and parent = getImmediateParent(e))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
3
rust/ql/test/.gitignore
vendored
Normal file
3
rust/ql/test/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Cargo.toml
|
||||||
|
Cargo.lock
|
||||||
|
target/
|
||||||
13
rust/ql/test/TestUtils.qll
Normal file
13
rust/ql/test/TestUtils.qll
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
private import codeql.rust.elements
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate toBeTested(Element e) {
|
||||||
|
exists(File f |
|
||||||
|
f.getName().matches("%rust/ql/test%") and
|
||||||
|
(
|
||||||
|
e = f
|
||||||
|
or
|
||||||
|
e.(Locatable).getLocation().getFile() = f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
| test.rs:0:0:0:0 | test.rs | DbFile | getName: | test.rs |
|
||||||
10
rust/ql/test/extractor-tests/generated/File/File.ql
generated
Normal file
10
rust/ql/test/extractor-tests/generated/File/File.ql
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// generated by codegen
|
||||||
|
import codeql.rust.elements
|
||||||
|
import TestUtils
|
||||||
|
|
||||||
|
from File x, string getName
|
||||||
|
where
|
||||||
|
toBeTested(x) and
|
||||||
|
not x.isUnknown() and
|
||||||
|
getName = x.getName()
|
||||||
|
select x, x.getPrimaryQlClasses(), "getName:", getName
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
// generated by codegen
|
|
||||||
|
|
||||||
After a source file is added in this directory and codegen is run again, test queries
|
|
||||||
will appear and this file will be deleted
|
|
||||||
1
rust/ql/test/extractor-tests/generated/File/test.rs
Normal file
1
rust/ql/test/extractor-tests/generated/File/test.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
| test.rs:0:0:0:11 | foo | getName: | foo |
|
||||||
|
| test.rs:1:0:1:11 | bar | getName: | bar |
|
||||||
|
| test.rs:2:0:2:11 | baz | getName: | baz |
|
||||||
10
rust/ql/test/extractor-tests/generated/Function/Function.ql
generated
Normal file
10
rust/ql/test/extractor-tests/generated/Function/Function.ql
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// generated by codegen
|
||||||
|
import codeql.rust.elements
|
||||||
|
import TestUtils
|
||||||
|
|
||||||
|
from Function x, string getName
|
||||||
|
where
|
||||||
|
toBeTested(x) and
|
||||||
|
not x.isUnknown() and
|
||||||
|
getName = x.getName()
|
||||||
|
select x, "getName:", getName
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
// generated by codegen
|
|
||||||
|
|
||||||
After a source file is added in this directory and codegen is run again, test queries
|
|
||||||
will appear and this file will be deleted
|
|
||||||
3
rust/ql/test/extractor-tests/generated/Function/test.rs
Normal file
3
rust/ql/test/extractor-tests/generated/Function/test.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fn foo() {}
|
||||||
|
fn bar() {}
|
||||||
|
fn baz() {}
|
||||||
4
rust/ql/test/qlpack.lock.yml
Normal file
4
rust/ql/test/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
dependencies: {}
|
||||||
|
compiled: false
|
||||||
|
lockVersion: 1.0.0
|
||||||
8
rust/ql/test/qlpack.yml
Normal file
8
rust/ql/test/qlpack.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
name: codeql/rust-tests
|
||||||
|
groups: [rust, test]
|
||||||
|
dependencies:
|
||||||
|
codeql/rust-queries: ${workspace}
|
||||||
|
codeql/rust-all: ${workspace}
|
||||||
|
extractor: rust
|
||||||
|
tests: .
|
||||||
|
warnOnImplicitThis: true
|
||||||
@@ -2,8 +2,6 @@ load("//misc/bazel:pkg.bzl", "codeql_pkg_files")
|
|||||||
|
|
||||||
codeql_pkg_files(
|
codeql_pkg_files(
|
||||||
name = "tools",
|
name = "tools",
|
||||||
exes = [
|
exes = glob(["*.sh"]),
|
||||||
"index.sh",
|
|
||||||
],
|
|
||||||
visibility = ["//rust:__pkg__"],
|
visibility = ["//rust:__pkg__"],
|
||||||
)
|
)
|
||||||
|
|||||||
5
rust/tools/index-files.sh
Executable file
5
rust/tools/index-files.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
exec "$CODEQL_EXTRACTOR_RUST_ROOT/tools/$CODEQL_PLATFORM/extractor" --inputs-file="$1"
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# TODO move this to rust code
|
|
||||||
|
|
||||||
inputs=($(find -name Cargo.toml))
|
|
||||||
|
|
||||||
if [ "${#inputs}" -eq 0 ]; then
|
|
||||||
inputs=($(find -name rust-project.json))
|
|
||||||
if [ "${#inputs}" -eq 0 ]; then
|
|
||||||
inputs=($(find -name '*.rs'))
|
|
||||||
if [ "${#inputs}" -eq 0 ]; then
|
|
||||||
echo "no source files found" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$CODEQL_EXTRACTOR_RUST_ROOT/tools/$CODEQL_PLATFORM/extractor" "${inputs[@]}"
|
|
||||||
32
rust/tools/qltest.sh
Executable file
32
rust/tools/qltest.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
mkdir -p "$CODEQL_EXTRACTOR_RUST_TRAP_DIR"
|
||||||
|
|
||||||
|
export RUST_BACKTRACE=full
|
||||||
|
|
||||||
|
QLTEST_LOG="$CODEQL_EXTRACTOR_RUST_LOG_DIR"/qltest.log
|
||||||
|
|
||||||
|
EXTRACTOR="$CODEQL_EXTRACTOR_RUST_ROOT/tools/$CODEQL_PLATFORM/extractor"
|
||||||
|
for src in *.rs; do
|
||||||
|
echo -e "[package]\nname = \"test\"\n[lib]\npath=\"$src\"\n" > Cargo.toml
|
||||||
|
env=()
|
||||||
|
opts=("$src")
|
||||||
|
opts+=($(sed -n '1 s=//codeql-extractor-options:==p' $src))
|
||||||
|
expected_status=$(sed -n 's=//codeql-extractor-expected-status:[[:space:]]*==p' $src)
|
||||||
|
expected_status=${expected_status:-0}
|
||||||
|
env+=($(sed -n '1 s=//codeql-extractor-env:==p' $src))
|
||||||
|
echo >> $QLTEST_LOG
|
||||||
|
echo "env ${env[@]} $EXTRACTOR ${opts[@]}" >> "$QLTEST_LOG"
|
||||||
|
env "${env[@]}" "$EXTRACTOR" "${opts[@]}" >> $QLTEST_LOG 2>&1
|
||||||
|
actual_status=$?
|
||||||
|
if [[ $actual_status != $expected_status ]]; then
|
||||||
|
FAILED=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
rm -rf Cargo.*
|
||||||
|
|
||||||
|
if [ -n "$FAILED" ]; then
|
||||||
|
cat "$QLTEST_LOG" # Show compiler errors on extraction failure
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user