mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
Merge pull request #17805 from github/aibaars/local-defs
Rust: Rust: add jump to definition for format arguments
This commit is contained in:
126
rust/ql/lib/codeql/rust/internal/Definitions.qll
Normal file
126
rust/ql/lib/codeql/rust/internal/Definitions.qll
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Provides classes and predicates related to jump-to-definition links
|
||||
* in the code viewer.
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.Variable
|
||||
private import codeql.rust.elements.Locatable
|
||||
private import codeql.rust.elements.FormatArgsExpr
|
||||
private import codeql.rust.elements.FormatArgsArg
|
||||
private import codeql.rust.elements.Format
|
||||
private import codeql.rust.elements.MacroCall
|
||||
private import codeql.rust.elements.NamedFormatArgument
|
||||
private import codeql.rust.elements.PositionalFormatArgument
|
||||
private import codeql.Locations
|
||||
|
||||
/** An element with an associated definition. */
|
||||
abstract class Use extends Locatable {
|
||||
/** Gets the definition associated with this element. */
|
||||
abstract Definition getDefinition();
|
||||
|
||||
/**
|
||||
* Gets the type of use.
|
||||
*/
|
||||
abstract string getUseType();
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TDef =
|
||||
TVariable(Variable v) or
|
||||
TFormatArgsArgName(Name name) { name = any(FormatArgsArg a).getName() } or
|
||||
TFormatArgsArgIndex(Expr e) { e = any(FormatArgsArg a).getExpr() }
|
||||
|
||||
/**
|
||||
* Gets an element, of kind `kind`, that element `use` uses, if any.
|
||||
*/
|
||||
cached
|
||||
Definition definitionOf(Use use, string kind) {
|
||||
result = use.getDefinition() and
|
||||
kind = use.getUseType() and
|
||||
not result.getLocation() = any(MacroCall m).getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
predicate definitionOf = Cached::definitionOf/2;
|
||||
|
||||
/** A definition */
|
||||
class Definition extends Cached::TDef {
|
||||
/** Gets the location of this variable. */
|
||||
Location getLocation() {
|
||||
result = this.asVariable().getLocation() or
|
||||
result = this.asName().getLocation() or
|
||||
result = this.asExpr().getLocation()
|
||||
}
|
||||
|
||||
/** Gets this definition as a `Variable` */
|
||||
Variable asVariable() { this = Cached::TVariable(result) }
|
||||
|
||||
/** Gets this definition as a `Name` */
|
||||
Name asName() { this = Cached::TFormatArgsArgName(result) }
|
||||
|
||||
/** Gets this definition as an `Expr` */
|
||||
Expr asExpr() { this = Cached::TFormatArgsArgIndex(result) }
|
||||
|
||||
/** Gets the string representation of this element. */
|
||||
string toString() {
|
||||
result = this.asExpr().toString() or
|
||||
result = this.asVariable().toString() or
|
||||
result = this.asName().getText()
|
||||
}
|
||||
}
|
||||
|
||||
private class LocalVariableUse extends Use instanceof VariableAccess {
|
||||
private Variable def;
|
||||
|
||||
LocalVariableUse() { this = def.getAnAccess() }
|
||||
|
||||
override Definition getDefinition() { result.asVariable() = def }
|
||||
|
||||
override string getUseType() { result = "local variable" }
|
||||
}
|
||||
|
||||
private class NamedFormatArgumentUse extends Use instanceof NamedFormatArgument {
|
||||
private Name def;
|
||||
|
||||
NamedFormatArgumentUse() {
|
||||
exists(FormatArgsExpr parent |
|
||||
parent = this.getParent().getParent() and
|
||||
parent.getAnArg().getName() = def and
|
||||
this.getName() = def.getText()
|
||||
)
|
||||
}
|
||||
|
||||
override Definition getDefinition() { result.asName() = def }
|
||||
|
||||
override string getUseType() { result = "format argument" }
|
||||
}
|
||||
|
||||
private class PositionalFormatUse extends Use instanceof Format {
|
||||
PositionalFormatUse() { not exists(this.getArgumentRef()) }
|
||||
|
||||
override Definition getDefinition() {
|
||||
exists(FormatArgsExpr parent, int index | parent.getFormat(_) = this |
|
||||
this = rank[index + 1](PositionalFormatUse f, int i | parent.getFormat(i) = f | f order by i) and
|
||||
result.asExpr() = parent.getArg(index).getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override string getUseType() { result = "format argument" }
|
||||
}
|
||||
|
||||
private class PositionalFormatArgumentUse extends Use instanceof PositionalFormatArgument {
|
||||
private Expr def;
|
||||
|
||||
PositionalFormatArgumentUse() {
|
||||
exists(FormatArgsExpr parent |
|
||||
parent = this.getParent().getParent() and
|
||||
def = parent.getArg(this.getIndex()).getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override Definition getDefinition() { result.asExpr() = def }
|
||||
|
||||
override string getUseType() { result = "format argument" }
|
||||
}
|
||||
@@ -3,21 +3,17 @@
|
||||
* @description Generates use-definition pairs that provide the data
|
||||
* for jump-to-definition in the code viewer.
|
||||
* @kind definitions
|
||||
* @id rus/ide-jump-to-definition
|
||||
* @id rust/ide-jump-to-definition
|
||||
* @tags ide-contextual-queries/local-definitions
|
||||
*/
|
||||
|
||||
import codeql.IDEContextual
|
||||
import codeql.rust.elements.Variable
|
||||
import codeql.rust.elements.Locatable
|
||||
import codeql.rust.internal.Definitions
|
||||
|
||||
external string selectedSourceFile();
|
||||
|
||||
predicate localVariable(Locatable e, Variable def) { e = def.getAnAccess() }
|
||||
|
||||
from Locatable e, Variable def, string kind
|
||||
from Use use, Definition def, string kind
|
||||
where
|
||||
e.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile()) and
|
||||
localVariable(e, def) and
|
||||
kind = "local variable"
|
||||
select e, def, kind
|
||||
def = definitionOf(use, kind) and
|
||||
use.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
select use, def, kind
|
||||
|
||||
19
rust/ql/lib/ide-contextual-queries/localReferences.ql
Normal file
19
rust/ql/lib/ide-contextual-queries/localReferences.ql
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name Find-references links
|
||||
* @description Generates use-definition pairs that provide the data
|
||||
* for find-references in the code viewer.
|
||||
* @kind definitions
|
||||
* @id rust/ide-find-references
|
||||
* @tags ide-contextual-queries/local-references
|
||||
*/
|
||||
|
||||
import codeql.IDEContextual
|
||||
import codeql.rust.internal.Definitions
|
||||
|
||||
external string selectedSourceFile();
|
||||
|
||||
from Use use, Definition def, string kind
|
||||
where
|
||||
def = definitionOf(use, kind) and
|
||||
def.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
select use, def, kind
|
||||
19
rust/ql/test/library-tests/definitions/Definitions.expected
Normal file
19
rust/ql/test/library-tests/definitions/Definitions.expected
Normal file
@@ -0,0 +1,19 @@
|
||||
| main.rs:2:9:2:13 | width | main.rs:5:29:5:33 | width | local variable |
|
||||
| main.rs:2:9:2:13 | width | main.rs:6:41:6:45 | width | local variable |
|
||||
| main.rs:2:9:2:13 | width | main.rs:7:36:7:40 | width | local variable |
|
||||
| main.rs:3:9:3:17 | precision | main.rs:5:36:5:44 | precision | local variable |
|
||||
| main.rs:3:9:3:17 | precision | main.rs:6:48:6:56 | precision | local variable |
|
||||
| main.rs:4:9:4:13 | value | main.rs:6:34:6:38 | value | local variable |
|
||||
| main.rs:4:9:4:13 | value | main.rs:7:29:7:33 | value | local variable |
|
||||
| main.rs:5:50:5:54 | value | main.rs:5:22:5:26 | value | format argument |
|
||||
| main.rs:6:34:6:38 | value | main.rs:6:22:6:22 | 0 | format argument |
|
||||
| main.rs:6:41:6:45 | width | main.rs:6:25:6:25 | 1 | format argument |
|
||||
| main.rs:6:48:6:56 | precision | main.rs:6:28:6:28 | 2 | format argument |
|
||||
| main.rs:7:29:7:33 | value | main.rs:7:21:7:22 | {} | format argument |
|
||||
| main.rs:7:36:7:40 | width | main.rs:7:24:7:25 | {} | format argument |
|
||||
| main.rs:8:9:8:14 | people | main.rs:9:22:9:27 | people | local variable |
|
||||
| main.rs:10:31:10:31 | 1 | main.rs:10:19:10:20 | {} | format argument |
|
||||
| main.rs:10:31:10:31 | 1 | main.rs:10:23:10:23 | 0 | format argument |
|
||||
| main.rs:10:34:10:34 | 2 | main.rs:10:16:10:16 | 1 | format argument |
|
||||
| main.rs:10:34:10:34 | 2 | main.rs:10:26:10:27 | {} | format argument |
|
||||
| main.rs:11:40:11:42 | "x" | main.rs:11:31:11:35 | {:<5} | format argument |
|
||||
5
rust/ql/test/library-tests/definitions/Definitions.ql
Normal file
5
rust/ql/test/library-tests/definitions/Definitions.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import codeql.rust.internal.Definitions
|
||||
|
||||
from Definition def, Use use, string kind
|
||||
where def = definitionOf(use, kind)
|
||||
select def, use, kind
|
||||
12
rust/ql/test/library-tests/definitions/main.rs
Normal file
12
rust/ql/test/library-tests/definitions/main.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
fn main() {
|
||||
let width = 4;
|
||||
let precision = 2;
|
||||
let value = 10;
|
||||
println!("Value {value:#width$.precision$}", value = 10.5);
|
||||
println!("Value {0:#1$.2$}", value, width, precision);
|
||||
println!("Value {} {}", value, width);
|
||||
let people = "Rustaceans";
|
||||
println!("Hello {people}!");
|
||||
println!("{1} {} {0} {}", 1, 2);
|
||||
assert_eq!(format!("Hello {:<5}!", "x"), "Hello x !");
|
||||
}
|
||||
Reference in New Issue
Block a user