mirror of
https://github.com/github/codeql.git
synced 2026-04-19 05:54:00 +02:00
Merge branch 'main' into rust/callable-base
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -390,11 +390,13 @@ dependencies = [
|
||||
"ra_ap_base_db",
|
||||
"ra_ap_hir",
|
||||
"ra_ap_hir_def",
|
||||
"ra_ap_hir_expand",
|
||||
"ra_ap_ide_db",
|
||||
"ra_ap_load-cargo",
|
||||
"ra_ap_parser",
|
||||
"ra_ap_paths",
|
||||
"ra_ap_project_model",
|
||||
"ra_ap_span",
|
||||
"ra_ap_syntax",
|
||||
"ra_ap_vfs",
|
||||
"rust-extractor-macros",
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Local source models with the `stdin` source kind have been added for the variable `os.Stdin` and the functions `fmt.Scan`, `fmt.Scanf` and `fmt.Scanln`. You can optionally include threat models as appropriate when using the CodeQL CLI and in GitHub code scanning. For more information, see [Analyzing your code with CodeQL queries](https://docs.github.com/code-security/codeql-cli/getting-started-with-the-codeql-cli/analyzing-your-code-with-codeql-queries#including-model-packs-to-add-potential-sources-of-tainted-data>) and [Customizing your advanced setup for code scanning](https://docs.github.com/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-threat-models).
|
||||
@@ -112,6 +112,15 @@ module Fmt {
|
||||
Scanner() { this.hasQualifiedName("fmt", ["Scan", "Scanf", "Scanln"]) }
|
||||
}
|
||||
|
||||
private class ScannerSource extends SourceNode {
|
||||
ScannerSource() {
|
||||
// All of the arguments which are sources are varargs.
|
||||
this.asExpr() = any(Scanner s).getACall().getAnImplicitVarargsArgument().asExpr()
|
||||
}
|
||||
|
||||
override string getThreatModel() { result = "stdin" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Fscan` function or one of its variants,
|
||||
* all of which read from a specified `io.Reader`.
|
||||
|
||||
@@ -43,4 +43,12 @@ module Os {
|
||||
input = inp and output = outp
|
||||
}
|
||||
}
|
||||
|
||||
private class Stdin extends SourceNode {
|
||||
Stdin() {
|
||||
exists(Variable osStdin | osStdin.hasQualifiedName("os", "Stdin") | this = osStdin.getARead())
|
||||
}
|
||||
|
||||
override string getThreatModel() { result = "stdin" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
module test
|
||||
|
||||
go 1.22.6
|
||||
@@ -0,0 +1,3 @@
|
||||
testFailures
|
||||
invalidModelRow
|
||||
failures
|
||||
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/threat-models
|
||||
extensible: threatModelConfiguration
|
||||
data:
|
||||
- ["stdin", true, 0]
|
||||
@@ -0,0 +1,19 @@
|
||||
import go
|
||||
import ModelValidation
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module SourceTest implements TestSig {
|
||||
string getARelevantTag() { result = "source" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(ActiveThreatModelSource s |
|
||||
s.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
|
||||
element = s.toString() and
|
||||
value = "" and
|
||||
tag = "source"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<SourceTest>
|
||||
@@ -0,0 +1,2 @@
|
||||
testFailures
|
||||
invalidModelRow
|
||||
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/threat-models
|
||||
extensible: threatModelConfiguration
|
||||
data:
|
||||
- ["stdin", true, 0]
|
||||
@@ -0,0 +1,48 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func sink(string) {
|
||||
|
||||
}
|
||||
|
||||
func readStdinBuffer() {
|
||||
buf := make([]byte, 1024)
|
||||
n, err := os.Stdin.Read(buf) // $source
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sink(string(buf[:n])) // $hasTaintFlow="type conversion"
|
||||
}
|
||||
|
||||
func readStdinBuffReader() {
|
||||
buf := make([]byte, 1024)
|
||||
r := bufio.NewReader(os.Stdin) // $source
|
||||
n, err := r.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sink(string(buf[:n])) // $hasTaintFlow="type conversion"
|
||||
}
|
||||
|
||||
func scan() {
|
||||
var username, email string
|
||||
fmt.Scan(&username, &email) // $source
|
||||
sink(username) // $hasTaintFlow="username"
|
||||
}
|
||||
|
||||
func scanf() {
|
||||
var s string
|
||||
fmt.Scanf("%s", &s) // $source
|
||||
sink(s) // $hasTaintFlow="s"
|
||||
}
|
||||
|
||||
func scanl() {
|
||||
var s string
|
||||
fmt.Scanln(&s) // $source
|
||||
sink(s) // $hasTaintFlow="s"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import go
|
||||
import semmle.go.dataflow.ExternalFlow
|
||||
import ModelValidation
|
||||
import experimental.frameworks.CleverGo
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(CallExpr c | c.getTarget().getName() = "sink").getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
import TaintFlowTest<Config>
|
||||
@@ -13,10 +13,10 @@ rm -rf dbs
|
||||
|
||||
mkdir dbs
|
||||
|
||||
CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB=True $CODEQL database create dbs/without-stdlib --language python --source-root repo_dir/
|
||||
$CODEQL database create dbs/without-stdlib --language python --source-root repo_dir/
|
||||
$CODEQL query run --database dbs/without-stdlib query.ql > query.without-stdlib.actual
|
||||
diff query.without-stdlib.expected query.without-stdlib.actual
|
||||
|
||||
LGTM_INDEX_EXCLUDE="/usr/lib/**" $CODEQL database create dbs/with-stdlib --language python --source-root repo_dir/
|
||||
LGTM_INDEX_EXCLUDE="/usr/lib/**" CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB=True $CODEQL database create dbs/with-stdlib --language python --source-root repo_dir/
|
||||
$CODEQL query run --database dbs/with-stdlib query.ql > query.with-stdlib.actual
|
||||
diff query.with-stdlib.expected query.with-stdlib.actual
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
| name |
|
||||
+----------+
|
||||
| dircache |
|
||||
| stat |
|
||||
| test |
|
||||
@@ -1,5 +1,3 @@
|
||||
| name |
|
||||
+----------+
|
||||
| dircache |
|
||||
| stat |
|
||||
| test |
|
||||
| name |
|
||||
+------+
|
||||
| test |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
| name |
|
||||
+------+
|
||||
| stat |
|
||||
| test |
|
||||
|
||||
@@ -102,8 +102,10 @@ def make_parser():
|
||||
config_options.add_option("--colorize", dest="colorize", default=False, action="store_true",
|
||||
help = """Colorize the logging output.""")
|
||||
|
||||
config_options.add_option("--dont-extract-stdlib", dest="extract_stdlib", default=True, action="store_false",
|
||||
help="Do not extract the standard library.")
|
||||
config_options.add_option("--dont-extract-stdlib", dest="extract_stdlib", action="store_false",
|
||||
help="This flag is deprecated; not extracting the standard library is now the default.")
|
||||
config_options.add_option("--extract-stdlib", dest="extract_stdlib", default=False, action="store_true",
|
||||
help="Extract the standard library.")
|
||||
|
||||
parser.add_option_group(config_options)
|
||||
|
||||
@@ -226,8 +228,18 @@ def parse(command_line):
|
||||
|
||||
if 'CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB' in os.environ:
|
||||
options.extract_stdlib = False
|
||||
print ("WARNING: CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB is deprecated; the default is now to not extract the standard library.")
|
||||
|
||||
if 'CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB' in os.environ:
|
||||
options.extract_stdlib = True
|
||||
|
||||
options.prune = True
|
||||
|
||||
if options.extract_stdlib:
|
||||
print ("WARNING: The analysis will extract the standard library. This behavior is deprecated and will be removed in a future release. We expect it to be gone in CLI version 2.20.0.")
|
||||
else:
|
||||
print ("INFO: The Python extractor has recently stopped extracting the standard library by default. If you encounter problems, please let us know by submitting an issue to https://github.com/github/codeql. It is possible to re-enable extraction of the standard library by setting the environment variable CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB.")
|
||||
|
||||
return options, args
|
||||
|
||||
def split_and_flatten(options_list, div):
|
||||
|
||||
@@ -67,7 +67,7 @@ def main(sys_path = sys.path[:]):
|
||||
update_analysis_version(last_version)
|
||||
|
||||
found_py2 = False
|
||||
if get_analysis_major_version() == 2:
|
||||
if get_analysis_major_version() == 2 and options.extract_stdlib:
|
||||
# Setup `sys_path` to use the Python 2 standard library
|
||||
sys_path, found_py2 = get_py2_sys_path(logger, sys_path)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from io import BytesIO
|
||||
|
||||
#Semantic version of extractor.
|
||||
#Update this if any changes are made
|
||||
VERSION = "6.1.2"
|
||||
VERSION = "7.0.0"
|
||||
|
||||
PY_EXTENSIONS = ".py", ".pyw"
|
||||
|
||||
|
||||
4
python/ql/lib/change-notes/2024-10-09-finditer-match.md
Normal file
4
python/ql/lib/change-notes/2024-10-09-finditer-match.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Modelled that `re.finditer` returns an iterable of `re.Match` objects. This is now understood by the API graph in many cases.
|
||||
@@ -3284,6 +3284,18 @@ module StdlibPrivate {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base API node for regular expression functions.
|
||||
* Either the `re` module or a compiled regular expression.
|
||||
*/
|
||||
private API::Node re(boolean compiled) {
|
||||
result = API::moduleImport("re") and
|
||||
compiled = false
|
||||
or
|
||||
result = any(RePatternSummary c).getACall().(API::CallNode).getReturn() and
|
||||
compiled = true
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow summary for methods returning a `re.Match` object
|
||||
*
|
||||
@@ -3293,17 +3305,18 @@ module StdlibPrivate {
|
||||
ReMatchSummary() { this = ["re.Match", "compiled re.Match"] }
|
||||
|
||||
override DataFlow::CallCfgNode getACall() {
|
||||
this = "re.Match" and
|
||||
result = API::moduleImport("re").getMember(["match", "search", "fullmatch"]).getACall()
|
||||
or
|
||||
this = "compiled re.Match" and
|
||||
result =
|
||||
any(RePatternSummary c)
|
||||
.getACall()
|
||||
.(API::CallNode)
|
||||
.getReturn()
|
||||
.getMember(["match", "search", "fullmatch"])
|
||||
.getACall()
|
||||
exists(API::Node re, boolean compiled |
|
||||
re = re(compiled) and
|
||||
(
|
||||
compiled = false and
|
||||
this = "re.Match"
|
||||
or
|
||||
compiled = true and
|
||||
this = "compiled re.Match"
|
||||
)
|
||||
|
|
||||
result = re.getMember(["match", "search", "fullmatch"]).getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::ArgumentNode getACallback() { none() }
|
||||
@@ -3340,6 +3353,13 @@ module StdlibPrivate {
|
||||
}
|
||||
}
|
||||
|
||||
/** An API node for a `re.Match` object */
|
||||
private API::Node match() {
|
||||
result = any(ReMatchSummary c).getACall().(API::CallNode).getReturn()
|
||||
or
|
||||
result = re(_).getMember("finditer").getReturn().getASubscript()
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow summary for methods on a `re.Match` object
|
||||
*
|
||||
@@ -3353,15 +3373,7 @@ module StdlibPrivate {
|
||||
methodName in ["expand", "group", "groups", "groupdict"]
|
||||
}
|
||||
|
||||
override DataFlow::CallCfgNode getACall() {
|
||||
result =
|
||||
any(ReMatchSummary c)
|
||||
.getACall()
|
||||
.(API::CallNode)
|
||||
.getReturn()
|
||||
.getMember(methodName)
|
||||
.getACall()
|
||||
}
|
||||
override DataFlow::CallCfgNode getACall() { result = match().getMember(methodName).getACall() }
|
||||
|
||||
override DataFlow::ArgumentNode getACallback() { none() }
|
||||
|
||||
@@ -3463,6 +3475,14 @@ module StdlibPrivate {
|
||||
) and
|
||||
preservesValue = false
|
||||
)
|
||||
or
|
||||
// flow from input string to attribute on match object
|
||||
exists(int arg | arg = methodName.(RegexExecutionMethod).getStringArgIndex() - offset |
|
||||
input in ["Argument[" + arg + "]", "Argument[string:]"] and
|
||||
methodName = "finditer" and
|
||||
output = "ReturnValue.ListElement.Attribute[string]" and
|
||||
preservesValue = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
| mapping | builtin-class collections.defaultdict |
|
||||
| mapping | builtin-class dict |
|
||||
| mapping | class MyDictSubclass |
|
||||
| mapping | class MyMappingABC |
|
||||
| mapping | class OrderedDict |
|
||||
| neither sequence nor mapping | builtin-class set |
|
||||
| neither sequence nor mapping | class MyMappingABC |
|
||||
| neither sequence nor mapping | class MySequenceABC |
|
||||
| sequence | builtin-class list |
|
||||
| sequence | builtin-class str |
|
||||
| sequence | builtin-class tuple |
|
||||
| sequence | builtin-class unicode |
|
||||
| sequence | class MySequenceABC |
|
||||
| sequence | class MySequenceImpl |
|
||||
|
||||
@@ -44,14 +44,10 @@
|
||||
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
|
||||
| test.py | 16 | ControlFlowNode for Attribute | class Y | ControlFlowNode for ClassExpr |
|
||||
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
|
||||
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | ControlFlowNode for ImportExpr |
|
||||
| test.py | 19 | ControlFlowNode for tty | Module tty | ControlFlowNode for ImportExpr |
|
||||
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | ControlFlowNode for from sys import * |
|
||||
| test.py | 22 | ControlFlowNode for x | Module package.x | Entry node for Module package.x |
|
||||
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 24 | ControlFlowNode for argv | int 0 | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
|
||||
| test.py | 31 | ControlFlowNode for argv | list object | ControlFlowNode for from sys import * |
|
||||
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | ControlFlowNode for ImportExpr |
|
||||
| test.py | 34 | ControlFlowNode for timeout | builtin-class socket.timeout | ControlFlowNode for from _socket import * |
|
||||
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
|
||||
|
||||
@@ -44,14 +44,10 @@
|
||||
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
|
||||
| test.py | 16 | ControlFlowNode for Attribute | class Y | builtin-class type | ControlFlowNode for ClassExpr |
|
||||
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
|
||||
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 19 | ControlFlowNode for tty | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | builtin-class builtin_function_or_method | ControlFlowNode for from sys import * |
|
||||
| test.py | 22 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x |
|
||||
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 24 | ControlFlowNode for argv | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 31 | ControlFlowNode for argv | list object | builtin-class list | ControlFlowNode for from sys import * |
|
||||
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 34 | ControlFlowNode for timeout | builtin-class socket.timeout | builtin-class type | ControlFlowNode for from _socket import * |
|
||||
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| six | Package six |
|
||||
| six.moves | Package six.moves |
|
||||
| six.moves.http_client | Module httplib |
|
||||
| six.moves.http_client.HTTPConnection | class HTTPConnection |
|
||||
| six.moves.http_client | Missing module httplib |
|
||||
| six.moves.http_client.HTTPConnection | Missing module attribute httplib.HTTPConnection |
|
||||
| six.moves.range | builtin-class xrange |
|
||||
| six.moves.urllib | Package six.moves.urllib |
|
||||
| six.moves.urllib.parse | Module six.moves.urllib_parse |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| 38 |
|
||||
| 11 |
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
| mapping | builtin-class collections.OrderedDict |
|
||||
| mapping | builtin-class collections.defaultdict |
|
||||
| mapping | builtin-class dict |
|
||||
| mapping | class MyDictSubclass |
|
||||
| mapping | class MyMappingABC |
|
||||
| mapping | class OrderedDict |
|
||||
| neither sequence nor mapping | builtin-class set |
|
||||
| sequence | builtin-class bytes |
|
||||
| sequence | builtin-class list |
|
||||
|
||||
@@ -44,14 +44,10 @@
|
||||
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
|
||||
| test.py | 16 | ControlFlowNode for Attribute | class Y | ControlFlowNode for ClassExpr |
|
||||
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
|
||||
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | ControlFlowNode for ImportExpr |
|
||||
| test.py | 19 | ControlFlowNode for tty | Module tty | ControlFlowNode for ImportExpr |
|
||||
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | ControlFlowNode for from sys import * |
|
||||
| test.py | 22 | ControlFlowNode for x | Module package.x | Entry node for Module package.x |
|
||||
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 24 | ControlFlowNode for argv | int 0 | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
|
||||
| test.py | 31 | ControlFlowNode for argv | list object | ControlFlowNode for from sys import * |
|
||||
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | ControlFlowNode for ImportExpr |
|
||||
| test.py | 34 | ControlFlowNode for timeout | builtin-class TimeoutError | ControlFlowNode for from _socket import * |
|
||||
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
|
||||
|
||||
@@ -44,14 +44,10 @@
|
||||
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
|
||||
| test.py | 16 | ControlFlowNode for Attribute | class Y | builtin-class type | ControlFlowNode for ClassExpr |
|
||||
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
|
||||
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 19 | ControlFlowNode for tty | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | builtin-class builtin_function_or_method | ControlFlowNode for from sys import * |
|
||||
| test.py | 22 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x |
|
||||
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 24 | ControlFlowNode for argv | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 31 | ControlFlowNode for argv | list object | builtin-class list | ControlFlowNode for from sys import * |
|
||||
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 34 | ControlFlowNode for timeout | builtin-class TimeoutError | builtin-class type | ControlFlowNode for from _socket import * |
|
||||
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
| mwe_failure.py:7:1:7:23 | class MyTest | <MISSING BASE TYPE> |
|
||||
| mwe_failure_2.py:7:1:7:23 | class MyTest | <MISSING BASE TYPE> |
|
||||
| mwe_failure.py:7:1:7:23 | class MyTest | class TestCase |
|
||||
| mwe_failure_2.py:7:1:7:23 | class MyTest | class TestCase |
|
||||
| mwe_success.py:7:1:7:23 | class MyTest | class TestCase |
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
| Module package.assistant | e | Wrong() |
|
||||
| Module package.assistant | f | int 1 |
|
||||
| Module package.helper | __name__ | str u'package.helper' |
|
||||
| Module package.helper | absolute_import | _Feature() |
|
||||
| Module package.helper | assistant | Module package.assistant |
|
||||
| Module package.helper | d | int 4 |
|
||||
| Module package.helper | e | int 5 |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| six | Package six |
|
||||
| six.moves | Package six.moves |
|
||||
| six.moves.http_client | Module http.client |
|
||||
| six.moves.http_client.HTTPConnection | class HTTPConnection |
|
||||
| six.moves.http_client | Missing module http.client |
|
||||
| six.moves.http_client.HTTPConnection | Missing module attribute http.client.HTTPConnection |
|
||||
| six.moves.range | builtin-class range |
|
||||
| six.moves.urllib | Package six.moves.urllib |
|
||||
| six.moves.urllib.parse | Module six.moves.urllib_parse |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| 51 |
|
||||
| 11 |
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
| UndefinedExport.py:3:18:3:20 | StringLiteral | The name 'y' is exported by __all__ but is not defined. |
|
||||
| UndefinedExport.py:3:23:3:25 | StringLiteral | The name 'z' is exported by __all__ but is not defined. |
|
||||
| UndefinedExport.py:3:28:3:35 | StringLiteral | The name 'module' is exported by __all__ but is not defined. |
|
||||
| enum_convert.py:8:13:8:19 | StringLiteral | The name 'Maybe' is exported by __all__ but is not defined. |
|
||||
| enum_convert.py:8:22:8:32 | StringLiteral | The name 'Maybe_not' is exported by __all__ but is not defined. |
|
||||
| package/__init__.py:1:23:1:34 | StringLiteral | The name 'not_exists' is exported by __all__ but is not defined. |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| options.all | False |
|
||||
| options.colorize | True |
|
||||
| options.context_cost | 11 |
|
||||
| options.extract_stdlib | True |
|
||||
| options.extract_stdlib | False |
|
||||
| options.guess | False |
|
||||
| options.help | False |
|
||||
| options.ignore_missing_modules | False |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
| 1 | ControlFlowNode for functools | Module functools | test.py:1 |
|
||||
| 3 | ControlFlowNode for annotate | Function annotate | test.py:3 |
|
||||
| 4 | ControlFlowNode for inner | Function inner | test.py:4 |
|
||||
| 5 | ControlFlowNode for func | Function func1 | test.py:23 |
|
||||
@@ -11,7 +10,6 @@
|
||||
| 13 | ControlFlowNode for wrapper | Function wrapper | test.py:10 |
|
||||
| 15 | ControlFlowNode for wraps2 | Function wraps2 | test.py:15 |
|
||||
| 16 | ControlFlowNode for func | Function func3 | test.py:31 |
|
||||
| 16 | ControlFlowNode for functools | Module functools | test.py:1 |
|
||||
| 17 | ControlFlowNode for args | args | test.py:17 |
|
||||
| 17 | ControlFlowNode for wrapper | Attribute()() | test.py:16 |
|
||||
| 18 | ControlFlowNode for args | args | test.py:17 |
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
| test.py:11:21:11:24 | ControlFlowNode for args | runtime | instance of tuple |
|
||||
| test.py:13:12:13:18 | ControlFlowNode for wrapper | runtime | Function wraps1.wrapper |
|
||||
| test.py:13:12:13:18 | ControlFlowNode for wrapper | test.py:26 from import | Function wraps1.wrapper |
|
||||
| test.py:16:6:16:14 | ControlFlowNode for functools | runtime | Module functools |
|
||||
| test.py:16:6:16:14 | ControlFlowNode for functools | test.py:30 from import | Module functools |
|
||||
| test.py:16:6:16:14 | ControlFlowNode for functools | runtime | Missing module functools |
|
||||
| test.py:16:6:16:14 | ControlFlowNode for functools | test.py:30 from import | Missing module functools |
|
||||
| test.py:16:22:16:25 | ControlFlowNode for func | runtime | Unknown value |
|
||||
| test.py:16:22:16:25 | ControlFlowNode for func | test.py:30 from import | Function func3 |
|
||||
| test.py:18:21:18:24 | ControlFlowNode for args | runtime | instance of tuple |
|
||||
|
||||
@@ -87,10 +87,6 @@
|
||||
| Module pointsto_test | 69 | ControlFlowNode for X | class X |
|
||||
| Module pointsto_test | 70 | ControlFlowNode for Attribute | deco() |
|
||||
| Module pointsto_test | 70 | ControlFlowNode for X | class X |
|
||||
| Module pointsto_test | 72 | ControlFlowNode for ImportExpr | Module abc |
|
||||
| Module pointsto_test | 72 | ControlFlowNode for ImportMember | Function abstractmethod |
|
||||
| Module pointsto_test | 72 | ControlFlowNode for abstractmethod | Function abstractmethod |
|
||||
| Module pointsto_test | 73 | ControlFlowNode for abstractmethod | Function abstractmethod |
|
||||
| Module pointsto_test | 75 | ControlFlowNode for C | class C |
|
||||
| Module pointsto_test | 75 | ControlFlowNode for C() | C() |
|
||||
| Module pointsto_test | 75 | ControlFlowNode for type | builtin-class type |
|
||||
|
||||
@@ -95,10 +95,6 @@
|
||||
| 69 | ControlFlowNode for X | class X |
|
||||
| 70 | ControlFlowNode for Attribute | deco() |
|
||||
| 70 | ControlFlowNode for X | class X |
|
||||
| 72 | ControlFlowNode for ImportExpr | Module abc |
|
||||
| 72 | ControlFlowNode for ImportMember | Function abstractmethod |
|
||||
| 72 | ControlFlowNode for abstractmethod | Function abstractmethod |
|
||||
| 73 | ControlFlowNode for abstractmethod | Function abstractmethod |
|
||||
| 75 | ControlFlowNode for C | class C |
|
||||
| 75 | ControlFlowNode for C() | C() |
|
||||
| 75 | ControlFlowNode for type | builtin-class type |
|
||||
|
||||
@@ -95,10 +95,6 @@
|
||||
| 69 | ControlFlowNode for Attribute | Attribute | builtin-class method |
|
||||
| 69 | ControlFlowNode for X | class X | builtin-class type |
|
||||
| 70 | ControlFlowNode for X | class X | builtin-class type |
|
||||
| 72 | ControlFlowNode for ImportExpr | Module abc | builtin-class module |
|
||||
| 72 | ControlFlowNode for ImportMember | Function abstractmethod | builtin-class function |
|
||||
| 72 | ControlFlowNode for abstractmethod | Function abstractmethod | builtin-class function |
|
||||
| 73 | ControlFlowNode for abstractmethod | Function abstractmethod | builtin-class function |
|
||||
| 75 | ControlFlowNode for C | class C | builtin-class type |
|
||||
| 75 | ControlFlowNode for C() | C() | class C |
|
||||
| 75 | ControlFlowNode for type | builtin-class type | builtin-class type |
|
||||
|
||||
@@ -70,7 +70,3 @@
|
||||
| type_test.py | 55 | ControlFlowNode for arg | class E | 29 |
|
||||
| type_test.py | 67 | ControlFlowNode for x | float 1.0 | 62 |
|
||||
| type_test.py | 67 | ControlFlowNode for x | int 0 | 62 |
|
||||
| type_test.py | 77 | ControlFlowNode for IntegerLiteral | int 0 | 77 |
|
||||
| type_test.py | 83 | ControlFlowNode for IntegerLiteral | int 0 | 83 |
|
||||
| type_test.py | 89 | ControlFlowNode for IntegerLiteral | int 0 | 89 |
|
||||
| type_test.py | 95 | ControlFlowNode for IntegerLiteral | int 0 | 95 |
|
||||
|
||||
@@ -70,7 +70,3 @@
|
||||
| type_test.py | 55 | ControlFlowNode for arg | class E | builtin-class type | 29 |
|
||||
| type_test.py | 67 | ControlFlowNode for x | float 1.0 | builtin-class float | 62 |
|
||||
| type_test.py | 67 | ControlFlowNode for x | int 0 | builtin-class int | 62 |
|
||||
| type_test.py | 77 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 77 |
|
||||
| type_test.py | 83 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 83 |
|
||||
| type_test.py | 89 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 89 |
|
||||
| type_test.py | 95 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 95 |
|
||||
|
||||
@@ -85,15 +85,12 @@
|
||||
| h_classes.py:23 | Class Base | __init__ | Function __init__ |
|
||||
| h_classes.py:48 | Class D | m | Function f |
|
||||
| h_classes.py:48 | Class D | n | Function n |
|
||||
| i_imports.py:0 | Module code.i_imports | BytesIO | builtin-class _io.BytesIO |
|
||||
| i_imports.py:0 | Module code.i_imports | StringIO | builtin-class _io.StringIO |
|
||||
| i_imports.py:0 | Module code.i_imports | _io | Module _io |
|
||||
| i_imports.py:0 | Module code.i_imports | a | int 1 |
|
||||
| i_imports.py:0 | Module code.i_imports | argv | list object |
|
||||
| i_imports.py:0 | Module code.i_imports | b | int 2 |
|
||||
| i_imports.py:0 | Module code.i_imports | c | int 3 |
|
||||
| i_imports.py:0 | Module code.i_imports | code | Module code |
|
||||
| i_imports.py:0 | Module code.i_imports | io | Module io |
|
||||
| i_imports.py:0 | Module code.i_imports | module1 | Module code.test_package.module1 |
|
||||
| i_imports.py:0 | Module code.i_imports | module2 | Module code.test_package.module2 |
|
||||
| i_imports.py:0 | Module code.i_imports | p | int 1 |
|
||||
|
||||
@@ -475,14 +475,6 @@
|
||||
| i_imports.py:31 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 31 | import |
|
||||
| i_imports.py:31 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 31 | import |
|
||||
| i_imports.py:31 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | import |
|
||||
| i_imports.py:33 | ControlFlowNode for ImportExpr | Module io | builtin-class module | 33 | import |
|
||||
| i_imports.py:33 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
|
||||
| i_imports.py:34 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 55 | import |
|
||||
| i_imports.py:34 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 55 | import |
|
||||
| i_imports.py:34 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
|
||||
| i_imports.py:35 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 55 | import |
|
||||
| i_imports.py:35 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 55 | import |
|
||||
| i_imports.py:35 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
|
||||
| i_imports.py:37 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 37 | import |
|
||||
| i_imports.py:37 | ControlFlowNode for code | Module code | builtin-class module | 37 | import |
|
||||
| i_imports.py:38 | ControlFlowNode for Attribute | Function f2 | builtin-class function | 24 | import |
|
||||
|
||||
@@ -572,14 +572,6 @@
|
||||
| i_imports.py:31 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 31 |
|
||||
| i_imports.py:31 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 31 |
|
||||
| i_imports.py:31 | ControlFlowNode for _io | Module _io | builtin-class module | 29 |
|
||||
| i_imports.py:33 | ControlFlowNode for ImportExpr | Module io | builtin-class module | 33 |
|
||||
| i_imports.py:33 | ControlFlowNode for io | Module io | builtin-class module | 33 |
|
||||
| i_imports.py:34 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 55 |
|
||||
| i_imports.py:34 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 55 |
|
||||
| i_imports.py:34 | ControlFlowNode for io | Module io | builtin-class module | 33 |
|
||||
| i_imports.py:35 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 55 |
|
||||
| i_imports.py:35 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 55 |
|
||||
| i_imports.py:35 | ControlFlowNode for io | Module io | builtin-class module | 33 |
|
||||
| i_imports.py:37 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 37 |
|
||||
| i_imports.py:37 | ControlFlowNode for code | Module code | builtin-class module | 37 |
|
||||
| i_imports.py:38 | ControlFlowNode for Attribute | Function f2 | builtin-class function | 24 |
|
||||
|
||||
@@ -373,11 +373,9 @@
|
||||
| i_imports.py:30 | ControlFlowNode for _io | import | Module _io | builtin-class module |
|
||||
| i_imports.py:31 | ControlFlowNode for Attribute | import | builtin-class _io.BytesIO | builtin-class type |
|
||||
| i_imports.py:31 | ControlFlowNode for _io | import | Module _io | builtin-class module |
|
||||
| i_imports.py:33 | ControlFlowNode for ImportExpr | import | Module io | builtin-class module |
|
||||
| i_imports.py:34 | ControlFlowNode for Attribute | import | builtin-class _io.StringIO | builtin-class type |
|
||||
| i_imports.py:34 | ControlFlowNode for io | import | Module io | builtin-class module |
|
||||
| i_imports.py:35 | ControlFlowNode for Attribute | import | builtin-class _io.BytesIO | builtin-class type |
|
||||
| i_imports.py:35 | ControlFlowNode for io | import | Module io | builtin-class module |
|
||||
| i_imports.py:33 | ControlFlowNode for ImportExpr | import | Missing module io | builtin-class module |
|
||||
| i_imports.py:34 | ControlFlowNode for io | import | Missing module io | builtin-class module |
|
||||
| i_imports.py:35 | ControlFlowNode for io | import | Missing module io | builtin-class module |
|
||||
| i_imports.py:37 | ControlFlowNode for ImportExpr | import | Package code | builtin-class module |
|
||||
| i_imports.py:38 | ControlFlowNode for Attribute | import | Function f2 | builtin-class function |
|
||||
| i_imports.py:38 | ControlFlowNode for Attribute | import | Module code.n_nesting | builtin-class module |
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
| Local module | code-invalid-package-name/cmd.py:0:0:0:0 | Module cmd | referenced in external file called | pdb.py |
|
||||
| Local module | code-invalid-package-name/cmd.py:0:0:0:0 | Module cmd | referenced in local file called | test_ok.py |
|
||||
| Local module | code-invalid-package-name/unique_name.py:0:0:0:0 | Module unique_name | referenced in local file called | unique_name_use.py |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
| Module 'cmd' (local, not in stdlib, not missing) referenced in local file | code-invalid-package-name/test_ok.py:1 |
|
||||
| Module 'pdb' (external, in stdlib, not missing) referenced in local file | code-invalid-package-name/test_fail.py:3 |
|
||||
| Module 'pdb' (external, not in stdlib, missing) referenced in local file | code-invalid-package-name/test_fail.py:3 |
|
||||
| Module 'unique_name' (local, not in stdlib, not missing) referenced in local file | code-invalid-package-name/unique_name_use.py:1 |
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
testFailures
|
||||
| classes.py:54:44:54:107 | Comment #$ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result:arg1="with_length_hint" |
|
||||
| classes.py:54:44:54:107 | Comment #$ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result:func=With_length_hint.__length_hint__ |
|
||||
| classes.py:71:32:71:77 | Comment #$ arg1="with_index" func=With_index.__index__ | Missing result:arg1="with_index" |
|
||||
| classes.py:71:32:71:77 | Comment #$ arg1="with_index" func=With_index.__index__ | Missing result:func=With_index.__index__ |
|
||||
failures
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
testFailures
|
||||
| test.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
|
||||
| test.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
|
||||
| test_dict.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
|
||||
| test_dict.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
|
||||
failures
|
||||
|
||||
@@ -38,6 +38,12 @@ ensure_tainted(
|
||||
|
||||
compiled_pat.match(ts).string, # $ tainted
|
||||
re.compile(ts).match("safe").re.pattern, # $ tainted
|
||||
|
||||
list(re.finditer(pat, ts))[0].string, # $ tainted
|
||||
[m.string for m in re.finditer(pat, ts)], # $ tainted
|
||||
|
||||
list(re.finditer(pat, ts))[0].groups()[0], # $ MISSING: tainted // this requires list content in type tracking
|
||||
[m.groups()[0] for m in re.finditer(pat, ts)], # $ tainted
|
||||
)
|
||||
ensure_not_tainted(
|
||||
safe_match.expand("Hello \1"),
|
||||
|
||||
@@ -37,7 +37,7 @@ explicit_argv_parsing = parser.parse_args(sys.argv) # $ threatModelSource[comman
|
||||
ensure_tainted(explicit_argv_parsing.foo) # $ tainted
|
||||
|
||||
fake_args = parser.parse_args(["<foo>"])
|
||||
ensure_not_tainted(fake_args.foo) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(fake_args.foo)
|
||||
|
||||
########################################
|
||||
# reading input from stdin
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
| sqlite3 | 2 | 1 |
|
||||
| sqlite3.__init__ | 2 | 1 |
|
||||
| sqlite3.dump | 2 | 1 |
|
||||
|
||||
@@ -2,6 +2,5 @@
|
||||
| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
|
||||
| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
|
||||
| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. |
|
||||
| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
|
||||
| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
|
||||
| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. |
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
| assert_raises.py:9:13:9:19 | ExprStmt | This statement has no effect. |
|
||||
| assert_raises.py:11:13:11:16 | ExprStmt | This statement has no effect. |
|
||||
| test.py:24:1:24:3 | ExprStmt | This statement has no effect. |
|
||||
| test.py:25:1:25:13 | ExprStmt | This statement has no effect. |
|
||||
| test.py:26:1:26:6 | ExprStmt | This statement has no effect. |
|
||||
|
||||
@@ -440,8 +440,9 @@ fn write_extractor(grammar: &AstSrc) -> std::io::Result<String> {
|
||||
"//! Generated by `ast-generator`, do not edit by hand.\n
|
||||
#![cfg_attr(any(), rustfmt::skip)]
|
||||
|
||||
use crate::generated;
|
||||
use super::base::{{TextValue, Translator}};
|
||||
use crate::emit_detached;
|
||||
use crate::generated;
|
||||
use crate::trap::{{Label, TrapId}};
|
||||
use ra_ap_syntax::ast::{{
|
||||
HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasModuleItem, HasName,
|
||||
@@ -449,7 +450,7 @@ use ra_ap_syntax::ast::{{
|
||||
}};
|
||||
use ra_ap_syntax::{{ast, AstNode}};
|
||||
|
||||
impl Translator {{
|
||||
impl Translator<'_> {{
|
||||
fn emit_else_branch(&mut self, node: ast::ElseBranch) -> Label<generated::Expr> {{
|
||||
match node {{
|
||||
ast::ElseBranch::IfExpr(inner) => self.emit_if_expr(inner).into(),
|
||||
@@ -550,7 +551,12 @@ impl Translator {{
|
||||
writeln!(buf, " self.emit_location(label, &node);")?;
|
||||
writeln!(
|
||||
buf,
|
||||
" self.emit_tokens(label.into(), node.syntax().children_with_tokens());"
|
||||
" emit_detached!({}, self, node, label);",
|
||||
class_name
|
||||
)?;
|
||||
writeln!(
|
||||
buf,
|
||||
" self.emit_tokens(&node, label.into(), node.syntax().children_with_tokens());"
|
||||
)?;
|
||||
writeln!(buf, " label")?;
|
||||
|
||||
@@ -566,9 +572,6 @@ fn main() -> std::io::Result<()> {
|
||||
.parse()
|
||||
.unwrap();
|
||||
let mut grammar = codegen::grammar::lower(&grammar);
|
||||
grammar
|
||||
.nodes
|
||||
.retain(|x| x.name != "MacroStmts" && x.name != "MacroItems");
|
||||
|
||||
grammar.enums.retain(|x| x.name != "Adt");
|
||||
|
||||
|
||||
@@ -13,12 +13,14 @@ ra_ap_base_db = "0.0.232"
|
||||
ra_ap_hir = "0.0.232"
|
||||
ra_ap_hir_def = "0.0.232"
|
||||
ra_ap_ide_db = "0.0.232"
|
||||
ra_ap_hir_expand = "0.0.232"
|
||||
ra_ap_load-cargo = "0.0.232"
|
||||
ra_ap_paths = "0.0.232"
|
||||
ra_ap_project_model = "0.0.232"
|
||||
ra_ap_syntax = "0.0.232"
|
||||
ra_ap_vfs = "0.0.232"
|
||||
ra_ap_parser = "0.0.232"
|
||||
ra_ap_span = "0.0.232"
|
||||
serde = "1.0.209"
|
||||
serde_with = "3.9.0"
|
||||
stderrlog = "0.6.0"
|
||||
|
||||
2
rust/extractor/src/generated/.generated.list
generated
2
rust/extractor/src/generated/.generated.list
generated
@@ -1,2 +1,2 @@
|
||||
mod.rs 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7
|
||||
top.rs 7c68cdb6a44e3f1ac27601f006a8c583ef1e5f198fd9c30a6710ffade2612d80 7c68cdb6a44e3f1ac27601f006a8c583ef1e5f198fd9c30a6710ffade2612d80
|
||||
top.rs f7bff00786adef1f7f80825d9f613a958c92d35896ea8c3c3b077b9992dca590 f7bff00786adef1f7f80825d9f613a958c92d35896ea8c3c3b077b9992dca590
|
||||
|
||||
110
rust/extractor/src/generated/top.rs
generated
110
rust/extractor/src/generated/top.rs
generated
@@ -1068,6 +1068,110 @@ impl From<trap::Label<Lifetime>> for trap::Label<Locatable> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MacroItems {
|
||||
pub id: trap::TrapId<MacroItems>,
|
||||
pub items: Vec<trap::Label<Item>>,
|
||||
}
|
||||
|
||||
impl trap::TrapEntry for MacroItems {
|
||||
fn extract_id(&mut self) -> trap::TrapId<Self> {
|
||||
std::mem::replace(&mut self.id, trap::TrapId::Star)
|
||||
}
|
||||
|
||||
fn emit(self, id: trap::Label<Self>, out: &mut trap::Writer) {
|
||||
out.add_tuple("macro_items", vec![id.into()]);
|
||||
for (i, v) in self.items.into_iter().enumerate() {
|
||||
out.add_tuple("macro_items_items", vec![id.into(), i.into(), v.into()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl trap::TrapClass for MacroItems {
|
||||
fn class_name() -> &'static str { "MacroItems" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroItems>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<MacroItems>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroItems is a subclass of AstNode
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroItems>> for trap::Label<Element> {
|
||||
fn from(value: trap::Label<MacroItems>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroItems is a subclass of Element
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroItems>> for trap::Label<Locatable> {
|
||||
fn from(value: trap::Label<MacroItems>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroItems is a subclass of Locatable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MacroStmts {
|
||||
pub id: trap::TrapId<MacroStmts>,
|
||||
pub expr: Option<trap::Label<Expr>>,
|
||||
pub statements: Vec<trap::Label<Stmt>>,
|
||||
}
|
||||
|
||||
impl trap::TrapEntry for MacroStmts {
|
||||
fn extract_id(&mut self) -> trap::TrapId<Self> {
|
||||
std::mem::replace(&mut self.id, trap::TrapId::Star)
|
||||
}
|
||||
|
||||
fn emit(self, id: trap::Label<Self>, out: &mut trap::Writer) {
|
||||
out.add_tuple("macro_stmts", vec![id.into()]);
|
||||
if let Some(v) = self.expr {
|
||||
out.add_tuple("macro_stmts_exprs", vec![id.into(), v.into()]);
|
||||
}
|
||||
for (i, v) in self.statements.into_iter().enumerate() {
|
||||
out.add_tuple("macro_stmts_statements", vec![id.into(), i.into(), v.into()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl trap::TrapClass for MacroStmts {
|
||||
fn class_name() -> &'static str { "MacroStmts" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroStmts>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<MacroStmts>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroStmts is a subclass of AstNode
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroStmts>> for trap::Label<Element> {
|
||||
fn from(value: trap::Label<MacroStmts>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroStmts is a subclass of Element
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroStmts>> for trap::Label<Locatable> {
|
||||
fn from(value: trap::Label<MacroStmts>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroStmts is a subclass of Locatable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MatchArm {
|
||||
pub id: trap::TrapId<MatchArm>,
|
||||
@@ -8720,6 +8824,12 @@ impl trap::TrapEntry for MacroCall {
|
||||
}
|
||||
}
|
||||
|
||||
impl MacroCall {
|
||||
pub fn emit_expanded(id: trap::Label<Self>, value: trap::Label<AstNode>, out: &mut trap::Writer) {
|
||||
out.add_tuple("macro_call_expandeds", vec![id.into(), value.into()]);
|
||||
}
|
||||
}
|
||||
|
||||
impl trap::TrapClass for MacroCall {
|
||||
fn class_name() -> &'static str { "MacroCall" }
|
||||
}
|
||||
|
||||
@@ -1,92 +1,119 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use ra_ap_ide_db::line_index::LineIndex;
|
||||
use ra_ap_parser::Edition;
|
||||
use std::borrow::Cow;
|
||||
use archive::Archiver;
|
||||
use ra_ap_ide_db::line_index::{LineCol, LineIndex};
|
||||
use ra_ap_project_model::ProjectManifest;
|
||||
use rust_analyzer::{ParseResult, RustAnalyzer};
|
||||
mod archive;
|
||||
mod config;
|
||||
pub mod generated;
|
||||
mod rust_analyzer;
|
||||
mod translate;
|
||||
pub mod trap;
|
||||
use ra_ap_syntax::ast::SourceFile;
|
||||
use ra_ap_syntax::{AstNode, SyntaxError, TextRange, TextSize};
|
||||
|
||||
fn from_utf8_lossy(v: &[u8]) -> (Cow<'_, str>, Option<SyntaxError>) {
|
||||
let mut iter = v.utf8_chunks();
|
||||
let (first_valid, first_invalid) = if let Some(chunk) = iter.next() {
|
||||
let valid = chunk.valid();
|
||||
let invalid = chunk.invalid();
|
||||
if invalid.is_empty() {
|
||||
debug_assert_eq!(valid.len(), v.len());
|
||||
return (Cow::Borrowed(valid), None);
|
||||
}
|
||||
(valid, invalid)
|
||||
} else {
|
||||
return (Cow::Borrowed(""), None);
|
||||
};
|
||||
|
||||
const REPLACEMENT: &str = "\u{FFFD}";
|
||||
let error_start = first_valid.len() as u32;
|
||||
let error_end = error_start + first_invalid.len() as u32;
|
||||
let error_range = TextRange::new(TextSize::new(error_start), TextSize::new(error_end));
|
||||
let error = SyntaxError::new("invalid utf-8 sequence".to_owned(), error_range);
|
||||
let mut res = String::with_capacity(v.len());
|
||||
res.push_str(first_valid);
|
||||
|
||||
res.push_str(REPLACEMENT);
|
||||
|
||||
for chunk in iter {
|
||||
res.push_str(chunk.valid());
|
||||
if !chunk.invalid().is_empty() {
|
||||
res.push_str(REPLACEMENT);
|
||||
}
|
||||
}
|
||||
|
||||
(Cow::Owned(res), Some(error))
|
||||
}
|
||||
|
||||
fn extract(
|
||||
archiver: &archive::Archiver,
|
||||
rust_analyzer: &mut rust_analyzer::RustAnalyzer,
|
||||
archiver: &Archiver,
|
||||
traps: &trap::TrapFileProvider,
|
||||
file: std::path::PathBuf,
|
||||
) -> anyhow::Result<()> {
|
||||
let file = std::path::absolute(&file).unwrap_or(file);
|
||||
let file = std::fs::canonicalize(&file).unwrap_or(file);
|
||||
archiver.archive(&file);
|
||||
let input = std::fs::read(&file)?;
|
||||
let (input, err) = from_utf8_lossy(&input);
|
||||
let line_index = LineIndex::new(&input);
|
||||
file: &std::path::Path,
|
||||
) {
|
||||
archiver.archive(file);
|
||||
|
||||
let ParseResult {
|
||||
ast,
|
||||
text,
|
||||
errors,
|
||||
file_id,
|
||||
semantics,
|
||||
} = rust_analyzer.parse(file);
|
||||
let line_index = LineIndex::new(text.as_ref());
|
||||
let display_path = file.to_string_lossy();
|
||||
let mut trap = traps.create("source", &file);
|
||||
let label = trap.emit_file(&file);
|
||||
let mut translator = translate::Translator::new(trap, label, line_index);
|
||||
if let Some(err) = err {
|
||||
translator.emit_parse_error(display_path.as_ref(), err);
|
||||
let mut trap = traps.create("source", file);
|
||||
let label = trap.emit_file(file);
|
||||
let mut translator = translate::Translator::new(
|
||||
trap,
|
||||
display_path.as_ref(),
|
||||
label,
|
||||
line_index,
|
||||
file_id,
|
||||
semantics,
|
||||
);
|
||||
|
||||
for err in errors {
|
||||
translator.emit_parse_error(&ast, &err);
|
||||
}
|
||||
let parse = ra_ap_syntax::ast::SourceFile::parse(&input, Edition::CURRENT);
|
||||
for err in parse.errors() {
|
||||
translator.emit_parse_error(display_path.as_ref(), err);
|
||||
let no_location = (LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 });
|
||||
if translator.semantics.is_none() {
|
||||
translator.emit_diagnostic(
|
||||
trap::DiagnosticSeverity::Warning,
|
||||
"semantics".to_owned(),
|
||||
"semantic analyzer unavailable".to_owned(),
|
||||
"semantic analyzer unavailable: macro expansion, call graph, and type inference will be skipped.".to_owned(),
|
||||
no_location,
|
||||
);
|
||||
}
|
||||
if let Some(ast) = SourceFile::cast(parse.syntax_node()) {
|
||||
translator.emit_source_file(ast);
|
||||
} else {
|
||||
log::warn!("Skipped {}", display_path);
|
||||
}
|
||||
translator.trap.commit()?;
|
||||
Ok(())
|
||||
translator.emit_source_file(ast);
|
||||
translator.trap.commit().unwrap_or_else(|err| {
|
||||
log::error!(
|
||||
"Failed to write trap file for: {}: {}",
|
||||
display_path,
|
||||
err.to_string()
|
||||
)
|
||||
});
|
||||
}
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let cfg = config::Config::extract().context("failed to load configuration")?;
|
||||
stderrlog::new()
|
||||
.module(module_path!())
|
||||
.verbosity(2 + cfg.verbose as usize)
|
||||
.verbosity(1 + cfg.verbose as usize)
|
||||
.init()?;
|
||||
log::info!("{cfg:?}");
|
||||
|
||||
let traps = trap::TrapFileProvider::new(&cfg).context("failed to set up trap files")?;
|
||||
let archiver = archive::Archiver {
|
||||
root: cfg.source_archive_dir,
|
||||
};
|
||||
for file in cfg.inputs {
|
||||
extract(&archiver, &traps, file)?;
|
||||
let files: Vec<PathBuf> = cfg
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|file| {
|
||||
let file = std::path::absolute(file).unwrap_or(file.to_path_buf());
|
||||
std::fs::canonicalize(&file).unwrap_or(file)
|
||||
})
|
||||
.collect();
|
||||
let manifests = rust_analyzer::find_project_manifests(&files)?;
|
||||
let mut map: HashMap<&Path, (&ProjectManifest, Vec<&Path>)> = manifests
|
||||
.iter()
|
||||
.map(|x| (x.manifest_path().parent().as_ref(), (x, Vec::new())))
|
||||
.collect();
|
||||
let mut other_files = Vec::new();
|
||||
|
||||
'outer: for file in &files {
|
||||
let mut p = file.as_path();
|
||||
while let Some(parent) = p.parent() {
|
||||
p = parent;
|
||||
if let Some((_, files)) = map.get_mut(parent) {
|
||||
files.push(file);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
other_files.push(file);
|
||||
}
|
||||
for (manifest, files) in map.values() {
|
||||
if files.is_empty() {
|
||||
break;
|
||||
}
|
||||
let mut rust_analyzer = RustAnalyzer::new(manifest, &cfg.scratch_dir);
|
||||
for file in files {
|
||||
extract(&mut rust_analyzer, &archiver, &traps, file);
|
||||
}
|
||||
}
|
||||
let mut rust_analyzer = RustAnalyzer::WithoutDatabase();
|
||||
for file in other_files {
|
||||
extract(&mut rust_analyzer, &archiver, &traps, file);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
160
rust/extractor/src/rust_analyzer.rs
Normal file
160
rust/extractor/src/rust_analyzer.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
use itertools::Itertools;
|
||||
use log::info;
|
||||
use ra_ap_base_db::SourceDatabase;
|
||||
use ra_ap_base_db::SourceDatabaseFileInputExt;
|
||||
use ra_ap_hir::Semantics;
|
||||
use ra_ap_ide_db::RootDatabase;
|
||||
use ra_ap_load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
|
||||
use ra_ap_paths::Utf8PathBuf;
|
||||
use ra_ap_project_model::CargoConfig;
|
||||
use ra_ap_project_model::ProjectManifest;
|
||||
use ra_ap_project_model::RustLibSource;
|
||||
use ra_ap_span::Edition;
|
||||
use ra_ap_span::EditionedFileId;
|
||||
use ra_ap_span::TextRange;
|
||||
use ra_ap_span::TextSize;
|
||||
use ra_ap_syntax::SourceFile;
|
||||
use ra_ap_syntax::SyntaxError;
|
||||
use ra_ap_vfs::AbsPathBuf;
|
||||
use ra_ap_vfs::Vfs;
|
||||
use ra_ap_vfs::VfsPath;
|
||||
use std::borrow::Cow;
|
||||
use std::path::{Path, PathBuf};
|
||||
use triomphe::Arc;
|
||||
pub enum RustAnalyzer {
|
||||
WithDatabase { db: RootDatabase, vfs: Vfs },
|
||||
WithoutDatabase(),
|
||||
}
|
||||
pub struct ParseResult<'a> {
|
||||
pub ast: SourceFile,
|
||||
pub text: Arc<str>,
|
||||
pub errors: Vec<SyntaxError>,
|
||||
pub file_id: Option<EditionedFileId>,
|
||||
pub semantics: Option<Semantics<'a, RootDatabase>>,
|
||||
}
|
||||
impl RustAnalyzer {
|
||||
pub fn new(project: &ProjectManifest, scratch_dir: &Path) -> Self {
|
||||
let config = CargoConfig {
|
||||
sysroot: Some(RustLibSource::Discover),
|
||||
target_dir: ra_ap_paths::Utf8PathBuf::from_path_buf(scratch_dir.to_path_buf())
|
||||
.map(|x| x.join("target"))
|
||||
.ok(),
|
||||
..Default::default()
|
||||
};
|
||||
let progress = |t| (log::trace!("progress: {}", t));
|
||||
let load_config = LoadCargoConfig {
|
||||
load_out_dirs_from_check: true,
|
||||
with_proc_macro_server: ProcMacroServerChoice::Sysroot,
|
||||
prefill_caches: false,
|
||||
};
|
||||
let manifest = project.manifest_path();
|
||||
|
||||
match load_workspace_at(manifest.as_ref(), &config, &load_config, &progress) {
|
||||
Ok((db, vfs, _macro_server)) => RustAnalyzer::WithDatabase { db, vfs },
|
||||
Err(err) => {
|
||||
log::error!("failed to load workspace for {}: {}", manifest, err);
|
||||
RustAnalyzer::WithoutDatabase()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn parse(&mut self, path: &Path) -> ParseResult<'_> {
|
||||
let mut errors = Vec::new();
|
||||
let input = match std::fs::read(path) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
errors.push(SyntaxError::new(
|
||||
format!("Could not read {}: {}", path.to_string_lossy(), e),
|
||||
TextRange::empty(TextSize::default()),
|
||||
));
|
||||
vec![]
|
||||
}
|
||||
};
|
||||
let (input, err) = from_utf8_lossy(&input);
|
||||
|
||||
if let RustAnalyzer::WithDatabase { vfs, db } = self {
|
||||
if let Some(file_id) = Utf8PathBuf::from_path_buf(path.to_path_buf())
|
||||
.ok()
|
||||
.and_then(|x| AbsPathBuf::try_from(x).ok())
|
||||
.map(VfsPath::from)
|
||||
.and_then(|x| vfs.file_id(&x))
|
||||
{
|
||||
db.set_file_text(file_id, &input);
|
||||
let semantics = Semantics::new(db);
|
||||
|
||||
let file_id = EditionedFileId::current_edition(file_id);
|
||||
let source_file = semantics.parse(file_id);
|
||||
errors.extend(
|
||||
db.parse_errors(file_id)
|
||||
.into_iter()
|
||||
.flat_map(|x| x.to_vec()),
|
||||
);
|
||||
return ParseResult {
|
||||
ast: source_file,
|
||||
text: input.as_ref().into(),
|
||||
errors,
|
||||
file_id: Some(file_id),
|
||||
semantics: Some(semantics),
|
||||
};
|
||||
}
|
||||
}
|
||||
let parse = ra_ap_syntax::ast::SourceFile::parse(&input, Edition::CURRENT);
|
||||
errors.extend(parse.errors());
|
||||
errors.extend(err);
|
||||
ParseResult {
|
||||
ast: parse.tree(),
|
||||
text: input.as_ref().into(),
|
||||
errors,
|
||||
file_id: None,
|
||||
semantics: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_project_manifests(
|
||||
files: &[PathBuf],
|
||||
) -> anyhow::Result<Vec<ra_ap_project_model::ProjectManifest>> {
|
||||
let current = std::env::current_dir()?;
|
||||
let abs_files: Vec<_> = files
|
||||
.iter()
|
||||
.map(|path| AbsPathBuf::assert_utf8(current.join(path)))
|
||||
.collect();
|
||||
let ret = ra_ap_project_model::ProjectManifest::discover_all(&abs_files);
|
||||
info!(
|
||||
"found manifests: {}",
|
||||
ret.iter().map(|m| format!("{m}")).join(", ")
|
||||
);
|
||||
Ok(ret)
|
||||
}
|
||||
fn from_utf8_lossy(v: &[u8]) -> (Cow<'_, str>, Option<SyntaxError>) {
|
||||
let mut iter = v.utf8_chunks();
|
||||
let (first_valid, first_invalid) = if let Some(chunk) = iter.next() {
|
||||
let valid = chunk.valid();
|
||||
let invalid = chunk.invalid();
|
||||
if invalid.is_empty() {
|
||||
debug_assert_eq!(valid.len(), v.len());
|
||||
return (Cow::Borrowed(valid), None);
|
||||
}
|
||||
(valid, invalid)
|
||||
} else {
|
||||
return (Cow::Borrowed(""), None);
|
||||
};
|
||||
|
||||
const REPLACEMENT: &str = "\u{FFFD}";
|
||||
let error_start = first_valid.len() as u32;
|
||||
let error_end = error_start + first_invalid.len() as u32;
|
||||
let error_range = TextRange::new(TextSize::new(error_start), TextSize::new(error_end));
|
||||
let error = SyntaxError::new("invalid utf-8 sequence".to_owned(), error_range);
|
||||
let mut res = String::with_capacity(v.len());
|
||||
res.push_str(first_valid);
|
||||
|
||||
res.push_str(REPLACEMENT);
|
||||
|
||||
for chunk in iter {
|
||||
res.push_str(chunk.valid());
|
||||
if !chunk.invalid().is_empty() {
|
||||
res.push_str(REPLACEMENT);
|
||||
}
|
||||
}
|
||||
|
||||
(Cow::Owned(res), Some(error))
|
||||
}
|
||||
@@ -1,11 +1,30 @@
|
||||
use crate::generated::{self, AstNode};
|
||||
use crate::generated::MacroCall;
|
||||
use crate::generated::{self};
|
||||
use crate::trap::{DiagnosticSeverity, TrapFile, TrapId};
|
||||
use crate::trap::{Label, TrapClass};
|
||||
use codeql_extractor::trap::{self};
|
||||
use log::Level;
|
||||
use ra_ap_hir::db::ExpandDatabase;
|
||||
use ra_ap_hir::Semantics;
|
||||
use ra_ap_hir_expand::ExpandTo;
|
||||
use ra_ap_ide_db::line_index::{LineCol, LineIndex};
|
||||
use ra_ap_ide_db::RootDatabase;
|
||||
use ra_ap_parser::SyntaxKind;
|
||||
use ra_ap_span::{EditionedFileId, TextSize};
|
||||
use ra_ap_syntax::ast::RangeItem;
|
||||
use ra_ap_syntax::{ast, NodeOrToken, SyntaxElementChildren, SyntaxError, SyntaxToken, TextRange};
|
||||
use ra_ap_syntax::{
|
||||
ast, AstNode, NodeOrToken, SyntaxElementChildren, SyntaxError, SyntaxNode, SyntaxToken,
|
||||
TextRange,
|
||||
};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! emit_detached {
|
||||
(MacroCall, $self:ident, $node:ident, $label:ident) => {
|
||||
$self.extract_macro_call_expanded(&$node, $label.into());
|
||||
};
|
||||
($($_:tt)*) => {};
|
||||
}
|
||||
|
||||
pub trait TextValue {
|
||||
fn try_get_text(&self) -> Option<String>;
|
||||
}
|
||||
@@ -56,27 +75,41 @@ impl TextValue for ast::RangePat {
|
||||
self.op_token().map(|x| x.text().to_string())
|
||||
}
|
||||
}
|
||||
pub struct Translator {
|
||||
|
||||
pub struct Translator<'a> {
|
||||
pub trap: TrapFile,
|
||||
path: &'a str,
|
||||
label: trap::Label,
|
||||
line_index: LineIndex,
|
||||
file_id: Option<EditionedFileId>,
|
||||
pub semantics: Option<Semantics<'a, RootDatabase>>,
|
||||
}
|
||||
|
||||
impl Translator {
|
||||
pub fn new(trap: TrapFile, label: trap::Label, line_index: LineIndex) -> Translator {
|
||||
impl<'a> Translator<'a> {
|
||||
pub fn new(
|
||||
trap: TrapFile,
|
||||
path: &'a str,
|
||||
label: trap::Label,
|
||||
line_index: LineIndex,
|
||||
file_id: Option<EditionedFileId>,
|
||||
semantics: Option<Semantics<'a, RootDatabase>>,
|
||||
) -> Translator<'a> {
|
||||
Translator {
|
||||
trap,
|
||||
path,
|
||||
label,
|
||||
line_index,
|
||||
file_id,
|
||||
semantics,
|
||||
}
|
||||
}
|
||||
pub fn location(&self, range: TextRange) -> (LineCol, LineCol) {
|
||||
fn location(&self, range: TextRange) -> (LineCol, LineCol) {
|
||||
let start = self.line_index.line_col(range.start());
|
||||
let range_end = range.end();
|
||||
// QL end positions are inclusive, while TextRange offsets are exclusive and point at the position
|
||||
// right after the last character of the range. We need to shift the end offset one character to the left to
|
||||
// get the right inclusive QL position. Unfortunately, simply subtracting `1` from the end-offset may cause
|
||||
// the offset to point in the middle of a mult-byte character, resulting in a `panic`. Therefore we use `try_line_col`
|
||||
// the offset to point in the middle of a multi-byte character, resulting in a `panic`. Therefore we use `try_line_col`
|
||||
// with decreasing offsets to find the start of the last character included in the range.
|
||||
for i in 1..4 {
|
||||
if let Some(end) = range_end
|
||||
@@ -89,39 +122,210 @@ impl Translator {
|
||||
let end = self.line_index.line_col(range_end);
|
||||
(start, end)
|
||||
}
|
||||
|
||||
pub fn text_range_for_node(&mut self, node: &impl ast::AstNode) -> Option<TextRange> {
|
||||
if let Some(semantics) = self.semantics.as_ref() {
|
||||
let file_range = semantics.original_range(node.syntax());
|
||||
let file_id = self.file_id?;
|
||||
if file_id == file_range.file_id {
|
||||
Some(file_range.range)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
Some(node.syntax().text_range())
|
||||
}
|
||||
}
|
||||
pub fn emit_location<T: TrapClass>(&mut self, label: Label<T>, node: &impl ast::AstNode) {
|
||||
let (start, end) = self.location(node.syntax().text_range());
|
||||
self.trap.emit_location(self.label, label, start, end)
|
||||
if let Some(range) = self.text_range_for_node(node) {
|
||||
let (start, end) = self.location(range);
|
||||
self.trap.emit_location(self.label, label, start, end)
|
||||
} else {
|
||||
self.emit_diagnostic(
|
||||
DiagnosticSeverity::Info,
|
||||
"locations".to_owned(),
|
||||
"missing location for AstNode".to_owned(),
|
||||
"missing location for AstNode".to_owned(),
|
||||
(LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 }),
|
||||
);
|
||||
}
|
||||
}
|
||||
pub fn emit_location_token(&mut self, label: Label<generated::Token>, token: &SyntaxToken) {
|
||||
let (start, end) = self.location(token.text_range());
|
||||
self.trap.emit_location(self.label, label, start, end)
|
||||
pub fn emit_location_token(
|
||||
&mut self,
|
||||
label: Label<generated::Token>,
|
||||
parent: &impl ast::AstNode,
|
||||
token: &SyntaxToken,
|
||||
) {
|
||||
let parent_range = parent.syntax().text_range();
|
||||
let token_range = token.text_range();
|
||||
if let Some(clipped_range) = token_range.intersect(parent_range) {
|
||||
if let Some(parent_range2) = self.text_range_for_node(parent) {
|
||||
let token_range = clipped_range + parent_range2.start() - parent_range.start();
|
||||
let (start, end) = self.location(token_range);
|
||||
self.trap.emit_location(self.label, label, start, end)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn emit_parse_error(&mut self, path: &str, err: SyntaxError) {
|
||||
let (start, end) = self.location(err.range());
|
||||
log::warn!("{}:{}:{}: {}", path, start.line + 1, start.col + 1, err);
|
||||
let message = err.to_string();
|
||||
pub fn emit_diagnostic(
|
||||
&mut self,
|
||||
severity: DiagnosticSeverity,
|
||||
error_tag: String,
|
||||
error_message: String,
|
||||
full_error_message: String,
|
||||
location: (LineCol, LineCol),
|
||||
) {
|
||||
let (start, end) = location;
|
||||
let level = match severity {
|
||||
DiagnosticSeverity::Debug => Level::Debug,
|
||||
DiagnosticSeverity::Info => Level::Info,
|
||||
DiagnosticSeverity::Warning => Level::Warn,
|
||||
DiagnosticSeverity::Error => Level::Error,
|
||||
};
|
||||
log::log!(
|
||||
level,
|
||||
"{}:{}:{}: {}",
|
||||
self.path,
|
||||
start.line + 1,
|
||||
start.col + 1,
|
||||
&error_message
|
||||
);
|
||||
let location = self.trap.emit_location_label(self.label, start, end);
|
||||
self.trap.emit_diagnostic(
|
||||
DiagnosticSeverity::Warning,
|
||||
"parse_error".to_owned(),
|
||||
message.clone(),
|
||||
message,
|
||||
severity,
|
||||
error_tag,
|
||||
error_message,
|
||||
full_error_message,
|
||||
location,
|
||||
);
|
||||
}
|
||||
pub fn emit_tokens(&mut self, parent: Label<AstNode>, children: SyntaxElementChildren) {
|
||||
pub fn emit_parse_error(&mut self, owner: &impl ast::AstNode, err: &SyntaxError) {
|
||||
let owner_range: TextRange = owner.syntax().text_range();
|
||||
let err_range = err.range();
|
||||
if let Some(owner_range2) = self.text_range_for_node(owner) {
|
||||
let location = if let Some(clipped_range) = err_range.intersect(owner_range) {
|
||||
let err_range = clipped_range + owner_range2.start() - owner_range.start();
|
||||
self.location(err_range)
|
||||
} else {
|
||||
self.location(owner_range2)
|
||||
};
|
||||
let message = err.to_string();
|
||||
self.emit_diagnostic(
|
||||
DiagnosticSeverity::Warning,
|
||||
"parse_error".to_owned(),
|
||||
message.clone(),
|
||||
message,
|
||||
location,
|
||||
);
|
||||
}
|
||||
}
|
||||
pub fn emit_tokens(
|
||||
&mut self,
|
||||
parent_node: &impl ast::AstNode,
|
||||
parent_label: Label<generated::AstNode>,
|
||||
children: SyntaxElementChildren,
|
||||
) {
|
||||
for child in children {
|
||||
if let NodeOrToken::Token(token) = child {
|
||||
if token.kind() == SyntaxKind::COMMENT {
|
||||
let label = self.trap.emit(generated::Comment {
|
||||
id: TrapId::Star,
|
||||
parent,
|
||||
parent: parent_label,
|
||||
text: token.text().to_owned(),
|
||||
});
|
||||
self.emit_location_token(label.into(), &token);
|
||||
self.emit_location_token(label.into(), parent_node, &token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn emit_macro_expansion_parse_errors(&mut self, mcall: &ast::MacroCall, expanded: &SyntaxNode) {
|
||||
let semantics = self.semantics.as_ref().unwrap();
|
||||
if let Some(value) = semantics
|
||||
.hir_file_for(expanded)
|
||||
.macro_file()
|
||||
.and_then(|macro_file| {
|
||||
semantics
|
||||
.db
|
||||
.parse_macro_expansion_error(macro_file.macro_call_id)
|
||||
})
|
||||
{
|
||||
if let Some(err) = &value.err {
|
||||
let (message, _error) = err.render_to_string(semantics.db);
|
||||
|
||||
if err.span().anchor.file_id == semantics.hir_file_for(mcall.syntax()) {
|
||||
let location = err.span().range
|
||||
+ semantics
|
||||
.db
|
||||
.ast_id_map(err.span().anchor.file_id.into())
|
||||
.get_erased(err.span().anchor.ast_id)
|
||||
.text_range()
|
||||
.start();
|
||||
self.emit_parse_error(mcall, &SyntaxError::new(message, location));
|
||||
};
|
||||
}
|
||||
for err in value.value.iter() {
|
||||
self.emit_parse_error(mcall, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_expanded_as(
|
||||
&mut self,
|
||||
expand_to: ExpandTo,
|
||||
expanded: SyntaxNode,
|
||||
) -> Option<Label<generated::AstNode>> {
|
||||
match expand_to {
|
||||
ra_ap_hir_expand::ExpandTo::Statements => {
|
||||
ast::MacroStmts::cast(expanded).map(|x| self.emit_macro_stmts(x).into())
|
||||
}
|
||||
ra_ap_hir_expand::ExpandTo::Items => {
|
||||
ast::MacroItems::cast(expanded).map(|x| self.emit_macro_items(x).into())
|
||||
}
|
||||
|
||||
ra_ap_hir_expand::ExpandTo::Pattern => {
|
||||
ast::Pat::cast(expanded).map(|x| self.emit_pat(x).into())
|
||||
}
|
||||
ra_ap_hir_expand::ExpandTo::Type => {
|
||||
ast::Type::cast(expanded).map(|x| self.emit_type(x).into())
|
||||
}
|
||||
ra_ap_hir_expand::ExpandTo::Expr => {
|
||||
ast::Expr::cast(expanded).map(|x| self.emit_expr(x).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn extract_macro_call_expanded(
|
||||
&mut self,
|
||||
mcall: &ast::MacroCall,
|
||||
label: Label<generated::MacroCall>,
|
||||
) {
|
||||
if let Some(expanded) = self.semantics.as_ref().and_then(|s| s.expand(mcall)) {
|
||||
self.emit_macro_expansion_parse_errors(mcall, &expanded);
|
||||
let expand_to = ra_ap_hir_expand::ExpandTo::from_call_site(mcall);
|
||||
let kind = expanded.kind();
|
||||
if let Some(value) = self.emit_expanded_as(expand_to, expanded) {
|
||||
MacroCall::emit_expanded(label, value, &mut self.trap.writer);
|
||||
} else {
|
||||
let range = self.text_range_for_node(mcall);
|
||||
self.emit_parse_error(mcall, &SyntaxError::new(
|
||||
format!(
|
||||
"macro expansion failed: the macro '{}' expands to {:?} but a {:?} was expected",
|
||||
mcall.path().map(|p| p.to_string()).unwrap_or_default(),
|
||||
kind, expand_to
|
||||
),
|
||||
range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
let range = self.text_range_for_node(mcall);
|
||||
self.emit_parse_error(
|
||||
mcall,
|
||||
&SyntaxError::new(
|
||||
format!(
|
||||
"macro expansion failed: could not resolve macro '{}'",
|
||||
mcall.path().map(|p| p.to_string()).unwrap_or_default()
|
||||
),
|
||||
range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
448
rust/extractor/src/translate/generated.rs
generated
448
rust/extractor/src/translate/generated.rs
generated
File diff suppressed because it is too large
Load Diff
@@ -124,7 +124,7 @@ impl<T: TrapClass> From<Label<T>> for trap::Arg {
|
||||
|
||||
pub struct TrapFile {
|
||||
path: PathBuf,
|
||||
writer: Writer,
|
||||
pub writer: Writer,
|
||||
compression: Compression,
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ impl TrapFileProvider {
|
||||
}
|
||||
|
||||
pub fn create(&self, category: &str, key: &Path) -> TrapFile {
|
||||
let path = file_paths::path_for(&self.trap_dir.join(category), key, ".trap");
|
||||
let path = file_paths::path_for(&self.trap_dir.join(category), key, "trap");
|
||||
debug!("creating trap file {}", path.display());
|
||||
let mut writer = trap::Writer::new();
|
||||
extractor::populate_empty_location(&mut writer);
|
||||
|
||||
31
rust/ql/.generated.list
generated
31
rust/ql/.generated.list
generated
@@ -66,11 +66,13 @@ lib/codeql/rust/elements/LiteralExpr.qll 40b67404b7c2b81e5afabc53a2a93e0a503f687
|
||||
lib/codeql/rust/elements/LiteralPat.qll daffb5f380a47543669c8cc92628b0e0de478c3ac82685802c63e8d75a206bed adfe9796598cf6ca4a9170c89ffd871e117f1cea6dd7dd80ecbbb947327a1a5d
|
||||
lib/codeql/rust/elements/Locatable.qll 2855efa4a469b54e0ca85daa89309a8b991cded6f3f10db361010831ba1e11d3 00c3406d14603f90abea11bf074eaf2c0b623a30e29cf6afc3a247cb58b92f0f
|
||||
lib/codeql/rust/elements/LoopExpr.qll 58ade0bc4a01a1cc361363682fde3ea56f4c5fbb4b28f5723ceff52ebaf897d7 fa299162c742bcf3b2211dc20821b312e3c133350c288a050eb26e6f8b5a5c78
|
||||
lib/codeql/rust/elements/MacroCall.qll 16933db15c6c0dbb717ef442f751ad8f63c444f36a12f8d56b8a05a3e5f71d1b ac05cbf50e4b06f39f58817cddbeac6f804c2d1e4f60956a960d63d495e7183d
|
||||
lib/codeql/rust/elements/MacroCall.qll a39a11d387355f59af3007dcbab3282e2b9e3289c1f8f4c6b96154ddb802f8c3 88d4575e462af2aa780219ba1338a790547fdfc1d267c4b84f1b929f4bc08d05
|
||||
lib/codeql/rust/elements/MacroDef.qll acb39275a1a3257084314a46ad4d8477946130f57e401c70c5949ad6aafc5c5f 6a8a8db12a3ec345fede51ca36e8c6acbdce58c5144388bb94f0706416fa152a
|
||||
lib/codeql/rust/elements/MacroExpr.qll ea9fed13f610bab1a2c4541c994510e0cb806530b60beef0d0c36b23e3b620f0 ad11a6bbd3a229ad97a16049cc6b0f3c8740f9f75ea61bbf4eebb072db9b12d2
|
||||
lib/codeql/rust/elements/MacroItems.qll 00a5d41f7bb836d952abbd9382e42f72a9d81e65646a15a460b35ccd07a866c6 00efdb4d701b5599d76096f740da9ec157804865267b7e29bc2a214cbf03763e
|
||||
lib/codeql/rust/elements/MacroPat.qll dbf193b4fb544ac0b5a7dcfc31a6652de7239b6e643ff15b05868b2c142e940c 19b45c0a1eb1198e450c05d564b5d4aa0d6da29e7db84b9521eadf901e20a932
|
||||
lib/codeql/rust/elements/MacroRules.qll a94535506798077043b9c1470992ac4310bf67bcce5f722080886d1b3e6d90d1 bd8e08a7171991abc85100b45267631e66d1b332caf1e5882cd17caee5cf18a3
|
||||
lib/codeql/rust/elements/MacroStmts.qll 6e9a1f90231cb72b27d3ff9479e399a9fba4abd0872a5005ab2fac45d5ca9be0 d6ca3a8254fc45794a93c451a3305c9b4be033a467ad72158d40d6f675a377a0
|
||||
lib/codeql/rust/elements/MacroType.qll e5a153643e49a6be41483ad944550a030e0500764947b4e328cef6fa08c4fbd4 a42332c0a9c5cf7317fc49f3e1049e7751004fcc3efa056bbe058a8bfa2ef0cb
|
||||
lib/codeql/rust/elements/MatchArm.qll c39fd6cc0da24b1ff8d1e42835bcfee7695ad13580e3c7c50acd7c881b1cd894 62a31d2bd125e6aaebefc406e541a641271d3c497a377959f94dd4735b2bfbf8
|
||||
lib/codeql/rust/elements/MatchArmList.qll e6c48fd7419d88e996b82eb45e4aa2686dfd079b283b02be7710192fb2cb93a0 0ec63a0ca56f5f7f80093fd3e77b198b74c6289e67be55dc6a4deb610753c7bd
|
||||
@@ -278,10 +280,14 @@ lib/codeql/rust/elements/internal/MacroDefConstructor.qll 382a3bdf46905d112ee491
|
||||
lib/codeql/rust/elements/internal/MacroDefImpl.qll f26e787ffd43e8cb079db01eba04412dbf32c338938acf1bc09a2f094bbdfdfe 044f43bc94fe4b6df22afae32e9f039d1d0d9e85ad9f24b6388be71211c37ce5
|
||||
lib/codeql/rust/elements/internal/MacroExprConstructor.qll b12edb21ea189a1b28d96309c69c3d08e08837621af22edd67ff9416c097d2df d35bc98e7b7b5451930214c0d93dce33a2c7b5b74f36bf99f113f53db1f19c14
|
||||
lib/codeql/rust/elements/internal/MacroExprImpl.qll 92dd9f658a85ae407e055f090385f451084de59190d8a00c7e1fba453c3eced4 89d544634fecdbead2ff06a26fc8132e127dab07f38b9322fa14dc55657b9f1a
|
||||
lib/codeql/rust/elements/internal/MacroItemsConstructor.qll 8e9ab7ec1e0f50a22605d4e993f99a85ca8059fbb506d67bc8f5a281af367b05 2602f9db31ea0c48192c3dde3bb5625a8ed1cae4cd3408729b9e09318d5bd071
|
||||
lib/codeql/rust/elements/internal/MacroItemsImpl.qll 76fd50a1f27336e9efc6d3f73ef4d724f19627cadbaa805d1e14d2cfa4f19899 40c0e512090050b39b69128730f4f4581f51ffd3c687fb52913617bd70a144e9
|
||||
lib/codeql/rust/elements/internal/MacroPatConstructor.qll 24744c1bbe21c1d249a04205fb09795ae38ed106ba1423e86ccbc5e62359eaa2 4fac3f731a1ffd87c1230d561c5236bd28dcde0d1ce0dcd7d7a84ba393669d4a
|
||||
lib/codeql/rust/elements/internal/MacroPatImpl.qll 7470e2d88c38c7300a64986f058ba92bb22b4945438e2e0e268f180c4f267b71 c1507df74fc4c92887f3e0a4f857f54b61f174ffae5b1af6fb70f466175d658b
|
||||
lib/codeql/rust/elements/internal/MacroRulesConstructor.qll dc04726ad59915ec980501c4cd3b3d2ad774f454ddbf138ff5808eba6bd63dea 8d6bf20feb850c47d1176237027ef131f18c5cbb095f6ab8b3ec58cea9bce856
|
||||
lib/codeql/rust/elements/internal/MacroRulesImpl.qll 10c03adfb63ee7a4348ff5cffc6ef5300a531b048f28811a51e940b053e69f68 2498bd64aeaea9849c086abeaa6c248e4ce41b4436155f4bd4840965976d5d54
|
||||
lib/codeql/rust/elements/internal/MacroStmtsConstructor.qll c293815cd69c002ba6de1db6018672654420f3f8bdd143f9d0c620adddd2be02 d376f8f07661a8cad1b10039076fd7fca353dcacf3ca40ed6507b8c874e849ca
|
||||
lib/codeql/rust/elements/internal/MacroStmtsImpl.qll 27faff9da93ad7f22a6236c73ebb4d4631161cf4ec1b82958cdf79c85aa2087c 7e2863eaf50d4b285b9240f2c5ff9497cfb4393c8528a0738d725d00f1a78406
|
||||
lib/codeql/rust/elements/internal/MacroTypeConstructor.qll 0a23573a6f69b38f3d7470050b16197601d67bdd5a4b1a43a155b0b99ccdf6b5 19b623962e8e1f73e55e3ed9712d2a3fe84b9510b99062173902feb2458ec12a
|
||||
lib/codeql/rust/elements/internal/MacroTypeImpl.qll b8711279f09f521b05bb67568c089271b7913f863ee64dfdeec2c502de2cbdc8 51bd9d3a2fb2065bce7b193b485e225ca5c8ba2029e60cab427d43a90baf0880
|
||||
lib/codeql/rust/elements/internal/MatchArmConstructor.qll b41c1d5822d54127ce376ef62c6a5fa60e11697319fc7d9c9c54fd313d784a93 96cca80e5684e5893c0e9c0dff365ef8ad9e15ff648c9969ba42d91f95abea05
|
||||
@@ -308,7 +314,6 @@ lib/codeql/rust/elements/internal/NeverTypeImpl.qll 8c7464cb76f9d081dab318d74381
|
||||
lib/codeql/rust/elements/internal/OffsetOfExprConstructor.qll 616e146562adb3ac0fba4d6f55dd6ce60518ed377c0856f1f09ba49593e7bfab 80518ce90fc6d08011d6f5fc2a543958067739e1b0a6a5f2ed90fc9b1db078f0
|
||||
lib/codeql/rust/elements/internal/OffsetOfExprImpl.qll e52d4596068cc54719438121f7d5afcaab04e0c70168ac5e4df1a3a0969817a6 6ab37e659d79e02fb2685d6802ae124157bf14b6f790b31688f437c87f40f52c
|
||||
lib/codeql/rust/elements/internal/OrPatConstructor.qll 4ef583e07298487c0c4c6d7c76ffcc04b1e5fe58aba0c1da3e2c8446a9e0c92b 980a6bd176ae5e5b11c134569910c5468ba91f480982d846e222d031a6a05f1a
|
||||
lib/codeql/rust/elements/internal/OrPatImpl.qll 0dbc461115f62306e679f69c4354550bc3425d4291aec0124ad8f7a55c779d51 d32ebaa5a3002e87b35949cb624b20377155869ad33aec873326f60f2f0b666d
|
||||
lib/codeql/rust/elements/internal/ParamConstructor.qll b98a2d8969f289fdcc8c0fb11cbd19a3b0c71be038c4a74f5988295a2bae52f0 77d81b31064167945b79b19d9697b57ca24462c3a7cc19e462c4693ce87db532
|
||||
lib/codeql/rust/elements/internal/ParamImpl.qll 8a5101559f5d636b60ab80237057944b537823ce054d760c3dbd58b2acf05a46 e7a08cefeb6a290a975899045b7b19a9624f5a2b0946cba0866b1854cc0c0fb0
|
||||
lib/codeql/rust/elements/internal/ParamListConstructor.qll 3123142ab3cab46fb53d7f3eff6ba2d3ff7a45b78839a53dc1979a9c6a54920e 165f3d777ea257cfcf142cc4ba9a0ebcd1902eb99842b8a6657c87087f3df6fe
|
||||
@@ -515,11 +520,13 @@ lib/codeql/rust/elements/internal/generated/LiteralExpr.qll f3a564d0a3ed0d915f5a
|
||||
lib/codeql/rust/elements/internal/generated/LiteralPat.qll ecc2bfe559abfce1be873fbf7b61b5728897c9afc3bb3f69551d8320d273da71 42196fb6a4a0ff9b570fd0bdbc920f24744b3f46772efbb46648af7fbfe1fbda
|
||||
lib/codeql/rust/elements/internal/generated/Locatable.qll c897dc1bdd4dfcb6ded83a4a93332ca3d8f421bae02493ea2a0555023071775e b32d242f8c9480dc9b53c1e13a5cb8dcfce575b0373991c082c1db460a3e37b8
|
||||
lib/codeql/rust/elements/internal/generated/LoopExpr.qll 22b755dfaf238ecea722c0c94c399992014e23481ec6fdd61f803bbec012b6f9 08731630c2dc05aa1e0ada222a6057752d9ce737329c62076708828247a358be
|
||||
lib/codeql/rust/elements/internal/generated/MacroCall.qll 8b49d44e6aeac26dc2fc4b9ba03c482c65ebf0cba089d16f9d65e784e48ccbb0 9ecf6e278007adcbdc42ed1c10e7b1c0652b6c64738b780d256c9326afa3b393
|
||||
lib/codeql/rust/elements/internal/generated/MacroCall.qll fc8988696493992cc4fdce8c0e5610c54ee92ea52ebb05262338f8b612353f50 188a2d7a484bd402a521787371e64f6e00e928306c8d437e6b19bf890a7aa14e
|
||||
lib/codeql/rust/elements/internal/generated/MacroDef.qll e9b3f07ba41aa12a8e0bd6ec1437b26a6c363065ce134b6d059478e96c2273a6 87470dea99da1a6afb3a19565291f9382e851ba864b50a995ac6f29589efbd70
|
||||
lib/codeql/rust/elements/internal/generated/MacroExpr.qll 03a1daa41866f51e479ac20f51f8406d04e9946b24f3875e3cf75a6b172c3d35 1ae8ca0ee96bd2be32575d87c07cc999a6ff7770151b66c0e3406f9454153786
|
||||
lib/codeql/rust/elements/internal/generated/MacroItems.qll 894890f61e118b3727d03ca813ae7220a15e45195f2d1d059cb1bba6802128c8 db3854b347f8782a3ec9f9a1439da822727b66f0bd33727383184ab65dbf29ac
|
||||
lib/codeql/rust/elements/internal/generated/MacroPat.qll 9e927e09d47029a3025eaad271c975e73479a80ea933c921381b6c9d751f2866 bdf5c58ca27743eb2e2dae2aeea3f3fc21f8a4f98fe1001598876455c88e8f69
|
||||
lib/codeql/rust/elements/internal/generated/MacroRules.qll 4fbd94f22b5ee0f3e5aaae39c2b9a5e9b7bf878a1017811ca589942f6de92843 49fb69543ee867bae196febea6918e621f335afdf4d3ccbf219965b37c7537b1
|
||||
lib/codeql/rust/elements/internal/generated/MacroStmts.qll cb4f3c2721a4d0c8522e51f567c675f4fc95f39bac8a2bd97e125d5553515ad2 09b5a739ccee75e6c556b34ecd6f78c7dc799029d9bc7df2e6169098d24f0ccd
|
||||
lib/codeql/rust/elements/internal/generated/MacroType.qll c462824df4a002956c036966d15cd0bce206e664888f8d0c7834dedb38b3c0bf 947480f07c40128ef3d00ad4c3a29a685472b3e20a661680c22f6bb318205ed1
|
||||
lib/codeql/rust/elements/internal/generated/MatchArm.qll 8fb740a0f2e308782d9cf390672969cd7cf6e698e5b847fb02ae3fa6c205646f 42bfe8dd94fc24ec925fbd44016df111600f99d1216c9a698631373bb6048830
|
||||
lib/codeql/rust/elements/internal/generated/MatchArmList.qll 13362680c037fe83fef4653562cc10a4429078316b5ec7c47b076336cf4aca2e 41c674293c13eceaca62134ae0c6778541f6a5201cbc5c146f0ba01b898dc267
|
||||
@@ -539,7 +546,7 @@ lib/codeql/rust/elements/internal/generated/ParamList.qll c808c9d84dd7800573832b
|
||||
lib/codeql/rust/elements/internal/generated/ParenExpr.qll bc0731505bfe88516205ec360582a4222d2681d11342c93e15258590ddee82f2 d4bd6e0c80cf1d63746c88d4bcb3a01d4c75732e5da09e3ebd9437ced227fb60
|
||||
lib/codeql/rust/elements/internal/generated/ParenPat.qll ce24b8f8ecbf0f204af200317405724063887257460c80cf250c39b2fdf37185 e7c87d37e1a0ca7ea03840017e1aa9ddb7f927f1f3b6396c0305b46aeee33db6
|
||||
lib/codeql/rust/elements/internal/generated/ParenType.qll 9cc954d73f8330dcac7b475f97748b63af5c8766dee9d2f2872c0a7e4c903537 c07534c8a9c683c4a9b11d490095647e420de0a0bfc23273eaf6f31b00244273
|
||||
lib/codeql/rust/elements/internal/generated/ParentChild.qll 4af9df75abf8215aa746c9063368911ee94f84b91d71ccf8e6f3acdab02adc03 08855e899a703d5ed63d63db7749ab353367166987ac56ae10875d93975f934a
|
||||
lib/codeql/rust/elements/internal/generated/ParentChild.qll 823b35d9802fab617be5c76327d65a3e52abd4be72bbc36d93e673cea7a9baaf 9d58eb407d0a929aefc0f4d532ef39dded81f6a370b6735ef581709c82ff9bc6
|
||||
lib/codeql/rust/elements/internal/generated/Pat.qll 3605ac062be2f294ee73336e9669027b8b655f4ad55660e1eab35266275154ee 7f9400db2884d336dd1d21df2a8093759c2a110be9bf6482ce8e80ae0fd74ed4
|
||||
lib/codeql/rust/elements/internal/generated/Path.qll 299abce24762a5ab023f3cf1ab9718b83047e171aed42a8092e7a155914b1657 db1a23d18640c548f08c9f94823838b5e019ac85877c7b15df2d1493d1846572
|
||||
lib/codeql/rust/elements/internal/generated/PathExpr.qll 17cdb0a7393258a207450f08e37178fc9d35d167f064ba6015be94246f3dc933 a75fdd280aff6d87e083a92030e041c2eb52b57cf7151d4a6989fcd31d6a64bf
|
||||
@@ -551,7 +558,7 @@ lib/codeql/rust/elements/internal/generated/PtrType.qll 40099c5a4041314b66932dfd
|
||||
lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll dc03515d678ba052c2ff2dd9f0883e0bce54cac740ba9a15e5173f292c1b6971 dc03515d678ba052c2ff2dd9f0883e0bce54cac740ba9a15e5173f292c1b6971
|
||||
lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9
|
||||
lib/codeql/rust/elements/internal/generated/RangePat.qll efd93730de217cf50dcba5875595263a5eadf9f7e4e1272401342a094d158614 229b251b3d118932e31e78ac4dfb75f48b766f240f20d436062785606d44467b
|
||||
lib/codeql/rust/elements/internal/generated/Raw.qll ff4874c063c0338443293c807108ecdb878ff2a6a97932c2bafe1c5d2a5486ed 4db42119a06518aeb33bfe9156d884e046afff540c98f07fa81c22bb11c063ad
|
||||
lib/codeql/rust/elements/internal/generated/Raw.qll 429057964308876b8186a0ca901634273d91b783e4bb85aa5e47860010f4da0b feb8231d0b724fedb1d9d2a65d4a8759ae58baec902b44e3bebdb81a7fbc1fd1
|
||||
lib/codeql/rust/elements/internal/generated/RecordExpr.qll eb6cb662e463f9260efae1a6ce874fa781172063b916ef1963f861e9942d308d 1a21cbccc8f3799ff13281e822818ebfb21d81591720a427cac3625512cb9d40
|
||||
lib/codeql/rust/elements/internal/generated/RecordExprField.qll 7e9f8663d3b74ebbc9603b10c9912f082febba6bd73d344b100bbd3edf837802 fbe6b578e7fd5d5a6f21bbb8c388957ab7210a6a249ec71510a50fb35b319ea1
|
||||
lib/codeql/rust/elements/internal/generated/RecordExprFieldList.qll 179a97211fe7aa6265085d4d54115cdbc0e1cd7c9b2135591e8f36d6432f13d3 dd44bbbc1e83a1ed3a587afb729d7debf7aeb7b63245de181726af13090e50c0
|
||||
@@ -576,8 +583,8 @@ lib/codeql/rust/elements/internal/generated/Static.qll 5fbd6879858cf356d4bdaa6da
|
||||
lib/codeql/rust/elements/internal/generated/Stmt.qll 8473ff532dd5cc9d7decaddcd174b94d610f6ca0aec8e473cc051dad9f3db917 6ef7d2b5237c2dbdcacbf7d8b39109d4dc100229f2b28b5c9e3e4fbf673ba72b
|
||||
lib/codeql/rust/elements/internal/generated/StmtList.qll a667193e32341e17400867c6e359878c4e645ef9f5f4d97676afc0283a33a026 a320ed678ee359302e2fc1b70a9476705cd616fcfa44a499d32f0c7715627f73
|
||||
lib/codeql/rust/elements/internal/generated/Struct.qll 4d57f0db12dc7ad3e31e750a24172ef1505406b4dab16386af0674bd18bf8f4b 1a73c83df926b996f629316f74c61ea775be04532ab61b56af904223354f033e
|
||||
lib/codeql/rust/elements/internal/generated/Synth.qll 277fd5258498732937682a2b6982405b6cb515f4631a6e0dc6f1a2545ffa54cb 0d3db7534cf9c1c73fc5863b9048f8bca4fe69615e9cdba8f521c36f02155878
|
||||
lib/codeql/rust/elements/internal/generated/SynthConstructors.qll 518b68ccf6d0791bc0c141486261108bb1723e37743fc7f8e4167a1d61660531 518b68ccf6d0791bc0c141486261108bb1723e37743fc7f8e4167a1d61660531
|
||||
lib/codeql/rust/elements/internal/generated/Synth.qll dd9d72a46cf446af025cd7b0085f3780ee7bf7d09a458d3ae6f495e999d342c8 cda06e3155f1a3eecc5ee8ec8097d5362234b44f815aff9bc3940860435262b3
|
||||
lib/codeql/rust/elements/internal/generated/SynthConstructors.qll 5d30b6d4f36791637f250734ee38820102c64f196454e20f79e30097da1a8e20 5d30b6d4f36791637f250734ee38820102c64f196454e20f79e30097da1a8e20
|
||||
lib/codeql/rust/elements/internal/generated/Token.qll 77a91a25ca5669703cf3a4353b591cef4d72caa6b0b9db07bb9e005d69c848d1 2fdffc4882ed3a6ca9ac6d1fb5f1ac5a471ca703e2ffdc642885fa558d6e373b
|
||||
lib/codeql/rust/elements/internal/generated/TokenTree.qll 8577c2b097c1be2f0f7daa5acfcf146f78674a424d99563e08a84dd3e6d91b46 d2f30764e84dbfc0a6a5d3d8a5f935cd432413688cb32da9c94e420fbc10665c
|
||||
lib/codeql/rust/elements/internal/generated/Trait.qll a570fa93d0b78a35766b00d5ca256c102f824564248b9d8b678a981d6eea3e2e d9c7475e5102e21cfdee3b1791f89a4f9cdba5a4200349ff706532b704c02664
|
||||
@@ -611,7 +618,7 @@ lib/codeql/rust/elements/internal/generated/WhileExpr.qll fec8a9211b82a80601bf73
|
||||
lib/codeql/rust/elements/internal/generated/WildcardPat.qll d74b70b57a0a66bfae017a329352a5b27a6b9e73dd5521d627f680e810c6c59e 4b913b548ba27ff3c82fcd32cf996ff329cb57d176d3bebd0fcef394486ea499
|
||||
lib/codeql/rust/elements/internal/generated/YeetExpr.qll cac328200872a35337b4bcb15c851afb4743f82c080f9738d295571eb01d7392 94af734eea08129b587fed849b643e7572800e8330c0b57d727d41abda47930b
|
||||
lib/codeql/rust/elements/internal/generated/YieldExpr.qll 37e5f0c1e373a22bbc53d8b7f2c0e1f476e5be5080b8437c5e964f4e83fad79a 4a9a68643401637bf48e5c2b2f74a6bf0ddcb4ff76f6bffb61d436b685621e85
|
||||
lib/codeql/rust/elements.qll 0e469834ccc4b5db3d35d9521d98e3c8b1911f8c5cd70d35d4cd52cb81c73722 0e469834ccc4b5db3d35d9521d98e3c8b1911f8c5cd70d35d4cd52cb81c73722
|
||||
lib/codeql/rust/elements.qll ef8063c90411cb957c776756837a4c7ad43aa4eeb52595786e8b2b96dc10ebff ef8063c90411cb957c776756837a4c7ad43aa4eeb52595786e8b2b96dc10ebff
|
||||
test/extractor-tests/generated/Abi/Abi.ql 7f6e7dc4af86eca3ebdc79b10373988cd0871bd78b51997d3cffd969105e5fdd 2f936b6ca005c6157c755121584410c03e4a3949c23bee302fbe05ee10ce118f
|
||||
test/extractor-tests/generated/Abi/Abi_getAbiString.ql a496762fcec5a0887b87023bbf93e9b650f02e20113e25c44d6e4281ae8f5335 14109c7ce11ba25e3cd6e7f1b3fcb4cb00622f2a4eac91bfe43145c5f366bc52
|
||||
test/extractor-tests/generated/ArgList/ArgList.ql e412927756e72165d0e7c5c9bd3fca89d08197bbf760db8fb7683c64bb2229bc 043dba8506946fbb87753e22c387987d7eded6ddb963aa067f9e60ef9024d684
|
||||
@@ -814,8 +821,9 @@ test/extractor-tests/generated/LoopExpr/LoopExpr.ql 636c28bff5f8c1ca0fb834f614b3
|
||||
test/extractor-tests/generated/LoopExpr/LoopExpr_getAttr.ql d557c1a34ae8762b32702d6b50e79c25bc506275c33a896b6b94bbbe73d04c49 34846c9eefa0219f4a16e28b518b2afa23f372d0aa03b08d042c5a35375e0cd6
|
||||
test/extractor-tests/generated/LoopExpr/LoopExpr_getLabel.ql 0b77b9d9fb5903d37bce5a2c0d6b276e6269da56fcb37b83cd931872fb88490f c7f09c526e59dcadec13ec9719980d68b8619d630caab2c26b8368b06c1f2cc0
|
||||
test/extractor-tests/generated/LoopExpr/LoopExpr_getLoopBody.ql 0267f54077640f3dfeb38524577e4a1229115eeb1c839398d0c5f460c1d65129 96ec876635b8c561f7add19e57574444f630eae3df9ab9bc33ac180e61f3a7b8
|
||||
test/extractor-tests/generated/MacroCall/MacroCall.ql d8b71880ffbfa0f9efa56c598a9bdd3f91e85129e0f8f2b30be6862556f87fcd 682736663ad11f9fdde165904324a8b2f3cdc59f91196a1accb1cd4cf5fb70d4
|
||||
test/extractor-tests/generated/MacroCall/MacroCall.ql 9eca338d7bc42dcfc3cfcd7953484d724d4f06b1182c01a426925d9963820e37 25fe9e90c38d3bd0c92c70bf2af01b034e3c375f3dbd1c1b8aab1fc1aae09547
|
||||
test/extractor-tests/generated/MacroCall/MacroCall_getAttr.ql c22a2a29d705e85b03a6586d1eda1a2f4f99f95f7dfeb4e6908ec3188b5ad0ad 9b8d9dcc2116a123c15c520a880efab73ade20e08197c64bc3ed0c50902c4672
|
||||
test/extractor-tests/generated/MacroCall/MacroCall_getExpanded.ql 757c4a4c32888e4604044c798a3180aa6d4f73381eec9bc28ba9dc71ffcbd03a 27d5edaa2c1096a24c86744aaad0f006da20d5caa28ccfd8528e7c98aa1bead1
|
||||
test/extractor-tests/generated/MacroCall/MacroCall_getPath.ql 160edc6a001a2d946da6049ffb21a84b9a3756e85f9a2fb0a4d85058124b399a 1e25dd600f19ef89a99f328f86603bce12190220168387c5a88bfb9926da56d9
|
||||
test/extractor-tests/generated/MacroCall/MacroCall_getTokenTree.ql 1cbf6b1ac7fa0910ff299b939743153fc00ad7e28a9a70c69a8297c6841e8238 570380c0dc4b20fe25c0499378569720a6da14bdb058e73d757e174bdd62d0c0
|
||||
test/extractor-tests/generated/MacroDef/MacroDef.ql dde2df9196800d9af9645fe21786e30245bff6cfa58117900582ce1f5c0b859d 6b87bec4e4df8e9b6ed09f18e7b7c20204c39c8d249494cc66d3a06ae39791e4
|
||||
@@ -826,6 +834,8 @@ test/extractor-tests/generated/MacroDef/MacroDef_getName.ql 6bc8a17804f23782e98f
|
||||
test/extractor-tests/generated/MacroDef/MacroDef_getVisibility.ql d858ccaab381432c529bf4a621afc82ea5e4b810b463f2b1f551de79908e14e7 83a85c4f90417ab44570a862642d8f8fc9208e62ba20ca69b32d39a3190381aa
|
||||
test/extractor-tests/generated/MacroExpr/MacroExpr.ql 69445cf24f5bec5c3f11f0ebf13604891bb2c0dffe715612628e5572587c7a6c 5434db79d94e437c86126d9cf20bf1e86e5537f462a57b9bf6b22a2caa95cc40
|
||||
test/extractor-tests/generated/MacroExpr/MacroExpr_getMacroCall.ql 8859743e23b987225a6a1933054a1ed8f5f1442b61a769599e2efd143f4feb9e d2d336135ff4d2ea65e79430dee8d0f69f9d7818a674f5446903d986f3948b92
|
||||
test/extractor-tests/generated/MacroItems/MacroItems.ql 876b5d2a4ce7dcb599e022083ff3f2d57300bcb0ea05f61069d59ad58353ca69 61ea54d4633ef871d3e634069e39fbb2545f7dc2796fa66f8edbacd4e0aa4ef5
|
||||
test/extractor-tests/generated/MacroItems/MacroItems_getItem.ql 53fc2db35a23b9aca6ee327d2a51202d23ddf482e6bdd92c5399b7f3a73959b1 63051c8b7a7bfbe9cc640f775e753c9a82f1eb8472989f7d3c8af94fdf26c7a0
|
||||
test/extractor-tests/generated/MacroPat/MacroPat.ql d9ec72d4d6a7342ee2d9aa7e90227faa31792ca5842fe948d7fdf22597a123b7 74b0f21ef2bb6c13aae74dba1eea97451755110909a083360e2c56cfbc76fd91
|
||||
test/extractor-tests/generated/MacroPat/MacroPat_getMacroCall.ql 398996f0d0f2aa6d3b58d80b26c7d1185b5094d455c6c5c7f075f6d414150aa6 b4662e57cac36ed0e692201f53ba46c3d0826bba99c5cc6dfcb302b44dd2154b
|
||||
test/extractor-tests/generated/MacroRules/MacroRules.ql 0742faf18179fa34e0f43361e9e4b807bfc242d232f6b3664a35e138a47d39c5 10e1cf45f32a27cb46bd61f5dd45416e2c0c9f25e880f6d213597a7d96e19103
|
||||
@@ -833,6 +843,9 @@ test/extractor-tests/generated/MacroRules/MacroRules_getAttr.ql 7de501c724e34655
|
||||
test/extractor-tests/generated/MacroRules/MacroRules_getName.ql 591606e3accae8b8fb49e1218c4867a42724ac209cf99786db0e5d7ea0bf55d5 d2936ef5aa4bbf024372516dde3de578990aafb2b8675bbbf0f72e8b54eb82a8
|
||||
test/extractor-tests/generated/MacroRules/MacroRules_getTokenTree.ql 7598d33c3d86f9ad8629219b90667b2b65e3a1e18c6b0887291df9455a319cab 69d90446743e78e851145683c17677497fe42ed02f61f2b2974e216dc6e05b01
|
||||
test/extractor-tests/generated/MacroRules/MacroRules_getVisibility.ql 5306cc85f470d21ebcbe6e98436334b0bf5ba819a0ae186569ba7e88c31636c6 fcbf5c54e5a904767a6f4d37d853072aa0040738e622c49c9a02dec8739d6587
|
||||
test/extractor-tests/generated/MacroStmts/MacroStmts.ql 991042263ba99acef0972697ce79132e5650b27bf53be2f975a0da1f29940fd8 64c44e65b3c5d3de5f9532b4ff7ce54b39442b37f63da8b10d789b9b52b85a9e
|
||||
test/extractor-tests/generated/MacroStmts/MacroStmts_getExpr.ql 5717f20376600e7bf5e471beae1a7c0084f235f0931f8b3f25d2de94ebb86f8b e4685fd9d45b078a6402c285eed3a15cc4550f6656c8bc5e7e274a88d1c7e9b3
|
||||
test/extractor-tests/generated/MacroStmts/MacroStmts_getStatement.ql 8958b2212776f487869c29314e7d28f5871f5c3dde62fd9d6f87fb9e94204498 6804f5d4c0c5909689bdcdd5b8ec11ca7a8c0399b47695f66d2f99e39561565a
|
||||
test/extractor-tests/generated/MacroType/MacroType.ql 408327fdb4d7cf096536457401cc280f83cd7e4f6fa9aebd65e64031f6c119cf 0c502d25194ab96eb068a85e3f57a9217510a951fa923e9d7a20fd75412bd6da
|
||||
test/extractor-tests/generated/MacroType/MacroType_getMacroCall.ql 565be7a72670218d7999d3f6cec4e704b754c217186243f1b24c334589fa82e2 ba413c712783320188800e2a78738b09c40fe9a6305c08d9e67e971a8fca96ee
|
||||
test/extractor-tests/generated/MatchArm/MatchArm.ql 512aa404c94ba40b859564f07e9dffe6a5e687fafb039556e9145f4f3742981c 529f96e38cede8a26054f8981d4ba1d189c17d14d0f92d622eb20acd8f3d7e5d
|
||||
|
||||
15
rust/ql/.gitattributes
generated
vendored
15
rust/ql/.gitattributes
generated
vendored
@@ -71,8 +71,10 @@
|
||||
/lib/codeql/rust/elements/MacroCall.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MacroDef.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MacroExpr.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MacroItems.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MacroPat.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MacroRules.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MacroStmts.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MacroType.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MatchArm.qll linguist-generated
|
||||
/lib/codeql/rust/elements/MatchArmList.qll linguist-generated
|
||||
@@ -280,10 +282,14 @@
|
||||
/lib/codeql/rust/elements/internal/MacroDefImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroExprConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroExprImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroItemsConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroItemsImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroPatConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroPatImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroRulesConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroRulesImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroStmtsConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroStmtsImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroTypeConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MacroTypeImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/MatchArmConstructor.qll linguist-generated
|
||||
@@ -310,7 +316,6 @@
|
||||
/lib/codeql/rust/elements/internal/OffsetOfExprConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/OffsetOfExprImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/OrPatConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/OrPatImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamListConstructor.qll linguist-generated
|
||||
@@ -520,8 +525,10 @@
|
||||
/lib/codeql/rust/elements/internal/generated/MacroCall.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MacroDef.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MacroExpr.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MacroItems.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MacroPat.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MacroRules.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MacroStmts.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MacroType.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MatchArm.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/MatchArmList.qll linguist-generated
|
||||
@@ -818,6 +825,7 @@
|
||||
/test/extractor-tests/generated/LoopExpr/LoopExpr_getLoopBody.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroCall/MacroCall.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroCall/MacroCall_getAttr.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroCall/MacroCall_getExpanded.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroCall/MacroCall_getPath.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroCall/MacroCall_getTokenTree.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroDef/MacroDef.ql linguist-generated
|
||||
@@ -828,6 +836,8 @@
|
||||
/test/extractor-tests/generated/MacroDef/MacroDef_getVisibility.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroExpr/MacroExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroExpr/MacroExpr_getMacroCall.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroItems/MacroItems.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroItems/MacroItems_getItem.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroPat/MacroPat.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroPat/MacroPat_getMacroCall.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroRules/MacroRules.ql linguist-generated
|
||||
@@ -835,6 +845,9 @@
|
||||
/test/extractor-tests/generated/MacroRules/MacroRules_getName.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroRules/MacroRules_getTokenTree.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroRules/MacroRules_getVisibility.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroStmts/MacroStmts.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroStmts/MacroStmts_getExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroStmts/MacroStmts_getStatement.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroType/MacroType.ql linguist-generated
|
||||
/test/extractor-tests/generated/MacroType/MacroType_getMacroCall.ql linguist-generated
|
||||
/test/extractor-tests/generated/MatchArm/MatchArm.ql linguist-generated
|
||||
|
||||
19
rust/ql/consistency-queries/SsaConsistency.ql
Normal file
19
rust/ql/consistency-queries/SsaConsistency.ql
Normal file
@@ -0,0 +1,19 @@
|
||||
import codeql.rust.dataflow.Ssa
|
||||
import codeql.rust.dataflow.internal.SsaImpl
|
||||
import Consistency
|
||||
|
||||
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
class MyRelevantDefinitionExt extends RelevantDefinitionExt, DefinitionExt {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,13 @@ class SimpleCompletion extends NormalCompletion, TSimpleCompletion {
|
||||
|
||||
// `SimpleCompletion` is the "default" completion type, thus it is valid for
|
||||
// any node where there isn't another more specific completion type.
|
||||
override predicate isValidFor(AstNode e) { not any(Completion c).isValidForSpecific(e) }
|
||||
override predicate isValidFor(AstNode e) {
|
||||
not any(Completion c).isValidForSpecific(e)
|
||||
or
|
||||
// A `?` expression can both proceed normally or cause an early return, so
|
||||
// we explicitly allow the former here.
|
||||
e instanceof TryExpr
|
||||
}
|
||||
|
||||
override string toString() { result = "simple" }
|
||||
}
|
||||
@@ -62,7 +68,7 @@ abstract class ConditionalCompletion extends NormalCompletion {
|
||||
abstract ConditionalCompletion getDual();
|
||||
}
|
||||
|
||||
/** Holds if node `le` has the Boolean constant value `value`. */
|
||||
/** Holds if node `le` has the constant Boolean value `value`. */
|
||||
private predicate isBooleanConstant(LiteralExpr le, Boolean value) {
|
||||
le.getTextValue() = value.toString()
|
||||
}
|
||||
@@ -117,13 +123,61 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion {
|
||||
override string toString() { result = "boolean(" + value + ")" }
|
||||
}
|
||||
|
||||
/** Holds if `pat` is guaranteed to match at the point in the AST where it occurs. */
|
||||
pragma[nomagic]
|
||||
private predicate isExhaustiveMatch(Pat pat) {
|
||||
(
|
||||
pat instanceof WildcardPat
|
||||
or
|
||||
pat = any(IdentPat ip | not ip.hasPat() and ip = any(Variable v).getPat())
|
||||
or
|
||||
pat instanceof RestPat
|
||||
or
|
||||
// `let` statements without an `else` branch must be exhaustive
|
||||
pat = any(LetStmt let | not let.hasLetElse()).getPat()
|
||||
or
|
||||
// `match` expressions must be exhaustive, so last arm cannot fail
|
||||
pat = any(MatchExpr me).getLastArm().getPat()
|
||||
or
|
||||
// macro invocations are exhaustive if their expansion is
|
||||
pat = any(MacroPat mp | isExhaustiveMatch(mp.getMacroCall().getExpanded()))
|
||||
or
|
||||
// parameter patterns must be exhaustive
|
||||
pat = any(Param p).getPat()
|
||||
) and
|
||||
not pat = any(ForExpr for).getPat() // workaround until `for` loops are desugared
|
||||
or
|
||||
exists(Pat parent | isExhaustiveMatch(parent) |
|
||||
pat = parent.(BoxPat).getPat()
|
||||
or
|
||||
pat = parent.(IdentPat).getPat()
|
||||
or
|
||||
pat = parent.(MacroPat).getMacroCall().getExpanded()
|
||||
or
|
||||
pat = parent.(ParenPat).getPat()
|
||||
or
|
||||
pat = parent.(RecordPat).getRecordPatFieldList().getField(_).getPat()
|
||||
or
|
||||
pat = parent.(RefPat).getPat()
|
||||
or
|
||||
pat = parent.(TuplePat).getAField()
|
||||
or
|
||||
pat = parent.(TupleStructPat).getAField()
|
||||
or
|
||||
pat = parent.(OrPat).getLastPat()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents the result of a pattern match.
|
||||
*/
|
||||
class MatchCompletion extends TMatchCompletion, ConditionalCompletion {
|
||||
MatchCompletion() { this = TMatchCompletion(value) }
|
||||
|
||||
override predicate isValidForSpecific(AstNode e) { e instanceof Pat }
|
||||
override predicate isValidForSpecific(AstNode e) {
|
||||
e instanceof Pat and
|
||||
if isExhaustiveMatch(e) then value = true else any()
|
||||
}
|
||||
|
||||
override MatchSuccessor getAMatchingSuccessorType() { result.getValue() = value }
|
||||
|
||||
@@ -161,7 +215,9 @@ class ContinueCompletion extends TContinueCompletion, Completion {
|
||||
class ReturnCompletion extends TReturnCompletion, Completion {
|
||||
override ReturnSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override predicate isValidForSpecific(AstNode e) { e instanceof ReturnExpr }
|
||||
override predicate isValidForSpecific(AstNode e) {
|
||||
e instanceof ReturnExpr or e instanceof TryExpr
|
||||
}
|
||||
|
||||
override string toString() { result = "return" }
|
||||
}
|
||||
|
||||
@@ -65,9 +65,6 @@ private module CfgImpl =
|
||||
|
||||
import CfgImpl
|
||||
|
||||
/** Holds if `p` is a trivial pattern that is always guaranteed to match. */
|
||||
predicate trivialPat(Pat p) { p instanceof WildcardPat or p instanceof IdentPat }
|
||||
|
||||
class ArrayExprTree extends StandardPostOrderTree, ArrayExpr {
|
||||
override AstNode getChildNode(int i) { result = this.getExpr(i) }
|
||||
}
|
||||
@@ -141,11 +138,10 @@ class LogicalAndTree extends PostOrderTree, LogicalAndExpr {
|
||||
|
||||
class BlockExprTree extends StandardPostOrderTree, BlockExpr {
|
||||
override AstNode getChildNode(int i) {
|
||||
result = super.getStmtList().getStatement(i)
|
||||
result = this.getStmtList().getStatement(i)
|
||||
or
|
||||
not exists(super.getStmtList().getStatement(i)) and
|
||||
(exists(super.getStmtList().getStatement(i - 1)) or i = 0) and
|
||||
result = super.getStmtList().getTailExpr()
|
||||
i = this.getStmtList().getNumberOfStatements() and
|
||||
result = this.getStmtList().getTailExpr()
|
||||
}
|
||||
|
||||
override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) }
|
||||
@@ -183,7 +179,23 @@ class CastExprTree extends StandardPostOrderTree instanceof CastExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
|
||||
}
|
||||
|
||||
class ClosureExprTree extends LeafTree instanceof ClosureExpr { }
|
||||
class ClosureExprTree extends StandardTree, ClosureExpr {
|
||||
override predicate first(AstNode first) { first = this }
|
||||
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
last = this and
|
||||
completionIsValidFor(c, this)
|
||||
}
|
||||
|
||||
override predicate propagatesAbnormal(AstNode child) { none() }
|
||||
|
||||
override AstNode getChildNode(int i) {
|
||||
result = this.getParamList().getParam(i)
|
||||
or
|
||||
i = this.getParamList().getNumberOfParams() and
|
||||
result = this.getBody()
|
||||
}
|
||||
}
|
||||
|
||||
class ContinueExprTree extends LeafTree, ContinueExpr {
|
||||
override predicate last(AstNode last, Completion c) { none() }
|
||||
@@ -203,7 +215,27 @@ class FieldExprTree extends StandardPostOrderTree instanceof FieldExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
|
||||
}
|
||||
|
||||
class FunctionTree extends LeafTree instanceof Function { }
|
||||
class FunctionTree extends StandardTree, Function {
|
||||
override predicate first(AstNode first) { first = this }
|
||||
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
last = this and
|
||||
completionIsValidFor(c, this)
|
||||
}
|
||||
|
||||
override predicate propagatesAbnormal(AstNode child) { none() }
|
||||
|
||||
override AstNode getChildNode(int i) {
|
||||
result = this.getParamList().getParam(i)
|
||||
or
|
||||
i = this.getParamList().getNumberOfParams() and
|
||||
result = this.getBody()
|
||||
}
|
||||
}
|
||||
|
||||
class ParamTree extends StandardPostOrderTree, Param {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = this.getPat() }
|
||||
}
|
||||
|
||||
class IfExprTree extends PostOrderTree instanceof IfExpr {
|
||||
override predicate first(AstNode node) { first(super.getCondition(), node) }
|
||||
@@ -241,6 +273,14 @@ class IfExprTree extends PostOrderTree instanceof IfExpr {
|
||||
}
|
||||
}
|
||||
|
||||
class FormatArgsExprTree extends StandardPostOrderTree, FormatArgsExpr {
|
||||
override AstNode getChildNode(int i) {
|
||||
i = -1 and result = this.getTemplate()
|
||||
or
|
||||
result = this.getArg(i).getExpr()
|
||||
}
|
||||
}
|
||||
|
||||
class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr {
|
||||
override AstNode getChildNode(int i) {
|
||||
i = 0 and result = super.getBase()
|
||||
@@ -249,53 +289,53 @@ class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr {
|
||||
}
|
||||
}
|
||||
|
||||
class ItemTree extends LeafTree, Item { }
|
||||
class ItemTree extends LeafTree, Item {
|
||||
ItemTree() {
|
||||
not this instanceof MacroCall and
|
||||
this = [any(StmtList s).getAStatement(), any(MacroStmts s).getAStatement()]
|
||||
}
|
||||
}
|
||||
|
||||
// `LetExpr` is a pre-order tree such that the pattern itself ends up
|
||||
// dominating successors in the graph in the same way that patterns do in
|
||||
// `match` expressions.
|
||||
class LetExprTree extends StandardPreOrderTree instanceof LetExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getPat() }
|
||||
}
|
||||
|
||||
// We handle `let` statements with trivial patterns separately as they don't
|
||||
// lead to non-standard control flow. For instance, in `let a = ...` it is not
|
||||
// interesing to create match edges as it would carry no information.
|
||||
class LetStmtTreeTrivialPat extends StandardPreOrderTree instanceof LetStmt {
|
||||
LetStmtTreeTrivialPat() { trivialPat(super.getPat()) }
|
||||
|
||||
class LetExprTree extends StandardPreOrderTree, LetExpr {
|
||||
override AstNode getChildNode(int i) {
|
||||
i = 0 and result = super.getInitializer()
|
||||
i = 0 and
|
||||
result = this.getExpr()
|
||||
or
|
||||
i = 1 and result = super.getPat()
|
||||
i = 1 and
|
||||
result = this.getPat()
|
||||
}
|
||||
}
|
||||
|
||||
// `let` statements with interesting patterns that we want to be reflected in
|
||||
// the CFG.
|
||||
class LetStmtTree extends PreOrderTree instanceof LetStmt {
|
||||
LetStmtTree() { not trivialPat(super.getPat()) }
|
||||
|
||||
class LetStmtTree extends PreOrderTree, LetStmt {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = [super.getInitializer(), super.getLetElse().getBlockExpr()]
|
||||
child = [this.getInitializer(), this.getLetElse().getBlockExpr()]
|
||||
}
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Edge to start of initializer.
|
||||
pred = this and first(super.getInitializer(), succ) and completionIsSimple(c)
|
||||
pred = this and first(this.getInitializer(), succ) and completionIsSimple(c)
|
||||
or
|
||||
// Edge to pattern when there is no initializer.
|
||||
pred = this and
|
||||
first(this.getPat(), succ) and
|
||||
completionIsSimple(c) and
|
||||
not this.hasInitializer()
|
||||
or
|
||||
// Edge from end of initializer to pattern.
|
||||
last(super.getInitializer(), pred, c) and first(super.getPat(), succ)
|
||||
last(this.getInitializer(), pred, c) and first(this.getPat(), succ)
|
||||
or
|
||||
// Edge from failed pattern to `else` branch.
|
||||
last(super.getPat(), pred, c) and
|
||||
first(super.getLetElse().getBlockExpr(), succ) and
|
||||
last(this.getPat(), pred, c) and
|
||||
first(this.getLetElse().getBlockExpr(), succ) and
|
||||
c.(MatchCompletion).failed()
|
||||
}
|
||||
|
||||
override predicate last(AstNode node, Completion c) {
|
||||
// Edge out of a successfully matched pattern.
|
||||
last(super.getPat(), node, c) and c.(MatchCompletion).succeeded()
|
||||
last(this.getPat(), node, c) and c.(MatchCompletion).succeeded()
|
||||
// NOTE: No edge out of the `else` branch as that is guaranteed to diverge.
|
||||
}
|
||||
}
|
||||
@@ -391,36 +431,66 @@ class ForExprTree extends LoopingExprTree instanceof ForExpr {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: replace with expanded macro once the extractor supports it
|
||||
class MacroExprTree extends LeafTree, MacroExpr { }
|
||||
class MacroCallTree extends ControlFlowTree, MacroCall {
|
||||
override predicate first(AstNode first) {
|
||||
first(this.getExpanded(), first)
|
||||
or
|
||||
not exists(this.getExpanded()) and first = this
|
||||
}
|
||||
|
||||
class MatchArmTree extends ControlFlowTree instanceof MatchArm {
|
||||
override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() }
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
last(this.getExpanded(), last, c)
|
||||
or
|
||||
not exists(this.getExpanded()) and
|
||||
last = this and
|
||||
completionIsValidFor(c, last)
|
||||
}
|
||||
|
||||
override predicate first(AstNode node) { node = super.getPat() }
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
|
||||
|
||||
override predicate propagatesAbnormal(AstNode child) { child = this.getExpanded() }
|
||||
}
|
||||
|
||||
class MacroExprTree extends StandardPostOrderTree, MacroExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = this.getMacroCall() }
|
||||
}
|
||||
|
||||
class MacroStmtsTree extends StandardPreOrderTree, MacroStmts {
|
||||
override AstNode getChildNode(int i) {
|
||||
result = this.getStatement(i)
|
||||
or
|
||||
i = this.getNumberOfStatements() and
|
||||
result = this.getExpr()
|
||||
}
|
||||
}
|
||||
|
||||
class MatchArmTree extends ControlFlowTree, MatchArm {
|
||||
override predicate propagatesAbnormal(AstNode child) { child = this.getExpr() }
|
||||
|
||||
override predicate first(AstNode node) { first(this.getPat(), node) }
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Edge from pattern to guard/arm if match succeeds.
|
||||
pred = super.getPat() and
|
||||
last(this.getPat(), pred, c) and
|
||||
c.(MatchCompletion).succeeded() and
|
||||
(
|
||||
first(super.getGuard().getCondition(), succ)
|
||||
first(this.getGuard().getCondition(), succ)
|
||||
or
|
||||
not super.hasGuard() and first(super.getExpr(), succ)
|
||||
not this.hasGuard() and first(this.getExpr(), succ)
|
||||
)
|
||||
or
|
||||
// Edge from guard to arm if the guard succeeds.
|
||||
last(super.getGuard().getCondition(), pred, c) and
|
||||
first(super.getExpr(), succ) and
|
||||
last(this.getGuard().getCondition(), pred, c) and
|
||||
first(this.getExpr(), succ) and
|
||||
c.(BooleanCompletion).succeeded()
|
||||
}
|
||||
|
||||
override predicate last(AstNode node, Completion c) {
|
||||
node = super.getPat() and c.(MatchCompletion).failed()
|
||||
last(this.getPat(), node, c) and c.(MatchCompletion).failed()
|
||||
or
|
||||
last(super.getGuard().getCondition(), node, c) and c.(BooleanCompletion).failed()
|
||||
last(this.getGuard().getCondition(), node, c) and c.(BooleanCompletion).failed()
|
||||
or
|
||||
last(super.getExpr(), node, c)
|
||||
last(this.getExpr(), node, c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +503,9 @@ class MatchExprTree extends PostOrderTree instanceof MatchExpr {
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Edge from the scrutinee to the first arm.
|
||||
last(super.getExpr(), pred, c) and succ = super.getArm(0).getPat()
|
||||
last(super.getExpr(), pred, c) and
|
||||
first(super.getArm(0).getPat(), succ) and
|
||||
completionIsNormal(c)
|
||||
or
|
||||
// Edge from a failed match/guard in one arm to the beginning of the next arm.
|
||||
exists(int i |
|
||||
@@ -447,10 +519,12 @@ class MatchExprTree extends PostOrderTree instanceof MatchExpr {
|
||||
}
|
||||
}
|
||||
|
||||
class MethodCallExprTree extends StandardPostOrderTree instanceof MethodCallExpr {
|
||||
class MethodCallExprTree extends StandardPostOrderTree, MethodCallExpr {
|
||||
override AstNode getChildNode(int i) {
|
||||
result = super.getReceiver() and
|
||||
result = super.getArgList().getArg(i + 1)
|
||||
i = 0 and
|
||||
result = this.getReceiver()
|
||||
or
|
||||
result = this.getArgList().getArg(i + 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,9 +548,6 @@ class ParenExprTree extends ControlFlowTree, ParenExpr {
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
|
||||
}
|
||||
|
||||
// This covers all patterns as they all extend `Pat`
|
||||
class PatExprTree extends LeafTree instanceof Pat { }
|
||||
|
||||
class PathExprTree extends LeafTree instanceof PathExpr { }
|
||||
|
||||
class PrefixExprTree extends StandardPostOrderTree instanceof PrefixExpr {
|
||||
@@ -501,18 +572,12 @@ class RefExprTree extends StandardPostOrderTree instanceof RefExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
|
||||
}
|
||||
|
||||
class ReturnExprTree extends PostOrderTree instanceof ReturnExpr {
|
||||
override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() }
|
||||
class ReturnExprTree extends StandardPostOrderTree instanceof ReturnExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
|
||||
}
|
||||
|
||||
override predicate first(AstNode node) {
|
||||
first(super.getExpr(), node)
|
||||
or
|
||||
not super.hasExpr() and node = this
|
||||
}
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
last(super.getExpr(), pred, c) and succ = this and completionIsNormal(c)
|
||||
}
|
||||
class TryExprTree extends StandardPostOrderTree instanceof TryExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
|
||||
}
|
||||
|
||||
class TupleExprTree extends StandardPostOrderTree instanceof TupleExpr {
|
||||
@@ -532,3 +597,166 @@ class YieldExprTree extends StandardPostOrderTree instanceof YieldExpr {
|
||||
class YeetExprTree extends StandardPostOrderTree instanceof YeetExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides `ControlFlowTree`s for patterns.
|
||||
*
|
||||
* Since patterns destruct values, they are modeled in pre-order, except for
|
||||
* `OrPat`s and `IdentPat`s.
|
||||
*/
|
||||
module PatternTrees {
|
||||
abstract class PreOrderPatTree extends PreOrderTree {
|
||||
abstract Pat getPat(int i);
|
||||
|
||||
private Pat getPatRanked(int i) {
|
||||
result = rank[i + 1](Pat pat, int j | pat = this.getPat(j) | pat order by j)
|
||||
}
|
||||
|
||||
override predicate propagatesAbnormal(AstNode child) { child = this.getPatRanked(_) }
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
completionIsValidFor(c, this) and
|
||||
c.(MatchCompletion).succeeded() and
|
||||
first(this.getPatRanked(0), succ)
|
||||
or
|
||||
exists(int i | last(this.getPatRanked(i), pred, c) |
|
||||
// Edge from successful pattern to the next
|
||||
c.(MatchCompletion).succeeded() and
|
||||
first(this.getPatRanked(i + 1), succ)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate last(AstNode node, Completion c) {
|
||||
node = this and
|
||||
completionIsValidFor(c, this) and
|
||||
c.(MatchCompletion).failed()
|
||||
or
|
||||
exists(int i | last(this.getPatRanked(i), node, c) |
|
||||
c.(MatchCompletion).failed()
|
||||
or
|
||||
not exists(this.getPatRanked(i + 1)) and
|
||||
completionIsNormal(c)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PostOrderPatTree extends PostOrderTree {
|
||||
abstract Pat getPat(int i);
|
||||
|
||||
private Pat getPatRanked(int i) {
|
||||
result = rank[i + 1](Pat pat, int j | pat = this.getPat(j) | pat order by j)
|
||||
}
|
||||
|
||||
override predicate propagatesAbnormal(AstNode child) { child = this.getPatRanked(_) }
|
||||
|
||||
override predicate first(AstNode node) {
|
||||
first(this.getPat(0), node)
|
||||
or
|
||||
not exists(this.getPat(_)) and
|
||||
node = this
|
||||
}
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
exists(int i | last(this.getPat(i), pred, c) |
|
||||
// Edge from unsuccessful pattern to the next
|
||||
c.(MatchCompletion).failed() and
|
||||
first(this.getPat(i + 1), succ)
|
||||
or
|
||||
// Edge from successful pattern to this
|
||||
c.(MatchCompletion).succeeded() and
|
||||
succ = this
|
||||
or
|
||||
// Edge from last pattern to this
|
||||
not exists(this.getPat(i + 1)) and
|
||||
succ = this and
|
||||
completionIsNormal(c)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class IdentPatTree extends PostOrderPatTree, IdentPat {
|
||||
override Pat getPat(int i) { i = 0 and result = this.getPat() }
|
||||
|
||||
override predicate last(AstNode node, Completion c) {
|
||||
super.last(node, c)
|
||||
or
|
||||
last(this.getPat(), node, c) and
|
||||
c.(MatchCompletion).failed()
|
||||
}
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
super.succ(pred, succ, c) and
|
||||
not (succ = this and c.(MatchCompletion).failed())
|
||||
}
|
||||
}
|
||||
|
||||
class BoxPatTree extends PreOrderPatTree, BoxPat {
|
||||
override Pat getPat(int i) { i = 0 and result = this.getPat() }
|
||||
}
|
||||
|
||||
class RestPatTree extends LeafTree, RestPat { }
|
||||
|
||||
class LiteralPatTree extends LeafTree, LiteralPat { }
|
||||
|
||||
class MacroPatTree extends PreOrderPatTree, MacroPat {
|
||||
override Pat getPat(int i) { i = 0 and result = this.getMacroCall().getExpanded() }
|
||||
}
|
||||
|
||||
class OrPatTree extends PostOrderPatTree instanceof OrPat {
|
||||
override Pat getPat(int i) { result = OrPat.super.getPat(i) }
|
||||
}
|
||||
|
||||
class ParenPatTree extends ControlFlowTree, ParenPat {
|
||||
private ControlFlowTree pat;
|
||||
|
||||
ParenPatTree() { pat = this.getPat() }
|
||||
|
||||
override predicate propagatesAbnormal(AstNode child) { pat.propagatesAbnormal(child) }
|
||||
|
||||
override predicate first(AstNode first) { pat.first(first) }
|
||||
|
||||
override predicate last(AstNode last, Completion c) { pat.last(last, c) }
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
|
||||
}
|
||||
|
||||
class PathPatTree extends LeafTree, PathPat { }
|
||||
|
||||
class WildcardPatTree extends LeafTree, WildcardPat { }
|
||||
|
||||
class RangePatTree extends PreOrderPatTree, RangePat {
|
||||
override Pat getPat(int i) {
|
||||
i = 0 and result = this.getStart()
|
||||
or
|
||||
i = 1 and result = this.getEnd()
|
||||
}
|
||||
}
|
||||
|
||||
class RecordPatTree extends PreOrderPatTree, RecordPat {
|
||||
override Pat getPat(int i) {
|
||||
result = this.getRecordPatFieldList().getField(i).getPat()
|
||||
or
|
||||
i = this.getRecordPatFieldList().getNumberOfFields() and
|
||||
result = this.getRecordPatFieldList().getRestPat()
|
||||
}
|
||||
}
|
||||
|
||||
class RefPatTree extends PreOrderPatTree, RefPat {
|
||||
override Pat getPat(int i) { i = 0 and result = super.getPat() }
|
||||
}
|
||||
|
||||
class SlicePatTree extends PreOrderPatTree instanceof SlicePat {
|
||||
override Pat getPat(int i) { result = SlicePat.super.getPat(i) }
|
||||
}
|
||||
|
||||
class TuplePatTree extends PreOrderPatTree, TuplePat {
|
||||
override Pat getPat(int i) { result = this.getField(i) }
|
||||
}
|
||||
|
||||
class TupleStructPatTree extends PreOrderPatTree, TupleStructPat {
|
||||
override Pat getPat(int i) { result = this.getField(i) }
|
||||
}
|
||||
|
||||
class ConstBlockPatTree extends LeafTree, ConstBlockPat { } // todo?
|
||||
}
|
||||
|
||||
@@ -12,13 +12,17 @@ abstract class CfgScope extends AstNode {
|
||||
}
|
||||
|
||||
final class FunctionScope extends CfgScope, Function {
|
||||
override predicate scopeFirst(AstNode node) { first(this.getBody(), node) }
|
||||
override predicate scopeFirst(AstNode node) {
|
||||
first(this.(FunctionTree).getFirstChildNode(), node)
|
||||
}
|
||||
|
||||
override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) }
|
||||
}
|
||||
|
||||
final class ClosureScope extends CfgScope, ClosureExpr {
|
||||
override predicate scopeFirst(AstNode node) { first(this.getBody(), node) }
|
||||
override predicate scopeFirst(AstNode node) {
|
||||
first(this.(ClosureExprTree).getFirstChildNode(), node)
|
||||
}
|
||||
|
||||
override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) }
|
||||
}
|
||||
|
||||
@@ -78,6 +78,11 @@ module ConditionalCompletionSplitting {
|
||||
child = parent.(MatchExpr).getAnArm().getExpr()
|
||||
or
|
||||
child = parent.(BlockExpr).getStmtList().getTailExpr()
|
||||
or
|
||||
child = parent.(PatternTrees::PreOrderPatTree).getPat(_) and
|
||||
childCompletion.(MatchCompletion).failed()
|
||||
or
|
||||
child = parent.(PatternTrees::PostOrderPatTree).getPat(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
340
rust/ql/lib/codeql/rust/dataflow/Ssa.qll
Normal file
340
rust/ql/lib/codeql/rust/dataflow/Ssa.qll
Normal file
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* Provides the module `Ssa` for working with static single assignment (SSA) form.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides classes for working with static single assignment (SSA) form.
|
||||
*/
|
||||
module Ssa {
|
||||
private import rust
|
||||
private import codeql.rust.controlflow.BasicBlocks
|
||||
private import codeql.rust.controlflow.ControlFlowGraph
|
||||
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl
|
||||
private import internal.SsaImpl as SsaImpl
|
||||
|
||||
class Variable = SsaImpl::SsaInput::SourceVariable;
|
||||
|
||||
/** A static single assignment (SSA) definition. */
|
||||
class Definition extends SsaImpl::Definition {
|
||||
/**
|
||||
* Gets the control flow node of this SSA definition, if any. Phi nodes are
|
||||
* examples of SSA definitions without a control flow node, as they are
|
||||
* modeled at index `-1` in the relevant basic block.
|
||||
*/
|
||||
final CfgNode getControlFlowNode() {
|
||||
exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a control-flow node that reads the value of this SSA definition.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* fn phi(b : bool) { // defines b_0
|
||||
* let mut x = 1; // defines x_0
|
||||
* println!("{}", x); // reads x_0
|
||||
* println!("{}", x + 1); // reads x_0
|
||||
*
|
||||
* if b { // reads b_0
|
||||
* x = 2; // defines x_1
|
||||
* println!("{}", x); // reads x_1
|
||||
* println!("{}", x + 1); // reads x_1
|
||||
* } else {
|
||||
* x = 3; // defines x_2
|
||||
* println!("{}", x); // reads x_2
|
||||
* println!("{}", x + 1); // reads x_2
|
||||
* }
|
||||
* // defines x_3 = phi(x_1, x_2)
|
||||
* println!("{}", x); // reads x_3
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final CfgNode getARead() { result = SsaImpl::getARead(this) }
|
||||
|
||||
/**
|
||||
* Gets a first control-flow node that reads the value of this SSA definition.
|
||||
* That is, a read that can be reached from this definition without passing
|
||||
* through other reads.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* fn phi(b : bool) { // defines b_0
|
||||
* let mut x = 1; // defines x_0
|
||||
* println!("{}", x); // first read of x_0
|
||||
* println!("{}", x + 1);
|
||||
*
|
||||
* if b { // first read of b_0
|
||||
* x = 2; // defines x_1
|
||||
* println!("{}", x); // first read of x_1
|
||||
* println!("{}", x + 1);
|
||||
* } else {
|
||||
* x = 3; // defines x_2
|
||||
* println!("{}", x); // first read of x_2
|
||||
* println!("{}", x + 1);
|
||||
* }
|
||||
* // defines x_3 = phi(x_1, x_2)
|
||||
* println!("{}", x); // first read of x_3
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final CfgNode getAFirstRead() { SsaImpl::firstRead(this, result) }
|
||||
|
||||
/**
|
||||
* Gets a last control-flow node that reads the value of this SSA definition.
|
||||
* That is, a read that can reach the end of the enclosing CFG scope, or another
|
||||
* SSA definition for the source variable, without passing through any other read.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* fn phi(b : bool) { // defines b_0
|
||||
* let mut x = 1; // defines x_0
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1); // last read of x_0
|
||||
*
|
||||
* if b { // last read of b_0
|
||||
* x = 2; // defines x_1
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1); // last read of x_1
|
||||
* } else {
|
||||
* x = 3; // defines x_2
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1); // last read of x_2
|
||||
* }
|
||||
* // defines x_3 = phi(x_1, x_2)
|
||||
* println!("{}", x); // last read of x_3
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final CfgNode getALastRead() { SsaImpl::lastRead(this, result) }
|
||||
|
||||
/**
|
||||
* Holds if `read1` and `read2` are adjacent reads of this SSA definition.
|
||||
* That is, `read2` can be reached from `read1` without passing through
|
||||
* another read.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* fn phi(b : bool) {
|
||||
* let mut x = 1; // defines x_0
|
||||
* println!("{}", x); // reads x_0 (read1)
|
||||
* println!("{}", x + 1); // reads x_0 (read2)
|
||||
*
|
||||
* if b {
|
||||
* x = 2; // defines x_1
|
||||
* println!("{}", x); // reads x_1 (read1)
|
||||
* println!("{}", x + 1); // reads x_1 (read2)
|
||||
* } else {
|
||||
* x = 3; // defines x_2
|
||||
* println!("{}", x); // reads x_2 (read1)
|
||||
* println!("{}", x + 1); // reads x_2 (read2)
|
||||
* }
|
||||
* println!("{}", x);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final predicate hasAdjacentReads(CfgNode read1, CfgNode read2) {
|
||||
SsaImpl::adjacentReadPair(this, read1, read2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an SSA definition whose value can flow to this one in one step. This
|
||||
* includes inputs to phi nodes and the prior definitions of uncertain writes.
|
||||
*/
|
||||
private Definition getAPhiInputOrPriorDefinition() {
|
||||
result = this.(PhiDefinition).getAnInput()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a definition that ultimately defines this SSA definition and is
|
||||
* not itself a phi node.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* fn phi(b : bool) {
|
||||
* let mut x = 1; // defines x_0
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1);
|
||||
*
|
||||
* if b {
|
||||
* x = 2; // defines x_1
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1);
|
||||
* } else {
|
||||
* x = 3; // defines x_2
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1);
|
||||
* }
|
||||
* // defines x_3 = phi(x_1, x_2); ultimate definitions are x_1 and x_2
|
||||
* println!("{}", x);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final Definition getAnUltimateDefinition() {
|
||||
result = this.getAPhiInputOrPriorDefinition*() and
|
||||
not result instanceof PhiDefinition
|
||||
}
|
||||
|
||||
override string toString() { result = this.getControlFlowNode().toString() }
|
||||
|
||||
/** Gets the scope of this SSA definition. */
|
||||
CfgScope getScope() { result = this.getBasicBlock().getScope() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition that corresponds to a write. Example:
|
||||
*
|
||||
* ```rust
|
||||
* fn m(i : i64) { // writes `i`
|
||||
* let mut x = i; // writes `x`
|
||||
* x = 11; // writes `x`
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class WriteDefinition extends Definition, SsaImpl::WriteDefinition {
|
||||
private CfgNode write;
|
||||
|
||||
WriteDefinition() {
|
||||
exists(BasicBlock bb, int i, Variable v |
|
||||
this.definesAt(v, bb, i) and
|
||||
SsaImpl::variableWriteActual(bb, i, v, write)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the underlying write access. */
|
||||
final CfgNode getWriteAccess() { result = write }
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition assigns `value` to the underlying variable.
|
||||
*
|
||||
* This is either a direct assignment, `x = value`, or an assignment via
|
||||
* simple pattern matching
|
||||
*
|
||||
* ```rb
|
||||
* case value
|
||||
* in Foo => x then ...
|
||||
* in y => then ...
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
predicate assigns(CfgNode value) {
|
||||
exists(AssignmentExpr ae, BasicBlock bb, int i |
|
||||
this.definesAt(_, bb, i) and
|
||||
ae.getLhs() = bb.getNode(i).getAstNode() and
|
||||
value.getAstNode() = ae.getRhs()
|
||||
)
|
||||
}
|
||||
|
||||
final override string toString() { result = write.toString() }
|
||||
|
||||
final override Location getLocation() { result = write.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A phi definition. For example, in
|
||||
*
|
||||
* ```rust
|
||||
* if b {
|
||||
* x = 0
|
||||
* } else {
|
||||
* x = 1
|
||||
* }
|
||||
* println!("{}", x);
|
||||
* ```
|
||||
*
|
||||
* a phi definition for `x` is inserted just before the call to `println!`.
|
||||
*/
|
||||
class PhiDefinition extends Definition, SsaImpl::PhiDefinition {
|
||||
/**
|
||||
* Gets an input of this phi definition.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* fn phi(b : bool) {
|
||||
* let mut x = 1; // defines x_0
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1);
|
||||
*
|
||||
* if b {
|
||||
* x = 2; // defines x_1
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1);
|
||||
* } else {
|
||||
* x = 3; // defines x_2
|
||||
* println!("{}", x);
|
||||
* println!("{}", x + 1);
|
||||
* }
|
||||
* // defines x_3 = phi(x_1, x_2); inputs are x_1 and x_2
|
||||
* println!("{}", x);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
||||
|
||||
/** Holds if `inp` is an input to this phi definition along the edge originating in `bb`. */
|
||||
predicate hasInputFromBlock(Definition inp, BasicBlock bb) {
|
||||
inp = SsaImpl::phiHasInputFromBlock(this, bb)
|
||||
}
|
||||
|
||||
private string getSplitString() {
|
||||
result = this.getBasicBlock().getFirstNode().(CfgImpl::AstCfgNode).getSplitsString()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
exists(string prefix |
|
||||
prefix = "[" + this.getSplitString() + "] "
|
||||
or
|
||||
not exists(this.getSplitString()) and
|
||||
prefix = ""
|
||||
|
|
||||
result = prefix + "phi"
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* The location of a phi definition is the same as the location of the first node
|
||||
* in the basic block in which it is defined.
|
||||
*
|
||||
* Strictly speaking, the node is *before* the first node, but such a location
|
||||
* does not exist in the source program.
|
||||
*/
|
||||
|
||||
final override Location getLocation() {
|
||||
result = this.getBasicBlock().getFirstNode().getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition inserted at the beginning of a scope to represent a
|
||||
* captured local variable. For example, in
|
||||
*
|
||||
* ```rust
|
||||
* fn capture_immut() {
|
||||
* let x = 100;
|
||||
* let mut cap = || {
|
||||
* println!("{}", x);
|
||||
* };
|
||||
* cap();
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* an entry definition for `x` is inserted at the start of the CFG for `cap`.
|
||||
*/
|
||||
class CapturedEntryDefinition extends Definition, SsaImpl::WriteDefinition {
|
||||
CapturedEntryDefinition() {
|
||||
exists(BasicBlock bb, int i, Variable v |
|
||||
this.definesAt(v, bb, i) and
|
||||
SsaImpl::capturedEntryWrite(bb, i, v)
|
||||
)
|
||||
}
|
||||
|
||||
final override string toString() { result = "<captured entry> " + this.getSourceVariable() }
|
||||
|
||||
override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
}
|
||||
}
|
||||
332
rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll
Normal file
332
rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll
Normal file
@@ -0,0 +1,332 @@
|
||||
private import rust
|
||||
private import codeql.rust.controlflow.BasicBlocks as BasicBlocks
|
||||
private import BasicBlocks
|
||||
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
|
||||
private import Cfg
|
||||
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as ControlFlowGraphImpl
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
|
||||
/** Holds if `v` is introduced like `let v : i64;`. */
|
||||
private predicate isUnitializedLet(IdentPat pat, Variable v) {
|
||||
pat = v.getPat() and
|
||||
exists(LetStmt let |
|
||||
let = v.getLetStmt() and
|
||||
not let.hasInitializer()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `write` writes to variable `v`. */
|
||||
predicate variableWrite(AstNode write, Variable v) {
|
||||
exists(IdentPat pat |
|
||||
pat = write and
|
||||
pat = v.getPat() and
|
||||
not isUnitializedLet(pat, v)
|
||||
)
|
||||
or
|
||||
exists(VariableAccess access |
|
||||
access = write and
|
||||
access.getVariable() = v
|
||||
|
|
||||
access instanceof VariableWriteAccess
|
||||
or
|
||||
// Although compound assignments, like `x += y`, may in fact not update `x`,
|
||||
// it makes sense to treat them as such
|
||||
access = any(CompoundAssignmentExpr cae).getLhs()
|
||||
)
|
||||
}
|
||||
|
||||
module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
class BasicBlock = BasicBlocks::BasicBlock;
|
||||
|
||||
class ControlFlowNode = CfgNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock = BasicBlocks::ExitBasicBlock;
|
||||
|
||||
/**
|
||||
* A variable amenable to SSA construction.
|
||||
*
|
||||
* All immutable variables are amenable. Mutable variables are restricted
|
||||
* to those that are not captured by closures, and are not borrowed
|
||||
* (either explicitly using `& mut`, or (potentially) implicit as borrowed
|
||||
* receivers in a method call).
|
||||
*/
|
||||
class SourceVariable extends Variable {
|
||||
SourceVariable() {
|
||||
this.isImmutable()
|
||||
or
|
||||
this.isMutable() and
|
||||
not this.isCaptured() and
|
||||
forall(VariableAccess va | va = this.getAnAccess() |
|
||||
va instanceof VariableReadAccess and
|
||||
// receivers can be borrowed implicitly, cf.
|
||||
// https://doc.rust-lang.org/reference/expressions/method-call-expr.html
|
||||
not va = any(MethodCallExpr mce).getReceiver()
|
||||
or
|
||||
variableWrite(va, this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
(
|
||||
variableWriteActual(bb, i, v, _)
|
||||
or
|
||||
capturedEntryWrite(bb, i, v)
|
||||
) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(VariableAccess va |
|
||||
bb.getNode(i).getAstNode() = va and
|
||||
va = v.getAnAccess()
|
||||
|
|
||||
va instanceof VariableReadAccess
|
||||
or
|
||||
// Although compound assignments, like `x += y`, may in fact not read `x`,
|
||||
// it makes sense to treat them as such
|
||||
va = any(CompoundAssignmentExpr cae).getLhs()
|
||||
) and
|
||||
certain = true
|
||||
or
|
||||
// For immutable variables, we model a read when they are borrowed (although the
|
||||
// actual read happens later, if at all). This only affects the SSA liveness
|
||||
// analysis.
|
||||
exists(VariableAccess va |
|
||||
va = any(RefExpr re).getExpr() and
|
||||
va = bb.getNode(i).getAstNode() and
|
||||
v = va.getVariable() and
|
||||
certain = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<Location, SsaInput> as Impl
|
||||
|
||||
class Definition = Impl::Definition;
|
||||
|
||||
class WriteDefinition = Impl::WriteDefinition;
|
||||
|
||||
class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
|
||||
|
||||
class PhiDefinition = Impl::PhiNode;
|
||||
|
||||
module Consistency = Impl::Consistency;
|
||||
|
||||
module ExposedForTestingOnly {
|
||||
predicate ssaDefReachesReadExt = Impl::ssaDefReachesReadExt/4;
|
||||
|
||||
predicate phiHasInputFromBlockExt = Impl::phiHasInputFromBlockExt/3;
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate adjacentDefRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SsaInput::SourceVariable v
|
||||
) {
|
||||
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate adjacentDefReadExt(
|
||||
DefinitionExt def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SsaInput::SourceVariable v
|
||||
) {
|
||||
Impl::adjacentDefReadExt(def, _, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
/** Holds if `v` is read at index `i` in basic block `bb`. */
|
||||
private predicate variableReadActual(BasicBlock bb, int i, Variable v) {
|
||||
exists(VariableReadAccess read |
|
||||
read.getVariable() = v and
|
||||
read = bb.getNode(i).getAstNode()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
exists(SsaInput::SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
|
||||
def.definesAt(v, bb1, i1)
|
||||
or
|
||||
SsaInput::variableRead(bb1, i1, v, true)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
|
||||
SsaInput::variableRead(bb3, i3, _, false) and
|
||||
Impl::adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesReadExt(
|
||||
DefinitionExt def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
exists(SsaInput::SourceVariable v | adjacentDefReadExt(def, bb1, i1, bb2, i2, v) |
|
||||
def.definesAt(v, bb1, i1, _)
|
||||
or
|
||||
SsaInput::variableRead(bb1, i1, v, true)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesReadExt(def, bb1, i1, bb3, i3) and
|
||||
SsaInput::variableRead(bb3, i3, _, false) and
|
||||
Impl::adjacentDefReadExt(def, _, bb3, i3, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
/** Same as `adjacentDefRead`, but skips uncertain reads. */
|
||||
pragma[nomagic]
|
||||
private predicate adjacentDefSkipUncertainReads(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
SsaInput::variableRead(bb2, i2, _, true)
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesUncertainReadExt(
|
||||
DefinitionExt def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefReachesReadExt(def, bb1, i1, bb2, i2) and
|
||||
SsaInput::variableRead(bb2, i2, _, false)
|
||||
}
|
||||
|
||||
/** Same as `lastRefRedef`, but skips uncertain reads. */
|
||||
pragma[nomagic]
|
||||
private predicate lastRefSkipUncertainReadsExt(DefinitionExt def, BasicBlock bb, int i) {
|
||||
Impl::lastRef(def, bb, i) and
|
||||
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
Impl::lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainReadExt(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `bb` contains a captured access to variable `v`. */
|
||||
pragma[nomagic]
|
||||
private predicate hasCapturedVariableAccess(BasicBlock bb, Variable v) {
|
||||
exists(VariableAccess read |
|
||||
read = bb.getANode().getAstNode() and
|
||||
read.isCapture() and
|
||||
read.getVariable() = v
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if an entry definition is needed for captured variable `v` at index
|
||||
* `i` in entry block `bb`.
|
||||
*/
|
||||
cached
|
||||
predicate capturedEntryWrite(EntryBasicBlock bb, int i, Variable v) {
|
||||
hasCapturedVariableAccess(bb.getASuccessor*(), v) and
|
||||
i = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is written at index `i` in basic block `bb`, and the corresponding
|
||||
* AST write access is `write`.
|
||||
*/
|
||||
cached
|
||||
predicate variableWriteActual(BasicBlock bb, int i, Variable v, CfgNode write) {
|
||||
bb.getNode(i) = write and
|
||||
variableWrite(write.getAstNode(), v)
|
||||
}
|
||||
|
||||
cached
|
||||
CfgNode getARead(Definition def) {
|
||||
exists(Variable v, BasicBlock bb, int i |
|
||||
Impl::ssaDefReachesRead(v, def, bb, i) and
|
||||
variableReadActual(bb, i, v) and
|
||||
result = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Definition phiHasInputFromBlock(PhiDefinition phi, BasicBlock bb) {
|
||||
Impl::phiHasInputFromBlock(phi, result, bb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value defined at SSA definition `def` can reach a read at `read`,
|
||||
* without passing through any other non-pseudo read.
|
||||
*/
|
||||
cached
|
||||
predicate firstRead(Definition def, CfgNode read) {
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
def.definesAt(_, bb1, i1) and
|
||||
adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and
|
||||
read = bb2.getNode(i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the read at `read2` is a read of the same SSA definition `def`
|
||||
* as the read at `read1`, and `read2` can be reached from `read1` without
|
||||
* passing through another non-pseudo read.
|
||||
*/
|
||||
cached
|
||||
predicate adjacentReadPair(Definition def, CfgNode read1, CfgNode read2) {
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
read1 = bb1.getNode(i1) and
|
||||
variableReadActual(bb1, i1, _) and
|
||||
adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and
|
||||
read2 = bb2.getNode(i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the read of `def` at `read` may be a last read. That is, `read`
|
||||
* can either reach another definition of the underlying source variable or
|
||||
* the end of the CFG scope, without passing through another non-pseudo read.
|
||||
*/
|
||||
cached
|
||||
predicate lastRead(Definition def, CfgNode read) {
|
||||
exists(BasicBlock bb, int i |
|
||||
lastRefSkipUncertainReadsExt(def, bb, i) and
|
||||
variableReadActual(bb, i, _) and
|
||||
read = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
|
||||
Impl::uncertainWriteDefinitionInput(def, result)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
private import codeql.rust.dataflow.Ssa
|
||||
|
||||
/**
|
||||
* An extended static single assignment (SSA) definition.
|
||||
*
|
||||
* This is either a normal SSA definition (`Definition`) or a
|
||||
* phi-read node (`PhiReadNode`).
|
||||
*
|
||||
* Only intended for internal use.
|
||||
*/
|
||||
class DefinitionExt extends Impl::DefinitionExt {
|
||||
CfgNode getARead() { result = getARead(this) }
|
||||
|
||||
override string toString() { result = this.(Ssa::Definition).toString() }
|
||||
|
||||
override Location getLocation() { result = this.(Ssa::Definition).getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A phi-read node.
|
||||
*
|
||||
* Only intended for internal use.
|
||||
*/
|
||||
class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
|
||||
override string toString() { result = "SSA phi read(" + this.getSourceVariable() + ")" }
|
||||
|
||||
override Location getLocation() { result = Impl::PhiReadNode.super.getLocation() }
|
||||
}
|
||||
2
rust/ql/lib/codeql/rust/elements.qll
generated
2
rust/ql/lib/codeql/rust/elements.qll
generated
@@ -74,8 +74,10 @@ import codeql.rust.elements.LoopExpr
|
||||
import codeql.rust.elements.MacroCall
|
||||
import codeql.rust.elements.MacroDef
|
||||
import codeql.rust.elements.MacroExpr
|
||||
import codeql.rust.elements.MacroItems
|
||||
import codeql.rust.elements.MacroPat
|
||||
import codeql.rust.elements.MacroRules
|
||||
import codeql.rust.elements.MacroStmts
|
||||
import codeql.rust.elements.MacroType
|
||||
import codeql.rust.elements.MatchArm
|
||||
import codeql.rust.elements.MatchArmList
|
||||
|
||||
1
rust/ql/lib/codeql/rust/elements/MacroCall.qll
generated
1
rust/ql/lib/codeql/rust/elements/MacroCall.qll
generated
@@ -5,6 +5,7 @@
|
||||
|
||||
private import internal.MacroCallImpl
|
||||
import codeql.rust.elements.AssocItem
|
||||
import codeql.rust.elements.AstNode
|
||||
import codeql.rust.elements.Attr
|
||||
import codeql.rust.elements.ExternItem
|
||||
import codeql.rust.elements.Item
|
||||
|
||||
18
rust/ql/lib/codeql/rust/elements/MacroItems.qll
generated
Normal file
18
rust/ql/lib/codeql/rust/elements/MacroItems.qll
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
// generated by codegen, do not edit
|
||||
/**
|
||||
* This module provides the public class `MacroItems`.
|
||||
*/
|
||||
|
||||
private import internal.MacroItemsImpl
|
||||
import codeql.rust.elements.AstNode
|
||||
import codeql.rust.elements.Item
|
||||
|
||||
/**
|
||||
* A sequence of items generated by a `MacroCall`. For example:
|
||||
* ```rust
|
||||
* mod foo{
|
||||
* include!("common_definitions.rs");
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final class MacroItems = Impl::MacroItems;
|
||||
19
rust/ql/lib/codeql/rust/elements/MacroStmts.qll
generated
Normal file
19
rust/ql/lib/codeql/rust/elements/MacroStmts.qll
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
// generated by codegen, do not edit
|
||||
/**
|
||||
* This module provides the public class `MacroStmts`.
|
||||
*/
|
||||
|
||||
private import internal.MacroStmtsImpl
|
||||
import codeql.rust.elements.AstNode
|
||||
import codeql.rust.elements.Expr
|
||||
import codeql.rust.elements.Stmt
|
||||
|
||||
/**
|
||||
* A sequence of statements generated by a `MacroCall`. For example:
|
||||
* ```rust
|
||||
* fn main() {
|
||||
* println!("Hello, world!"); // This macro expands into a list of statements
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final class MacroStmts = Impl::MacroStmts;
|
||||
14
rust/ql/lib/codeql/rust/elements/internal/MacroItemsConstructor.qll
generated
Normal file
14
rust/ql/lib/codeql/rust/elements/internal/MacroItemsConstructor.qll
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module defines the hook used internally to tweak the characteristic predicate of
|
||||
* `MacroItems` synthesized instances.
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.Raw
|
||||
|
||||
/**
|
||||
* The characteristic predicate of `MacroItems` synthesized instances.
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
predicate constructMacroItems(Raw::MacroItems id) { any() }
|
||||
24
rust/ql/lib/codeql/rust/elements/internal/MacroItemsImpl.qll
generated
Normal file
24
rust/ql/lib/codeql/rust/elements/internal/MacroItemsImpl.qll
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module provides a hand-modifiable wrapper around the generated class `MacroItems`.
|
||||
*
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.MacroItems
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the customizable definition of `MacroItems` and should not
|
||||
* be referenced directly.
|
||||
*/
|
||||
module Impl {
|
||||
/**
|
||||
* A sequence of items generated by a `MacroCall`. For example:
|
||||
* ```rust
|
||||
* mod foo{
|
||||
* include!("common_definitions.rs");
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class MacroItems extends Generated::MacroItems { }
|
||||
}
|
||||
14
rust/ql/lib/codeql/rust/elements/internal/MacroStmtsConstructor.qll
generated
Normal file
14
rust/ql/lib/codeql/rust/elements/internal/MacroStmtsConstructor.qll
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module defines the hook used internally to tweak the characteristic predicate of
|
||||
* `MacroStmts` synthesized instances.
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.Raw
|
||||
|
||||
/**
|
||||
* The characteristic predicate of `MacroStmts` synthesized instances.
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
predicate constructMacroStmts(Raw::MacroStmts id) { any() }
|
||||
24
rust/ql/lib/codeql/rust/elements/internal/MacroStmtsImpl.qll
generated
Normal file
24
rust/ql/lib/codeql/rust/elements/internal/MacroStmtsImpl.qll
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module provides a hand-modifiable wrapper around the generated class `MacroStmts`.
|
||||
*
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.MacroStmts
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the customizable definition of `MacroStmts` and should not
|
||||
* be referenced directly.
|
||||
*/
|
||||
module Impl {
|
||||
/**
|
||||
* A sequence of statements generated by a `MacroCall`. For example:
|
||||
* ```rust
|
||||
* fn main() {
|
||||
* println!("Hello, world!"); // This macro expands into a list of statements
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class MacroStmts extends Generated::MacroStmts { }
|
||||
}
|
||||
@@ -42,5 +42,11 @@ module Impl {
|
||||
* Gets the number of arms of this match expression.
|
||||
*/
|
||||
int getNumberOfArms() { result = this.getMatchArmList().getNumberOfArms() }
|
||||
|
||||
/**
|
||||
* Gets the last arm of this match expression. Due to exhaustiveness checking,
|
||||
* this arm is guaranteed to succeed.
|
||||
*/
|
||||
MatchArm getLastArm() { result = this.getArm(this.getNumberOfArms() - 1) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module provides a hand-modifiable wrapper around the generated class `OrPat`.
|
||||
*
|
||||
@@ -12,6 +11,7 @@ private import codeql.rust.elements.internal.generated.OrPat
|
||||
* be referenced directly.
|
||||
*/
|
||||
module Impl {
|
||||
// the following QLdoc is generated: if you need to edit it, do it in the schema file
|
||||
/**
|
||||
* An or pattern. For example:
|
||||
* ```rust
|
||||
@@ -20,5 +20,9 @@ module Impl {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class OrPat extends Generated::OrPat { }
|
||||
class OrPat extends Generated::OrPat {
|
||||
/** Gets the last pattern in this or pattern. */
|
||||
pragma[nomagic]
|
||||
Pat getLastPat() { result = this.getPat(this.getNumberOfPats() - 1) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,16 +118,23 @@ module Impl {
|
||||
*/
|
||||
IdentPat getPat() { variableDecl(definingNode, result, name) }
|
||||
|
||||
/** Gets the `let` statement that introduces this variable, if any. */
|
||||
LetStmt getLetStmt() { this.getPat() = result.getPat() }
|
||||
|
||||
/** Gets the initial value of this variable, if any. */
|
||||
Expr getInitializer() {
|
||||
exists(LetStmt let |
|
||||
this.getPat() = let.getPat() and
|
||||
result = let.getInitializer()
|
||||
)
|
||||
}
|
||||
Expr getInitializer() { result = this.getLetStmt().getInitializer() }
|
||||
|
||||
/** Holds if this variable is captured. */
|
||||
predicate isCaptured() { this.getAnAccess().isCapture() }
|
||||
|
||||
/** Gets the parameter that introduces this variable, if any. */
|
||||
Param getParameter() { parameterDeclInScope(result, this, _) }
|
||||
|
||||
/** Hold is this variable is mutable. */
|
||||
predicate isMutable() { this.getPat().isMut() }
|
||||
|
||||
/** Hold is this variable is immutable. */
|
||||
predicate isImmutable() { not this.isMutable() }
|
||||
}
|
||||
|
||||
/** A path expression that may access a local variable. */
|
||||
@@ -180,6 +187,27 @@ module Impl {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if parameter `p` introduces the variable `v` inside variable scope
|
||||
* `scope`.
|
||||
*/
|
||||
private predicate parameterDeclInScope(Param p, Variable v, VariableScope scope) {
|
||||
exists(Pat pat |
|
||||
pat = getAVariablePatAncestor(v) and
|
||||
p.getPat() = pat
|
||||
|
|
||||
exists(Function f |
|
||||
f.getParamList().getAParam() = p and
|
||||
scope = f.getBody()
|
||||
)
|
||||
or
|
||||
exists(ClosureExpr ce |
|
||||
ce.getParamList().getAParam() = p and
|
||||
scope = ce.getBody()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is named `name` and is declared inside variable scope
|
||||
* `scope`, and `v` is bound starting from `(line, column)`.
|
||||
@@ -188,51 +216,44 @@ module Impl {
|
||||
Variable v, VariableScope scope, string name, int line, int column
|
||||
) {
|
||||
name = v.getName() and
|
||||
exists(Pat pat | pat = getAVariablePatAncestor(v) |
|
||||
scope =
|
||||
any(MatchArmScope arm |
|
||||
arm.getPat() = pat and
|
||||
arm.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
(
|
||||
parameterDeclInScope(_, v, scope) and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
or
|
||||
exists(Pat pat | pat = getAVariablePatAncestor(v) |
|
||||
scope =
|
||||
any(MatchArmScope arm |
|
||||
arm.getPat() = pat and
|
||||
arm.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
or
|
||||
exists(LetStmt let |
|
||||
let.getPat() = pat and
|
||||
scope = getEnclosingScope(let) and
|
||||
// for `let` statements, variables are bound _after_ the statement, i.e.
|
||||
// not in the RHS
|
||||
let.getLocation().hasLocationInfo(_, _, _, line, column)
|
||||
)
|
||||
or
|
||||
exists(IfExpr ie, LetExpr let |
|
||||
let.getPat() = pat and
|
||||
ie.getCondition() = let and
|
||||
scope = ie.getThen() and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
or
|
||||
exists(ForExpr fe |
|
||||
fe.getPat() = pat and
|
||||
scope = fe.getLoopBody() and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
or
|
||||
exists(WhileExpr we, LetExpr let |
|
||||
let.getPat() = pat and
|
||||
we.getCondition() = let and
|
||||
scope = we.getLoopBody() and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
or
|
||||
exists(Function f |
|
||||
f.getParamList().getAParam().getPat() = pat and
|
||||
scope = f.getBody() and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
or
|
||||
exists(LetStmt let |
|
||||
let.getPat() = pat and
|
||||
scope = getEnclosingScope(let) and
|
||||
// for `let` statements, variables are bound _after_ the statement, i.e.
|
||||
// not in the RHS
|
||||
let.getLocation().hasLocationInfo(_, _, _, line, column)
|
||||
)
|
||||
or
|
||||
exists(IfExpr ie, LetExpr let |
|
||||
let.getPat() = pat and
|
||||
ie.getCondition() = let and
|
||||
scope = ie.getThen() and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
or
|
||||
exists(ForExpr fe |
|
||||
fe.getPat() = pat and
|
||||
scope = fe.getLoopBody() and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
or
|
||||
exists(ClosureExpr ce |
|
||||
ce.getParamList().getAParam().getPat() = pat and
|
||||
scope = ce.getBody() and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
or
|
||||
exists(WhileExpr we, LetExpr let |
|
||||
let.getPat() = pat and
|
||||
we.getCondition() = let and
|
||||
scope = we.getLoopBody() and
|
||||
scope.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -427,7 +448,8 @@ module Impl {
|
||||
exists(Expr mid |
|
||||
assignmentExprDescendant(mid) and
|
||||
getImmediateParent(e) = mid and
|
||||
not mid.(PrefixExpr).getOperatorName() = "*"
|
||||
not mid.(PrefixExpr).getOperatorName() = "*" and
|
||||
not mid instanceof FieldExpr
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
private import codeql.rust.elements.internal.generated.Synth
|
||||
private import codeql.rust.elements.internal.generated.Raw
|
||||
import codeql.rust.elements.internal.AssocItemImpl::Impl as AssocItemImpl
|
||||
import codeql.rust.elements.AstNode
|
||||
import codeql.rust.elements.Attr
|
||||
import codeql.rust.elements.internal.ExternItemImpl::Impl as ExternItemImpl
|
||||
import codeql.rust.elements.internal.ItemImpl::Impl as ItemImpl
|
||||
@@ -76,5 +77,20 @@ module Generated {
|
||||
* Holds if `getTokenTree()` exists.
|
||||
*/
|
||||
final predicate hasTokenTree() { exists(this.getTokenTree()) }
|
||||
|
||||
/**
|
||||
* Gets the expanded of this macro call, if it exists.
|
||||
*/
|
||||
AstNode getExpanded() {
|
||||
result =
|
||||
Synth::convertAstNodeFromRaw(Synth::convertMacroCallToRaw(this)
|
||||
.(Raw::MacroCall)
|
||||
.getExpanded())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `getExpanded()` exists.
|
||||
*/
|
||||
final predicate hasExpanded() { exists(this.getExpanded()) }
|
||||
}
|
||||
}
|
||||
|
||||
50
rust/ql/lib/codeql/rust/elements/internal/generated/MacroItems.qll
generated
Normal file
50
rust/ql/lib/codeql/rust/elements/internal/generated/MacroItems.qll
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
// generated by codegen, do not edit
|
||||
/**
|
||||
* This module provides the generated definition of `MacroItems`.
|
||||
* INTERNAL: Do not import directly.
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.Synth
|
||||
private import codeql.rust.elements.internal.generated.Raw
|
||||
import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
|
||||
import codeql.rust.elements.Item
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the fully generated definition of `MacroItems` and should not
|
||||
* be referenced directly.
|
||||
*/
|
||||
module Generated {
|
||||
/**
|
||||
* A sequence of items generated by a `MacroCall`. For example:
|
||||
* ```rust
|
||||
* mod foo{
|
||||
* include!("common_definitions.rs");
|
||||
* }
|
||||
* ```
|
||||
* INTERNAL: Do not reference the `Generated::MacroItems` class directly.
|
||||
* Use the subclass `MacroItems`, where the following predicates are available.
|
||||
*/
|
||||
class MacroItems extends Synth::TMacroItems, AstNodeImpl::AstNode {
|
||||
override string getAPrimaryQlClass() { result = "MacroItems" }
|
||||
|
||||
/**
|
||||
* Gets the `index`th item of this macro items (0-based).
|
||||
*/
|
||||
Item getItem(int index) {
|
||||
result =
|
||||
Synth::convertItemFromRaw(Synth::convertMacroItemsToRaw(this)
|
||||
.(Raw::MacroItems)
|
||||
.getItem(index))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any of the items of this macro items.
|
||||
*/
|
||||
final Item getAnItem() { result = this.getItem(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of items of this macro items.
|
||||
*/
|
||||
final int getNumberOfItems() { result = count(int i | exists(this.getItem(i))) }
|
||||
}
|
||||
}
|
||||
64
rust/ql/lib/codeql/rust/elements/internal/generated/MacroStmts.qll
generated
Normal file
64
rust/ql/lib/codeql/rust/elements/internal/generated/MacroStmts.qll
generated
Normal file
@@ -0,0 +1,64 @@
|
||||
// generated by codegen, do not edit
|
||||
/**
|
||||
* This module provides the generated definition of `MacroStmts`.
|
||||
* INTERNAL: Do not import directly.
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.Synth
|
||||
private import codeql.rust.elements.internal.generated.Raw
|
||||
import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
|
||||
import codeql.rust.elements.Expr
|
||||
import codeql.rust.elements.Stmt
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the fully generated definition of `MacroStmts` and should not
|
||||
* be referenced directly.
|
||||
*/
|
||||
module Generated {
|
||||
/**
|
||||
* A sequence of statements generated by a `MacroCall`. For example:
|
||||
* ```rust
|
||||
* fn main() {
|
||||
* println!("Hello, world!"); // This macro expands into a list of statements
|
||||
* }
|
||||
* ```
|
||||
* INTERNAL: Do not reference the `Generated::MacroStmts` class directly.
|
||||
* Use the subclass `MacroStmts`, where the following predicates are available.
|
||||
*/
|
||||
class MacroStmts extends Synth::TMacroStmts, AstNodeImpl::AstNode {
|
||||
override string getAPrimaryQlClass() { result = "MacroStmts" }
|
||||
|
||||
/**
|
||||
* Gets the expression of this macro statements, if it exists.
|
||||
*/
|
||||
Expr getExpr() {
|
||||
result =
|
||||
Synth::convertExprFromRaw(Synth::convertMacroStmtsToRaw(this).(Raw::MacroStmts).getExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `getExpr()` exists.
|
||||
*/
|
||||
final predicate hasExpr() { exists(this.getExpr()) }
|
||||
|
||||
/**
|
||||
* Gets the `index`th statement of this macro statements (0-based).
|
||||
*/
|
||||
Stmt getStatement(int index) {
|
||||
result =
|
||||
Synth::convertStmtFromRaw(Synth::convertMacroStmtsToRaw(this)
|
||||
.(Raw::MacroStmts)
|
||||
.getStatement(index))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any of the statements of this macro statements.
|
||||
*/
|
||||
final Stmt getAStatement() { result = this.getStatement(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of statements of this macro statements.
|
||||
*/
|
||||
final int getNumberOfStatements() { result = count(int i | exists(this.getStatement(i))) }
|
||||
}
|
||||
}
|
||||
@@ -418,6 +418,43 @@ private module Impl {
|
||||
)
|
||||
}
|
||||
|
||||
private Element getImmediateChildOfMacroItems(MacroItems e, int index, string partialPredicateCall) {
|
||||
exists(int b, int bAstNode, int n, int nItem |
|
||||
b = 0 and
|
||||
bAstNode = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAstNode(e, i, _)) | i) and
|
||||
n = bAstNode and
|
||||
nItem = n + 1 + max(int i | i = -1 or exists(e.getItem(i)) | i) and
|
||||
(
|
||||
none()
|
||||
or
|
||||
result = getImmediateChildOfAstNode(e, index - b, partialPredicateCall)
|
||||
or
|
||||
result = e.getItem(index - n) and
|
||||
partialPredicateCall = "Item(" + (index - n).toString() + ")"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private Element getImmediateChildOfMacroStmts(MacroStmts e, int index, string partialPredicateCall) {
|
||||
exists(int b, int bAstNode, int n, int nExpr, int nStatement |
|
||||
b = 0 and
|
||||
bAstNode = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAstNode(e, i, _)) | i) and
|
||||
n = bAstNode and
|
||||
nExpr = n + 1 and
|
||||
nStatement = nExpr + 1 + max(int i | i = -1 or exists(e.getStatement(i)) | i) and
|
||||
(
|
||||
none()
|
||||
or
|
||||
result = getImmediateChildOfAstNode(e, index - b, partialPredicateCall)
|
||||
or
|
||||
index = n and result = e.getExpr() and partialPredicateCall = "Expr()"
|
||||
or
|
||||
result = e.getStatement(index - nExpr) and
|
||||
partialPredicateCall = "Statement(" + (index - nExpr).toString() + ")"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private Element getImmediateChildOfMatchArm(MatchArm e, int index, string partialPredicateCall) {
|
||||
exists(int b, int bAstNode, int n, int nAttr, int nExpr, int nGuard, int nPat |
|
||||
b = 0 and
|
||||
@@ -2999,7 +3036,8 @@ private module Impl {
|
||||
|
||||
private Element getImmediateChildOfMacroCall(MacroCall e, int index, string partialPredicateCall) {
|
||||
exists(
|
||||
int b, int bAssocItem, int bExternItem, int bItem, int n, int nAttr, int nPath, int nTokenTree
|
||||
int b, int bAssocItem, int bExternItem, int bItem, int n, int nAttr, int nPath,
|
||||
int nTokenTree, int nExpanded
|
||||
|
|
||||
b = 0 and
|
||||
bAssocItem = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAssocItem(e, i, _)) | i) and
|
||||
@@ -3010,6 +3048,7 @@ private module Impl {
|
||||
nAttr = n + 1 + max(int i | i = -1 or exists(e.getAttr(i)) | i) and
|
||||
nPath = nAttr + 1 and
|
||||
nTokenTree = nPath + 1 and
|
||||
nExpanded = nTokenTree + 1 and
|
||||
(
|
||||
none()
|
||||
or
|
||||
@@ -3025,6 +3064,8 @@ private module Impl {
|
||||
index = nAttr and result = e.getPath() and partialPredicateCall = "Path()"
|
||||
or
|
||||
index = nPath and result = e.getTokenTree() and partialPredicateCall = "TokenTree()"
|
||||
or
|
||||
index = nTokenTree and result = e.getExpanded() and partialPredicateCall = "Expanded()"
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3448,6 +3489,10 @@ private module Impl {
|
||||
or
|
||||
result = getImmediateChildOfLifetime(e, index, partialAccessor)
|
||||
or
|
||||
result = getImmediateChildOfMacroItems(e, index, partialAccessor)
|
||||
or
|
||||
result = getImmediateChildOfMacroStmts(e, index, partialAccessor)
|
||||
or
|
||||
result = getImmediateChildOfMatchArm(e, index, partialAccessor)
|
||||
or
|
||||
result = getImmediateChildOfMatchArmList(e, index, partialAccessor)
|
||||
|
||||
@@ -345,6 +345,47 @@ module Raw {
|
||||
string getText() { lifetime_texts(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* A sequence of items generated by a `MacroCall`. For example:
|
||||
* ```rust
|
||||
* mod foo{
|
||||
* include!("common_definitions.rs");
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class MacroItems extends @macro_items, AstNode {
|
||||
override string toString() { result = "MacroItems" }
|
||||
|
||||
/**
|
||||
* Gets the `index`th item of this macro items (0-based).
|
||||
*/
|
||||
Item getItem(int index) { macro_items_items(this, index, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* A sequence of statements generated by a `MacroCall`. For example:
|
||||
* ```rust
|
||||
* fn main() {
|
||||
* println!("Hello, world!"); // This macro expands into a list of statements
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class MacroStmts extends @macro_stmts, AstNode {
|
||||
override string toString() { result = "MacroStmts" }
|
||||
|
||||
/**
|
||||
* Gets the expression of this macro statements, if it exists.
|
||||
*/
|
||||
Expr getExpr() { macro_stmts_exprs(this, result) }
|
||||
|
||||
/**
|
||||
* Gets the `index`th statement of this macro statements (0-based).
|
||||
*/
|
||||
Stmt getStatement(int index) { macro_stmts_statements(this, index, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* A match arm. For example:
|
||||
@@ -3430,6 +3471,11 @@ module Raw {
|
||||
* Gets the token tree of this macro call, if it exists.
|
||||
*/
|
||||
TokenTree getTokenTree() { macro_call_token_trees(this, result) }
|
||||
|
||||
/**
|
||||
* Gets the expanded of this macro call, if it exists.
|
||||
*/
|
||||
AstNode getExpanded() { macro_call_expandeds(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -250,6 +250,10 @@ module Synth {
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
TMacroExpr(Raw::MacroExpr id) { constructMacroExpr(id) } or
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
TMacroItems(Raw::MacroItems id) { constructMacroItems(id) } or
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
@@ -258,6 +262,10 @@ module Synth {
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
TMacroRules(Raw::MacroRules id) { constructMacroRules(id) } or
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
TMacroStmts(Raw::MacroStmts id) { constructMacroStmts(id) } or
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
@@ -595,13 +603,13 @@ module Synth {
|
||||
TAbi or TArgList or TAssocItem or TAssocItemList or TAttr or TCallable or TClosureBinder or
|
||||
TExpr or TExternItem or TExternItemList or TFieldList or TFormatArgsArg or TGenericArg or
|
||||
TGenericArgList or TGenericParam or TGenericParamList or TItemList or TLabel or TLetElse or
|
||||
TLifetime or TMatchArm or TMatchArmList or TMatchGuard or TMeta or TName or TNameRef or
|
||||
TParam or TParamList or TPat or TPath or TPathSegment or TRecordExprField or
|
||||
TRecordExprFieldList or TRecordField or TRecordPatField or TRecordPatFieldList or TRename or
|
||||
TRetType or TReturnTypeSyntax or TSelfParam or TSourceFile or TStmt or TStmtList or
|
||||
TToken or TTokenTree or TTupleField or TTypeBound or TTypeBoundList or TTypeRef or
|
||||
TUseTree or TUseTreeList or TVariant or TVariantList or TVisibility or TWhereClause or
|
||||
TWherePred;
|
||||
TLifetime or TMacroItems or TMacroStmts or TMatchArm or TMatchArmList or TMatchGuard or
|
||||
TMeta or TName or TNameRef or TParam or TParamList or TPat or TPath or TPathSegment or
|
||||
TRecordExprField or TRecordExprFieldList or TRecordField or TRecordPatField or
|
||||
TRecordPatFieldList or TRename or TRetType or TReturnTypeSyntax or TSelfParam or
|
||||
TSourceFile or TStmt or TStmtList or TToken or TTokenTree or TTupleField or TTypeBound or
|
||||
TTypeBoundList or TTypeRef or TUseTree or TUseTreeList or TVariant or TVariantList or
|
||||
TVisibility or TWhereClause or TWherePred;
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
@@ -1042,6 +1050,12 @@ module Synth {
|
||||
*/
|
||||
TMacroExpr convertMacroExprFromRaw(Raw::Element e) { result = TMacroExpr(e) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Converts a raw element to a synthesized `TMacroItems`, if possible.
|
||||
*/
|
||||
TMacroItems convertMacroItemsFromRaw(Raw::Element e) { result = TMacroItems(e) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Converts a raw element to a synthesized `TMacroPat`, if possible.
|
||||
@@ -1054,6 +1068,12 @@ module Synth {
|
||||
*/
|
||||
TMacroRules convertMacroRulesFromRaw(Raw::Element e) { result = TMacroRules(e) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Converts a raw element to a synthesized `TMacroStmts`, if possible.
|
||||
*/
|
||||
TMacroStmts convertMacroStmtsFromRaw(Raw::Element e) { result = TMacroStmts(e) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Converts a raw element to a synthesized `TMacroType`, if possible.
|
||||
@@ -1603,6 +1623,10 @@ module Synth {
|
||||
or
|
||||
result = convertLifetimeFromRaw(e)
|
||||
or
|
||||
result = convertMacroItemsFromRaw(e)
|
||||
or
|
||||
result = convertMacroStmtsFromRaw(e)
|
||||
or
|
||||
result = convertMatchArmFromRaw(e)
|
||||
or
|
||||
result = convertMatchArmListFromRaw(e)
|
||||
@@ -2332,6 +2356,12 @@ module Synth {
|
||||
*/
|
||||
Raw::Element convertMacroExprToRaw(TMacroExpr e) { e = TMacroExpr(result) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Converts a synthesized `TMacroItems` to a raw DB element, if possible.
|
||||
*/
|
||||
Raw::Element convertMacroItemsToRaw(TMacroItems e) { e = TMacroItems(result) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Converts a synthesized `TMacroPat` to a raw DB element, if possible.
|
||||
@@ -2344,6 +2374,12 @@ module Synth {
|
||||
*/
|
||||
Raw::Element convertMacroRulesToRaw(TMacroRules e) { e = TMacroRules(result) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Converts a synthesized `TMacroStmts` to a raw DB element, if possible.
|
||||
*/
|
||||
Raw::Element convertMacroStmtsToRaw(TMacroStmts e) { e = TMacroStmts(result) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Converts a synthesized `TMacroType` to a raw DB element, if possible.
|
||||
@@ -2893,6 +2929,10 @@ module Synth {
|
||||
or
|
||||
result = convertLifetimeToRaw(e)
|
||||
or
|
||||
result = convertMacroItemsToRaw(e)
|
||||
or
|
||||
result = convertMacroStmtsToRaw(e)
|
||||
or
|
||||
result = convertMatchArmToRaw(e)
|
||||
or
|
||||
result = convertMatchArmListToRaw(e)
|
||||
|
||||
@@ -62,8 +62,10 @@ import codeql.rust.elements.internal.LoopExprConstructor
|
||||
import codeql.rust.elements.internal.MacroCallConstructor
|
||||
import codeql.rust.elements.internal.MacroDefConstructor
|
||||
import codeql.rust.elements.internal.MacroExprConstructor
|
||||
import codeql.rust.elements.internal.MacroItemsConstructor
|
||||
import codeql.rust.elements.internal.MacroPatConstructor
|
||||
import codeql.rust.elements.internal.MacroRulesConstructor
|
||||
import codeql.rust.elements.internal.MacroStmtsConstructor
|
||||
import codeql.rust.elements.internal.MacroTypeConstructor
|
||||
import codeql.rust.elements.internal.MatchArmConstructor
|
||||
import codeql.rust.elements.internal.MatchArmListConstructor
|
||||
|
||||
@@ -154,6 +154,8 @@ locatable_locations(
|
||||
| @label
|
||||
| @let_else
|
||||
| @lifetime
|
||||
| @macro_items
|
||||
| @macro_stmts
|
||||
| @match_arm
|
||||
| @match_arm_list
|
||||
| @match_guard
|
||||
@@ -451,6 +453,34 @@ lifetime_texts(
|
||||
string text: string ref
|
||||
);
|
||||
|
||||
macro_items(
|
||||
unique int id: @macro_items
|
||||
);
|
||||
|
||||
#keyset[id, index]
|
||||
macro_items_items(
|
||||
int id: @macro_items ref,
|
||||
int index: int ref,
|
||||
int item: @item ref
|
||||
);
|
||||
|
||||
macro_stmts(
|
||||
unique int id: @macro_stmts
|
||||
);
|
||||
|
||||
#keyset[id]
|
||||
macro_stmts_exprs(
|
||||
int id: @macro_stmts ref,
|
||||
int expr: @expr ref
|
||||
);
|
||||
|
||||
#keyset[id, index]
|
||||
macro_stmts_statements(
|
||||
int id: @macro_stmts ref,
|
||||
int index: int ref,
|
||||
int statement: @stmt ref
|
||||
);
|
||||
|
||||
match_arms(
|
||||
unique int id: @match_arm
|
||||
);
|
||||
@@ -2885,6 +2915,12 @@ macro_call_token_trees(
|
||||
int token_tree: @token_tree ref
|
||||
);
|
||||
|
||||
#keyset[id]
|
||||
macro_call_expandeds(
|
||||
int id: @macro_call ref,
|
||||
int expanded: @ast_node ref
|
||||
);
|
||||
|
||||
macro_defs(
|
||||
unique int id: @macro_def
|
||||
);
|
||||
|
||||
@@ -57,8 +57,10 @@ LoopExpr/gen_loop_expr.rs 35deaf35e765db4ae3124a11284266d8f341d1ce7b700030efada0
|
||||
MacroCall/gen_macro_call.rs 139ef2c69323eea1a901e260d4e2acdd00b26f013b90c9344f48c6503ce29d79 139ef2c69323eea1a901e260d4e2acdd00b26f013b90c9344f48c6503ce29d79
|
||||
MacroDef/gen_macro_def.rs 17c5387fb464a60b4a4520d22b055ba35ff23e9fe431a18a33808ae02c4bbff5 17c5387fb464a60b4a4520d22b055ba35ff23e9fe431a18a33808ae02c4bbff5
|
||||
MacroExpr/gen_macro_expr.rs 3c23dc88fcc4bc8f97d9364d2f367671a0a5a63d07e52237d28204b64756dcdb 3c23dc88fcc4bc8f97d9364d2f367671a0a5a63d07e52237d28204b64756dcdb
|
||||
MacroItems/gen_macro_items.rs 8ef3e16b73635dc97afa3ffa4db2bb21a8f1b435176861a594b0200cc5b9b931 8ef3e16b73635dc97afa3ffa4db2bb21a8f1b435176861a594b0200cc5b9b931
|
||||
MacroPat/gen_macro_pat.rs b8041370598bd7fb26778d829a15c415c2078d69124f6af634ddeba13a114aa0 b8041370598bd7fb26778d829a15c415c2078d69124f6af634ddeba13a114aa0
|
||||
MacroRules/gen_macro_rules.rs 7e03b410f4669e422d3b4328f7aafdca2e286e5d951495dd69cee0d44cb793a9 7e03b410f4669e422d3b4328f7aafdca2e286e5d951495dd69cee0d44cb793a9
|
||||
MacroStmts/gen_macro_stmts.rs 2e45dcf44bf2e8404b49ce9abeee4931572693174b5d96f3fd81eb40ea8e7b4b 2e45dcf44bf2e8404b49ce9abeee4931572693174b5d96f3fd81eb40ea8e7b4b
|
||||
MacroType/gen_macro_type.rs 84db79c78860512b14f885391fcae999ca7282f2d8a9ab65d30cc413d5bbebd0 84db79c78860512b14f885391fcae999ca7282f2d8a9ab65d30cc413d5bbebd0
|
||||
MatchArm/gen_match_arm.rs ac75b4836a103e2755bd47a1ee1b74af6eb8349adc4ebedaaa27b3ea3ae41aa5 ac75b4836a103e2755bd47a1ee1b74af6eb8349adc4ebedaaa27b3ea3ae41aa5
|
||||
MatchArmList/gen_match_arm_list.rs dbf36444d371421a2b8768a188660dd45ed3b823fb1c56b90c1ba77f177d23d6 dbf36444d371421a2b8768a188660dd45ed3b823fb1c56b90c1ba77f177d23d6
|
||||
|
||||
2
rust/ql/test/extractor-tests/generated/.gitattributes
generated
vendored
2
rust/ql/test/extractor-tests/generated/.gitattributes
generated
vendored
@@ -59,8 +59,10 @@
|
||||
/MacroCall/gen_macro_call.rs linguist-generated
|
||||
/MacroDef/gen_macro_def.rs linguist-generated
|
||||
/MacroExpr/gen_macro_expr.rs linguist-generated
|
||||
/MacroItems/gen_macro_items.rs linguist-generated
|
||||
/MacroPat/gen_macro_pat.rs linguist-generated
|
||||
/MacroRules/gen_macro_rules.rs linguist-generated
|
||||
/MacroStmts/gen_macro_stmts.rs linguist-generated
|
||||
/MacroType/gen_macro_type.rs linguist-generated
|
||||
/MatchArm/gen_match_arm.rs linguist-generated
|
||||
/MatchArmList/gen_match_arm_list.rs linguist-generated
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| gen_arg_list.rs:5:5:5:11 | ArgList | getNumberOfArgs: | 1 |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| gen_arg_list.rs:5:5:5:11 | ArgList | 0 | gen_arg_list.rs:5:5:5:11 | "not yet implemented" |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| gen_macro_call.rs:5:5:5:11 | MacroCall | getNumberOfAttrs: | 0 | hasPath: | yes | hasTokenTree: | yes |
|
||||
| gen_macro_call.rs:5:5:5:11 | MacroCall | getNumberOfAttrs: | 0 | hasPath: | yes | hasTokenTree: | yes | hasExpanded: | yes |
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
import codeql.rust.elements
|
||||
import TestUtils
|
||||
|
||||
from MacroCall x, int getNumberOfAttrs, string hasPath, string hasTokenTree
|
||||
from MacroCall x, int getNumberOfAttrs, string hasPath, string hasTokenTree, string hasExpanded
|
||||
where
|
||||
toBeTested(x) and
|
||||
not x.isUnknown() and
|
||||
getNumberOfAttrs = x.getNumberOfAttrs() and
|
||||
(if x.hasPath() then hasPath = "yes" else hasPath = "no") and
|
||||
if x.hasTokenTree() then hasTokenTree = "yes" else hasTokenTree = "no"
|
||||
select x, "getNumberOfAttrs:", getNumberOfAttrs, "hasPath:", hasPath, "hasTokenTree:", hasTokenTree
|
||||
(if x.hasTokenTree() then hasTokenTree = "yes" else hasTokenTree = "no") and
|
||||
if x.hasExpanded() then hasExpanded = "yes" else hasExpanded = "no"
|
||||
select x, "getNumberOfAttrs:", getNumberOfAttrs, "hasPath:", hasPath, "hasTokenTree:", hasTokenTree,
|
||||
"hasExpanded:", hasExpanded
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| gen_macro_call.rs:5:5:5:11 | MacroCall | gen_macro_call.rs:5:5:5:11 | MacroStmts |
|
||||
7
rust/ql/test/extractor-tests/generated/MacroCall/MacroCall_getExpanded.ql
generated
Normal file
7
rust/ql/test/extractor-tests/generated/MacroCall/MacroCall_getExpanded.ql
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
// generated by codegen, do not edit
|
||||
import codeql.rust.elements
|
||||
import TestUtils
|
||||
|
||||
from MacroCall x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, x.getExpanded()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user