Merge branch 'main' into idrissrio/preprocessor-multiline

This commit is contained in:
idrissrio
2025-03-24 15:17:00 +01:00
31 changed files with 530 additions and 242 deletions

View File

@@ -109,7 +109,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
if (checkNugetFeedResponsiveness && !CheckFeeds(out explicitFeeds))
{
// todo: we could also check the reachability of the inherited nuget feeds, but to use those in the fallback we would need to handle authentication too.
var unresponsiveMissingPackageLocation = DownloadMissingPackagesFromSpecificFeeds(explicitFeeds);
var unresponsiveMissingPackageLocation = DownloadMissingPackagesFromSpecificFeeds([], explicitFeeds);
return unresponsiveMissingPackageLocation is null
? []
: [unresponsiveMissingPackageLocation];
@@ -166,11 +166,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
.ToList();
assemblyLookupLocations.UnionWith(paths.Select(p => new AssemblyLookupLocation(p)));
LogAllUnusedPackages(dependencies);
var usedPackageNames = GetAllUsedPackageDirNames(dependencies);
var missingPackageLocation = checkNugetFeedResponsiveness
? DownloadMissingPackagesFromSpecificFeeds(explicitFeeds)
: DownloadMissingPackages();
? DownloadMissingPackagesFromSpecificFeeds(usedPackageNames, explicitFeeds)
: DownloadMissingPackages(usedPackageNames);
if (missingPackageLocation is not null)
{
@@ -297,21 +297,21 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
compilationInfoContainer.CompilationInfos.Add(("Failed project restore with package source error", nugetSourceFailures.ToString()));
}
private AssemblyLookupLocation? DownloadMissingPackagesFromSpecificFeeds(HashSet<string>? feedsFromNugetConfigs)
private AssemblyLookupLocation? DownloadMissingPackagesFromSpecificFeeds(IEnumerable<string> usedPackageNames, HashSet<string>? feedsFromNugetConfigs)
{
var reachableFallbackFeeds = GetReachableFallbackNugetFeeds(feedsFromNugetConfigs);
if (reachableFallbackFeeds.Count > 0)
{
return DownloadMissingPackages(fallbackNugetFeeds: reachableFallbackFeeds);
return DownloadMissingPackages(usedPackageNames, fallbackNugetFeeds: reachableFallbackFeeds);
}
logger.LogWarning("Skipping download of missing packages from specific feeds as no fallback Nuget feeds are reachable.");
return null;
}
private AssemblyLookupLocation? DownloadMissingPackages(IEnumerable<string>? fallbackNugetFeeds = null)
private AssemblyLookupLocation? DownloadMissingPackages(IEnumerable<string> usedPackageNames, IEnumerable<string>? fallbackNugetFeeds = null)
{
var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames(PackageDirectory.DirInfo);
var alreadyDownloadedPackages = usedPackageNames.Select(p => p.ToLowerInvariant());
var alreadyDownloadedLegacyPackages = GetRestoredLegacyPackageNames();
var notYetDownloadedPackages = new HashSet<PackageReference>(fileContent.AllPackages);
@@ -418,17 +418,23 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return nugetConfig;
}
private void LogAllUnusedPackages(DependencyContainer dependencies)
private IEnumerable<string> GetAllUsedPackageDirNames(DependencyContainer dependencies)
{
var allPackageDirectories = GetAllPackageDirectories();
logger.LogInfo($"Restored {allPackageDirectories.Count} packages");
logger.LogInfo($"Found {dependencies.Packages.Count} packages in project.assets.json files");
allPackageDirectories
.Where(package => !dependencies.Packages.Contains(package))
var usage = allPackageDirectories.Select(package => (package, isUsed: dependencies.Packages.Contains(package)));
usage
.Where(package => !package.isUsed)
.Order()
.ForEach(package => logger.LogDebug($"Unused package: {package}"));
.ForEach(package => logger.LogDebug($"Unused package: {package.package}"));
return usage
.Where(package => package.isUsed)
.Select(package => package.package);
}
private ICollection<string> GetAllPackageDirectories()

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved dependency resolution in `build-mode: none` extraction to handle failing `dotnet restore` processes that managed to download a subset of the dependencies before the failure.

View File

@@ -1,7 +1,7 @@
use lib::a_module::hello;
use lib::a_module::hello; // $ item=HELLO
mod a_module;
fn main() {
hello();
hello(); // $ item=HELLO
}

View File

@@ -1,3 +1,3 @@
pub fn hello() {
println!("Hello, world!");
}
} // HELLO

View File

@@ -0,0 +1 @@
import utils.test.PathResolutionInlineExpectationsTest

View File

@@ -2,14 +2,23 @@
"sysroot_src": "filled by the rust_project fixture",
"crates": [
{
"display_name": "exe",
"version": "0.1.0",
"root_module": "exe/src/main.rs",
"edition": "2021",
"deps": [{"crate": 1, "name": "lib"}]
"deps": [
{
"crate": 1,
"name": "lib"
}
]
},
{
"display_name": "lib",
"version": "0.1.0",
"root_module": "lib/src/lib.rs",
"edition": "2021",
"deps": []
}
]
}
}

View File

@@ -1,4 +1,4 @@
| Elements extracted | 87 |
| Elements extracted | 90 |
| Elements unextracted | 0 |
| Extraction errors | 0 |
| Extraction warnings | 0 |

View File

@@ -1,4 +1,4 @@
| Elements extracted | 87 |
| Elements extracted | 90 |
| Elements unextracted | 0 |
| Extraction errors | 0 |
| Extraction warnings | 0 |

View File

@@ -13,6 +13,7 @@ private import codeql.rust.elements.internal.generated.Crate
module Impl {
private import rust
private import codeql.rust.elements.internal.NamedCrate
private import codeql.rust.internal.PathResolution
class Crate extends Generated::Crate {
override string toStringImpl() {
@@ -58,6 +59,14 @@ module Impl {
*/
Crate getADependency() { result = this.getDependency(_) }
/** Gets the source file that defines this crate, if any. */
SourceFile getSourceFile() { result.getFile() = this.getModule().getFile() }
/**
* Gets a source file that belongs to this crate, if any.
*/
SourceFile getASourceFile() { result = this.(CrateItemNode).getASourceFile() }
override Location getLocation() { result = this.getModule().getLocation() }
}
}

View File

@@ -23,7 +23,7 @@ module Impl {
*/
class FieldExpr extends Generated::FieldExpr {
/** Gets the record field that this access references, if any. */
StructField getStructField() { result = TypeInference::resolveRecordFieldExpr(this) }
StructField getStructField() { result = TypeInference::resolveStructFieldExpr(this) }
/** Gets the tuple field that this access references, if any. */
TupleField getTupleField() { result = TypeInference::resolveTupleFieldExpr(this) }

View File

@@ -43,6 +43,6 @@ module Impl {
* Empty structs are considered to use record fields.
*/
pragma[nomagic]
predicate isRecord() { not this.isTuple() }
predicate isStruct() { not this.isTuple() }
}
}

View File

@@ -38,12 +38,12 @@ module Impl {
predicate isTuple() { this.getFieldList() instanceof TupleFieldList }
/**
* Holds if this variant uses record fields.
* Holds if this variant uses struct fields.
*
* Empty variants are considered to use record fields.
* Empty variants are considered to use struct fields.
*/
pragma[nomagic]
predicate isRecord() { not this.isTuple() }
predicate isStruct() { not this.isTuple() }
/** Gets the enum that this variant belongs to. */
Enum getEnum() { this = result.getVariantList().getAVariant() }

View File

@@ -73,7 +73,7 @@ final class Namespace extends TNamespace {
* - https://doc.rust-lang.org/reference/visibility-and-privacy.html
* - https://doc.rust-lang.org/reference/names/namespaces.html
*/
abstract class ItemNode extends AstNode {
abstract class ItemNode extends Locatable {
/** Gets the (original) name of this item. */
abstract string getName();
@@ -109,7 +109,11 @@ abstract class ItemNode extends AstNode {
/** Gets the immediately enclosing module (or source file) of this item. */
pragma[nomagic]
ModuleLikeNode getImmediateParentModule() { this = result.getAnItemInScope() }
ModuleLikeNode getImmediateParentModule() {
this = result.getAnItemInScope()
or
result = this.(SourceFileItemNode).getSuper()
}
pragma[nomagic]
private ItemNode getASuccessorRec(string name) {
@@ -122,6 +126,10 @@ abstract class ItemNode extends AstNode {
or
useImportEdge(this, name, result)
or
crateDefEdge(this, name, result)
or
crateDependencyEdge(this, name, result)
or
// items made available through `use` are available to nodes that contain the `use`
exists(UseItemNode use |
use = this.getASuccessorRec(_) and
@@ -168,19 +176,18 @@ abstract class ItemNode extends AstNode {
result = this.getASuccessorRec(name)
or
name = "super" and
if this instanceof Module
if this instanceof Module or this instanceof SourceFile
then result = this.getImmediateParentModule()
else result = this.getImmediateParentModule().getImmediateParentModule()
or
name = "self" and
not this instanceof Module and
result = this.getImmediateParentModule()
if this instanceof Module then result = this else result = this.getImmediateParentModule()
or
name = "Self" and
this = result.(ImplOrTraitItemNode).getAnItemInSelfScope()
or
name = "crate" and
result.(SourceFileItemNode).getFile() = this.getFile()
this = result.(CrateItemNode).getASourceFile()
}
/** Gets the location of this item. */
@@ -203,6 +210,11 @@ abstract private class ModuleLikeNode extends ItemNode {
}
private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
pragma[nomagic]
ModuleLikeNode getSuper() {
result = any(ModuleItemNode mod | fileImport(mod, this)).getASuccessor("super")
}
override string getName() { result = "(source file)" }
override Namespace getNamespace() {
@@ -211,6 +223,55 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
override Visibility getVisibility() { none() }
override predicate isPublic() { any() }
override TypeParam getTypeParam(int i) { none() }
}
class CrateItemNode extends ItemNode instanceof Crate {
/**
* Gets the module node that defines this crate.
*
* This is either a source file, when the crate is defined in source code,
* or a module, when the crate is defined in a dependency.
*/
pragma[nomagic]
ModuleLikeNode getModuleNode() {
result = super.getSourceFile()
or
not exists(super.getSourceFile()) and
result = super.getModule()
}
/**
* Gets a source file that belongs to this crate, if any.
*
* This is calculated as those source files that can be reached from the entry
* file of this crate using zero or more `mod` imports, without going through
* the entry point of some other crate.
*/
pragma[nomagic]
SourceFileItemNode getASourceFile() {
result = super.getSourceFile()
or
exists(SourceFileItemNode mid, Module mod |
mid = this.getASourceFile() and
mod.getFile() = mid.getFile() and
fileImport(mod, result) and
not result = any(Crate other).getSourceFile()
)
}
override string getName() { result = Crate.super.getName() }
override Namespace getNamespace() {
result.isType() // can be referenced with `crate`
}
override Visibility getVisibility() { none() }
override predicate isPublic() { any() }
override TypeParam getTypeParam(int i) { none() }
}
@@ -460,7 +521,7 @@ private class UseItemNode extends ItemNode instanceof Use {
override Namespace getNamespace() { none() }
override Visibility getVisibility() { none() }
override Visibility getVisibility() { result = Use.super.getVisibility() }
override TypeParam getTypeParam(int i) { none() }
}
@@ -586,11 +647,33 @@ private predicate fileImport(Module m, SourceFile f) {
* Holds if `mod` is a `mod name;` item targeting a file resulting in `item` being
* in scope under the name `name`.
*/
pragma[nomagic]
private predicate fileImportEdge(Module mod, string name, ItemNode item) {
item.isPublic() and
exists(SourceFile f |
exists(SourceFileItemNode f |
fileImport(mod, f) and
sourceFileEdge(f, name, item)
item = f.getASuccessor(name)
)
}
/**
* Holds if crate `c` defines the item `i` named `name`.
*/
pragma[nomagic]
private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
i = c.getModuleNode().getASuccessor(name) and
not i instanceof Crate
}
/**
* Holds if `m` depends on crate `dep` named `name`.
*/
private predicate crateDependencyEdge(ModuleLikeNode m, string name, CrateItemNode dep) {
exists(CrateItemNode c | dep = c.(Crate).getDependency(name) |
// entry module/entry source file
m = c.getModuleNode()
or
// entry/transitive source file
m = c.getASourceFile()
)
}
@@ -745,13 +828,53 @@ private predicate pathUsesNamespace(Path p, Namespace n) {
)
}
/** Gets the item that `path` resolves to, if any. */
cached
ItemNode resolvePath(RelevantPath path) {
pragma[nomagic]
private ItemNode resolvePath1(RelevantPath path) {
exists(Namespace ns | result = resolvePath0(path, ns) |
pathUsesNamespace(path, ns)
or
not pathUsesNamespace(path, _)
not pathUsesNamespace(path, _) and
not path = any(MacroCall mc).getPath()
)
}
pragma[nomagic]
private ItemNode resolvePathPrivate(
RelevantPath path, ModuleLikeNode itemParent, ModuleLikeNode pathParent
) {
result = resolvePath1(path) and
itemParent = result.getImmediateParentModule() and
not result.isPublic() and
(
pathParent.getADescendant() = path
or
pathParent = any(ItemNode mid | path = mid.getADescendant()).getImmediateParentModule()
)
}
/**
* Gets a module that has access to private items defined inside `itemParent`.
*
* According to [The Rust Reference][1] this is either `itemParent` itself or any
* descendant of `itemParent`.
*
* [1]: https://doc.rust-lang.org/reference/visibility-and-privacy.html#r-vis.access
*/
pragma[nomagic]
private ModuleLikeNode getAPrivateVisibleModule(ModuleLikeNode itemParent) {
exists(resolvePathPrivate(_, itemParent, _)) and
result.getImmediateParentModule*() = itemParent
}
/** Gets the item that `path` resolves to, if any. */
cached
ItemNode resolvePath(RelevantPath path) {
result = resolvePath1(path) and
result.isPublic()
or
exists(ModuleLikeNode itemParent, ModuleLikeNode pathParent |
result = resolvePathPrivate(path, itemParent, pathParent) and
pathParent = getAPrivateVisibleModule(itemParent)
)
}
@@ -831,3 +954,44 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
name != "_"
)
}
/** Provides predicates for debugging the path resolution implementation. */
private module Debug {
private Locatable getRelevantLocatable() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
filepath.matches("%/main.rs") and
startline = 1
)
}
predicate debugUnqualifiedPathLookup(RelevantPath p, string name, Namespace ns, ItemNode encl) {
p = getRelevantLocatable() and
unqualifiedPathLookup(p, name, ns, encl)
}
ItemNode debugResolvePath(RelevantPath path) {
path = getRelevantLocatable() and
result = resolvePath(path)
}
predicate debugUseImportEdge(Use use, string name, ItemNode item) {
use = getRelevantLocatable() and
useImportEdge(use, name, item)
}
ItemNode debugGetASuccessorRec(ItemNode i, string name) {
i = getRelevantLocatable() and
result = i.getASuccessor(name)
}
predicate debugFileImportEdge(Module mod, string name, ItemNode item) {
mod = getRelevantLocatable() and
fileImportEdge(mod, name, item)
}
predicate debugFileImport(Module m, SourceFile f) {
m = getRelevantLocatable() and
fileImport(m, f)
}
}

View File

@@ -7,6 +7,7 @@ private import PathResolution
/** Holds if `p` may resolve to multiple items including `i`. */
query predicate multiplePathResolutions(Path p, ItemNode i) {
p.fromSource() and
i = resolvePath(p) and
// `use foo::bar` may use both a type `bar` and a value `bar`
not p =

View File

@@ -29,7 +29,7 @@ abstract class Type extends TType {
pragma[nomagic]
abstract Function getMethod(string name);
/** Gets the record field `name` belonging to this type, if any. */
/** Gets the struct field `name` belonging to this type, if any. */
pragma[nomagic]
abstract StructField getStructField(string name);

View File

@@ -248,24 +248,24 @@ private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) {
}
/**
* A matching configuration for resolving types of record expressions
* A matching configuration for resolving types of struct expressions
* like `Foo { bar = baz }`.
*/
private module StructExprMatchingInput implements MatchingInputSig {
private newtype TPos =
TFieldPos(string name) { exists(any(Declaration decl).getField(name)) } or
TRecordPos()
TStructPos()
class DeclarationPosition extends TPos {
string asFieldPos() { this = TFieldPos(result) }
predicate isRecordPos() { this = TRecordPos() }
predicate isStructPos() { this = TStructPos() }
string toString() {
result = this.asFieldPos()
or
this.isRecordPos() and
result = "(record)"
this.isStructPos() and
result = "(struct)"
}
}
@@ -286,15 +286,15 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = tp.resolveTypeAt(path)
)
or
// type parameter of the record itself
dpos.isRecordPos() and
// type parameter of the struct itself
dpos.isStructPos() and
result = this.getTypeParameter(_) and
path = TypePath::singleton(result)
}
}
private class RecordStructDecl extends Declaration, Struct {
RecordStructDecl() { this.isRecord() }
private class StructDecl extends Declaration, Struct {
StructDecl() { this.isStruct() }
override TypeParam getATypeParam() { result = this.getGenericParamList().getATypeParam() }
@@ -304,14 +304,14 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = super.getDeclaredType(dpos, path)
or
// type of the struct itself
dpos.isRecordPos() and
dpos.isStructPos() and
path.isEmpty() and
result = TStruct(this)
}
}
private class RecordVariantDecl extends Declaration, Variant {
RecordVariantDecl() { this.isRecord() }
private class StructVariantDecl extends Declaration, Variant {
StructVariantDecl() { this.isStruct() }
Enum getEnum() { result.getVariantList().getAVariant() = this }
@@ -325,7 +325,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = super.getDeclaredType(dpos, path)
or
// type of the enum itself
dpos.isRecordPos() and
dpos.isStructPos() and
path.isEmpty() and
result = TEnum(this.getEnum())
}
@@ -342,7 +342,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = this.getFieldExpr(apos.asFieldPos()).getExpr()
or
result = this and
apos.isRecordPos()
apos.isStructPos()
}
Type getInferredType(AccessPosition apos, TypePath path) {
@@ -360,8 +360,8 @@ private module StructExprMatchingInput implements MatchingInputSig {
private module StructExprMatching = Matching<StructExprMatchingInput>;
/**
* Gets the type of `n` at `path`, where `n` is either a record expression or
* a field expression of a record expression.
* Gets the type of `n` at `path`, where `n` is either a struct expression or
* a field expression of a struct expression.
*/
pragma[nomagic]
private Type inferStructExprType(AstNode n, TypePath path) {
@@ -777,7 +777,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
Declaration getTarget() {
// mutual recursion; resolving fields requires resolving types and vice versa
result = [resolveRecordFieldExpr(this).(AstNode), resolveTupleFieldExpr(this)]
result = [resolveStructFieldExpr(this).(AstNode), resolveTupleFieldExpr(this)]
}
}
@@ -921,10 +921,10 @@ private module Cached {
}
/**
* Gets the record field that the field expression `fe` resolves to, if any.
* Gets the struct field that the field expression `fe` resolves to, if any.
*/
cached
StructField resolveRecordFieldExpr(FieldExpr fe) {
StructField resolveStructFieldExpr(FieldExpr fe) {
exists(string name | result = getFieldExprLookupType(fe, name).getStructField(name))
}

View File

@@ -0,0 +1,48 @@
/**
* Provides an inline expectations test for path resolution.
*/
private import rust
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.TypeInference
private import utils.test.InlineExpectationsTest
private module ResolveTest implements TestSig {
string getARelevantTag() { result = "item" }
private predicate itemAt(ItemNode i, string filepath, int line, boolean inMacro) {
i.getLocation().hasLocationInfo(filepath, _, _, line, _) and
if i.(AstNode).isInMacroExpansion() then inMacro = true else inMacro = false
}
private predicate commmentAt(string text, string filepath, int line) {
exists(Comment c |
c.getLocation().hasLocationInfo(filepath, line, _, _, _) and
c.getCommentText() = text
)
}
private predicate item(ItemNode i, string value) {
exists(string filepath, int line, boolean inMacro | itemAt(i, filepath, line, inMacro) |
commmentAt(value, filepath, line) and inMacro = false
or
not (commmentAt(_, filepath, line) and inMacro = false) and
value = i.getName()
)
}
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(AstNode n |
not n = any(Path parent).getQualifier() and
location = n.getLocation() and
element = n.toString() and
tag = "item"
|
item(resolvePath(n), value)
or
item(n.(MethodCallExpr).getStaticTarget(), value)
)
}
}
import MakeTest<ResolveTest>

View File

@@ -59,6 +59,19 @@ private module Compare<ResolvableSig R, CompareSig<R> RustAnalyzer, CompareSig<R
predicate qlUniqueCount(int c) { c = count(Source s | qlUnique(s)) }
// debug predicates to find missing targets in QL implementation
private module Debug {
predicate qlMissing(Source s, Target t) {
t = RustAnalyzer::resolve(s) and
not t = Ql::resolve(s)
}
predicate qlMissingWithCount(Source s, Target t, int c) {
qlMissing(s, t) and
c = strictcount(Source s0 | qlMissing(s0, t))
}
}
predicate summary(string key, int value) {
key = "rust-analyzer unique" and rustAnalyzerUniqueCount(value)
or

View File

@@ -0,0 +1,3 @@
multipleStaticCallTargets
| regular.rs:29:5:29:9 | s.g(...) | anonymous.rs:15:9:15:22 | fn g |
| regular.rs:29:5:29:9 | s.g(...) | regular.rs:13:5:13:18 | fn g |

View File

@@ -0,0 +1,3 @@
multipleStaticCallTargets
| regular.rs:32:5:32:9 | s.g(...) | anonymous.rs:18:9:18:22 | fn g |
| regular.rs:32:5:32:9 | s.g(...) | regular.rs:16:5:16:18 | fn g |

View File

@@ -495,4 +495,7 @@ fn main() {
m15::f(); // $ item=I75
m16::f(); // $ item=I83
m17::f(); // $ item=I99
nested6::f(); // $ item=I116
nested8::f(); // $ item=I119
my3::f(); // $ item=I200
}

View File

@@ -1,6 +1,12 @@
pub mod nested2; // I8
fn g() {
println!("mod.rs::g");
println!("my2/mod.rs::g");
nested2::nested3::nested4::f(); // $ item=I12
} // I9
pub use nested2::nested5::*; // $ item=I114
pub use nested2::nested7::nested8::{self}; // $ item=I118
pub mod my3;

View File

@@ -0,0 +1,8 @@
pub fn f() {
println!("my2/my3/mod.rs::f");
g(); // $ item=I9
h(); // $ item=I25
} // I200
use super::super::h; // $ item=I25
use super::g; // $ item=I9

View File

@@ -9,3 +9,19 @@ pub mod nested3 {
} // I13
} // I11
} // I10
pub mod nested5 {
pub mod nested6 {
pub fn f() {
println!("nested2.rs::nested5::nested6::f");
} // I116
} // I115
} // I114
pub mod nested7 {
pub mod nested8 {
pub fn f() {
println!("nested2.rs::nested7::nested8::f");
} // I119
} // I118
} // I117

View File

@@ -22,8 +22,13 @@ mod
| main.rs:350:1:442:1 | mod m16 |
| main.rs:444:1:474:1 | mod m17 |
| my2/mod.rs:1:1:1:16 | mod nested2 |
| my2/mod.rs:12:1:12:12 | mod my3 |
| my2/nested2.rs:1:1:11:1 | mod nested3 |
| my2/nested2.rs:2:5:10:5 | mod nested4 |
| my2/nested2.rs:13:1:19:1 | mod nested5 |
| my2/nested2.rs:14:5:18:5 | mod nested6 |
| my2/nested2.rs:21:1:27:1 | mod nested7 |
| my2/nested2.rs:22:5:26:5 | mod nested8 |
| my.rs:1:1:1:15 | mod nested |
| my/nested.rs:1:1:17:1 | mod nested1 |
| my/nested.rs:2:5:11:5 | mod nested2 |
@@ -46,7 +51,7 @@ resolvePath
| main.rs:30:17:30:21 | super | main.rs:18:5:36:5 | mod m2 |
| main.rs:30:17:30:24 | ...::f | main.rs:19:9:21:9 | fn f |
| main.rs:33:17:33:17 | f | main.rs:19:9:21:9 | fn f |
| main.rs:40:9:40:13 | super | main.rs:1:1:498:2 | SourceFile |
| main.rs:40:9:40:13 | super | main.rs:1:1:501:2 | SourceFile |
| main.rs:40:9:40:17 | ...::m1 | main.rs:13:1:37:1 | mod m1 |
| main.rs:40:9:40:21 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
| main.rs:40:9:40:24 | ...::g | main.rs:23:9:27:9 | fn g |
@@ -58,7 +63,7 @@ resolvePath
| main.rs:61:17:61:19 | Foo | main.rs:59:9:59:21 | struct Foo |
| main.rs:64:13:64:15 | Foo | main.rs:53:5:53:17 | struct Foo |
| main.rs:66:5:66:5 | f | main.rs:55:5:62:5 | fn f |
| main.rs:68:5:68:8 | self | main.rs:1:1:498:2 | SourceFile |
| main.rs:68:5:68:8 | self | main.rs:1:1:501:2 | SourceFile |
| main.rs:68:5:68:11 | ...::i | main.rs:71:1:83:1 | fn i |
| main.rs:74:13:74:15 | Foo | main.rs:48:1:48:13 | struct Foo |
| main.rs:81:17:81:19 | Foo | main.rs:77:9:79:9 | struct Foo |
@@ -72,7 +77,7 @@ resolvePath
| main.rs:87:57:87:66 | ...::g | my2/nested2.rs:7:9:9:9 | fn g |
| main.rs:87:80:87:86 | nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
| main.rs:100:5:100:22 | f_defined_in_macro | main.rs:99:18:99:42 | fn f_defined_in_macro |
| main.rs:117:13:117:17 | super | main.rs:1:1:498:2 | SourceFile |
| main.rs:117:13:117:17 | super | main.rs:1:1:501:2 | SourceFile |
| main.rs:117:13:117:21 | ...::m5 | main.rs:103:1:107:1 | mod m5 |
| main.rs:118:9:118:9 | f | main.rs:104:5:106:5 | fn f |
| main.rs:118:9:118:9 | f | main.rs:110:5:112:5 | fn f |
@@ -127,7 +132,7 @@ resolvePath
| main.rs:274:16:274:16 | T | main.rs:268:7:268:7 | T |
| main.rs:275:14:275:17 | Self | main.rs:266:5:276:5 | trait MyParamTrait |
| main.rs:275:14:275:33 | ...::AssociatedType | main.rs:270:9:270:28 | TypeAlias |
| main.rs:284:13:284:17 | crate | main.rs:1:1:498:2 | SourceFile |
| main.rs:284:13:284:17 | crate | main.rs:0:0:0:0 | Crate(main@0.0.1) |
| main.rs:284:13:284:22 | ...::m13 | main.rs:279:1:292:1 | mod m13 |
| main.rs:284:13:284:25 | ...::f | main.rs:280:5:280:17 | fn f |
| main.rs:284:13:284:25 | ...::f | main.rs:280:19:281:19 | struct f |
@@ -218,7 +223,7 @@ resolvePath
| main.rs:479:5:479:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f |
| main.rs:480:5:480:5 | f | my2/nested2.rs:3:9:5:9 | fn f |
| main.rs:481:5:481:5 | g | my2/nested2.rs:7:9:9:9 | fn g |
| main.rs:482:5:482:9 | crate | main.rs:1:1:498:2 | SourceFile |
| main.rs:482:5:482:9 | crate | main.rs:0:0:0:0 | Crate(main@0.0.1) |
| main.rs:482:5:482:12 | ...::h | main.rs:50:1:69:1 | fn h |
| main.rs:483:5:483:6 | m1 | main.rs:13:1:37:1 | mod m1 |
| main.rs:483:5:483:10 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
@@ -249,10 +254,29 @@ resolvePath
| main.rs:496:5:496:10 | ...::f | main.rs:417:5:441:5 | fn f |
| main.rs:497:5:497:7 | m17 | main.rs:444:1:474:1 | mod m17 |
| main.rs:497:5:497:10 | ...::f | main.rs:468:5:473:5 | fn f |
| main.rs:498:5:498:11 | nested6 | my2/nested2.rs:14:5:18:5 | mod nested6 |
| main.rs:498:5:498:14 | ...::f | my2/nested2.rs:15:9:17:9 | fn f |
| main.rs:499:5:499:11 | nested8 | my2/nested2.rs:22:5:26:5 | mod nested8 |
| main.rs:499:5:499:14 | ...::f | my2/nested2.rs:23:9:25:9 | fn f |
| main.rs:500:5:500:7 | my3 | my2/mod.rs:12:1:12:12 | mod my3 |
| main.rs:500:5:500:10 | ...::f | my2/my3/mod.rs:1:1:5:1 | fn f |
| my2/mod.rs:5:5:5:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
| my2/mod.rs:5:5:5:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
| my2/mod.rs:5:5:5:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
| my2/mod.rs:5:5:5:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f |
| my2/mod.rs:8:9:8:15 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
| my2/mod.rs:8:9:8:24 | ...::nested5 | my2/nested2.rs:13:1:19:1 | mod nested5 |
| my2/mod.rs:10:9:10:15 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
| my2/mod.rs:10:9:10:24 | ...::nested7 | my2/nested2.rs:21:1:27:1 | mod nested7 |
| my2/mod.rs:10:9:10:33 | ...::nested8 | my2/nested2.rs:22:5:26:5 | mod nested8 |
| my2/mod.rs:10:37:10:40 | self | my2/nested2.rs:22:5:26:5 | mod nested8 |
| my2/my3/mod.rs:3:5:3:5 | g | my2/mod.rs:3:1:6:1 | fn g |
| my2/my3/mod.rs:4:5:4:5 | h | main.rs:50:1:69:1 | fn h |
| my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:12:13 | SourceFile |
| my2/my3/mod.rs:7:5:7:16 | ...::super | main.rs:1:1:501:2 | SourceFile |
| my2/my3/mod.rs:7:5:7:19 | ...::h | main.rs:50:1:69:1 | fn h |
| my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:12:13 | SourceFile |
| my2/my3/mod.rs:8:5:8:12 | ...::g | my2/mod.rs:3:1:6:1 | fn g |
| my.rs:3:5:3:10 | nested | my.rs:1:1:1:15 | mod nested |
| my.rs:3:5:3:13 | ...::g | my/nested.rs:19:1:22:1 | fn g |
| my.rs:11:5:11:5 | g | my/nested.rs:19:1:22:1 | fn g |

View File

@@ -1,49 +1,8 @@
import rust
import codeql.rust.internal.PathResolution
import codeql.rust.internal.TypeInference
import utils.test.InlineExpectationsTest
import utils.test.PathResolutionInlineExpectationsTest
import TestUtils
query predicate mod(Module m) { toBeTested(m) }
query predicate resolvePath(Path p, ItemNode i) { toBeTested(p) and i = resolvePath(p) }
module ResolveTest implements TestSig {
string getARelevantTag() { result = "item" }
private predicate itemAt(ItemNode i, string filepath, int line, boolean inMacro) {
i.getLocation().hasLocationInfo(filepath, _, _, line, _) and
if i.isInMacroExpansion() then inMacro = true else inMacro = false
}
private predicate commmentAt(string text, string filepath, int line) {
exists(Comment c |
c.getLocation().hasLocationInfo(filepath, line, _, _, _) and
c.getCommentText() = text
)
}
private predicate item(ItemNode i, string value) {
exists(string filepath, int line, boolean inMacro | itemAt(i, filepath, line, inMacro) |
commmentAt(value, filepath, line) and inMacro = false
or
not (commmentAt(_, filepath, line) and inMacro = false) and
value = i.getName()
)
}
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(AstNode n |
not n = any(Path parent).getQualifier() and
location = n.getLocation() and
element = n.toString() and
tag = "item"
|
item(resolvePath(n), value)
or
item(n.(MethodCallExpr).getStaticTarget(), value)
)
}
}
import MakeTest<ResolveTest>

View File

@@ -255,8 +255,8 @@ mod type_parameter_bounds {
mod function_trait_bounds {
#[derive(Debug)]
struct MyThing<A> {
a: A,
struct MyThing<T> {
a: T,
}
#[derive(Debug)]
@@ -387,12 +387,12 @@ mod method_supertraits {
#[derive(Debug)]
struct S2;
trait MyTrait1<A> {
fn m1(self) -> A;
trait MyTrait1<Tr1> {
fn m1(self) -> Tr1;
}
trait MyTrait2<A>: MyTrait1<A> {
fn m2(self) -> A
trait MyTrait2<Tr2>: MyTrait1<Tr2> {
fn m2(self) -> Tr2
where
Self: Sized,
{
@@ -404,8 +404,8 @@ mod method_supertraits {
}
}
trait MyTrait3<A>: MyTrait2<MyThing<A>> {
fn m3(self) -> A
trait MyTrait3<Tr3>: MyTrait2<MyThing<Tr3>> {
fn m3(self) -> Tr3
where
Self: Sized,
{

View File

@@ -337,69 +337,69 @@ inferType
| main.rs:279:9:279:9 | x | A | main.rs:278:22:278:23 | T1 |
| main.rs:279:9:279:14 | x.m1(...) | | main.rs:278:22:278:23 | T1 |
| main.rs:283:15:283:18 | SelfParam | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:283:15:283:18 | SelfParam | A | main.rs:282:10:282:10 | T |
| main.rs:283:15:283:18 | SelfParam | T | main.rs:282:10:282:10 | T |
| main.rs:283:26:285:9 | { ... } | | main.rs:282:10:282:10 | T |
| main.rs:284:13:284:16 | self | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:284:13:284:16 | self | A | main.rs:282:10:282:10 | T |
| main.rs:284:13:284:16 | self | T | main.rs:282:10:282:10 | T |
| main.rs:284:13:284:18 | self.a | | main.rs:282:10:282:10 | T |
| main.rs:289:13:289:13 | x | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:289:13:289:13 | x | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:289:13:289:13 | x | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:289:17:289:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:289:17:289:33 | MyThing {...} | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:289:17:289:33 | MyThing {...} | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:289:30:289:31 | S1 | | main.rs:262:5:263:14 | struct S1 |
| main.rs:290:13:290:13 | y | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:290:13:290:13 | y | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:290:13:290:13 | y | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:290:17:290:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:290:17:290:33 | MyThing {...} | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:290:17:290:33 | MyThing {...} | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:290:30:290:31 | S2 | | main.rs:264:5:265:14 | struct S2 |
| main.rs:292:26:292:26 | x | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:292:26:292:26 | x | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:292:26:292:26 | x | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:292:26:292:31 | x.m1(...) | | main.rs:262:5:263:14 | struct S1 |
| main.rs:293:26:293:26 | y | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:293:26:293:26 | y | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:293:26:293:26 | y | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:293:26:293:31 | y.m1(...) | | main.rs:264:5:265:14 | struct S2 |
| main.rs:295:13:295:13 | x | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:295:13:295:13 | x | | main.rs:267:5:276:5 | trait MyTrait |
| main.rs:295:13:295:13 | x | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:295:13:295:13 | x | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:295:13:295:13 | x | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:295:17:295:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:295:17:295:33 | MyThing {...} | | main.rs:267:5:276:5 | trait MyTrait |
| main.rs:295:17:295:33 | MyThing {...} | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:295:17:295:33 | MyThing {...} | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:295:17:295:33 | MyThing {...} | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:295:30:295:31 | S1 | | main.rs:262:5:263:14 | struct S1 |
| main.rs:296:13:296:13 | y | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:296:13:296:13 | y | | main.rs:267:5:276:5 | trait MyTrait |
| main.rs:296:13:296:13 | y | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:296:13:296:13 | y | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:296:13:296:13 | y | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:296:17:296:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:296:17:296:33 | MyThing {...} | | main.rs:267:5:276:5 | trait MyTrait |
| main.rs:296:17:296:33 | MyThing {...} | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:296:17:296:33 | MyThing {...} | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:296:17:296:33 | MyThing {...} | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:296:30:296:31 | S2 | | main.rs:264:5:265:14 | struct S2 |
| main.rs:298:26:298:26 | x | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:298:26:298:26 | x | | main.rs:267:5:276:5 | trait MyTrait |
| main.rs:298:26:298:26 | x | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:298:26:298:26 | x | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:298:26:298:26 | x | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:298:26:298:31 | x.m2(...) | | main.rs:262:5:263:14 | struct S1 |
| main.rs:299:26:299:26 | y | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:299:26:299:26 | y | | main.rs:267:5:276:5 | trait MyTrait |
| main.rs:299:26:299:26 | y | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:299:26:299:26 | y | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:299:26:299:26 | y | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:299:26:299:31 | y.m2(...) | | main.rs:264:5:265:14 | struct S2 |
| main.rs:301:13:301:13 | x | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:301:13:301:13 | x | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:301:13:301:13 | x | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:301:17:301:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:301:17:301:33 | MyThing {...} | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:301:17:301:33 | MyThing {...} | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:301:30:301:31 | S1 | | main.rs:262:5:263:14 | struct S1 |
| main.rs:302:13:302:13 | y | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:302:13:302:13 | y | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:302:13:302:13 | y | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:302:17:302:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:302:17:302:33 | MyThing {...} | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:302:17:302:33 | MyThing {...} | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:302:30:302:31 | S2 | | main.rs:264:5:265:14 | struct S2 |
| main.rs:304:40:304:40 | x | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:304:40:304:40 | x | A | main.rs:262:5:263:14 | struct S1 |
| main.rs:304:40:304:40 | x | T | main.rs:262:5:263:14 | struct S1 |
| main.rs:305:40:305:40 | y | | main.rs:257:5:260:5 | struct MyThing |
| main.rs:305:40:305:40 | y | A | main.rs:264:5:265:14 | struct S2 |
| main.rs:305:40:305:40 | y | T | main.rs:264:5:265:14 | struct S2 |
| main.rs:313:15:313:18 | SelfParam | | main.rs:310:5:322:5 | trait MyTrait |
| main.rs:315:15:315:18 | SelfParam | | main.rs:310:5:322:5 | trait MyTrait |
| main.rs:330:15:330:18 | SelfParam | | main.rs:324:5:325:13 | struct S |
@@ -442,50 +442,50 @@ inferType
| main.rs:370:26:370:26 | y | A | main.rs:353:5:354:14 | struct S2 |
| main.rs:370:26:370:31 | y.m1(...) | | main.rs:353:5:354:14 | struct S2 |
| main.rs:391:15:391:18 | SelfParam | | main.rs:390:5:392:5 | trait MyTrait1 |
| main.rs:391:15:391:18 | SelfParam | A | main.rs:390:20:390:20 | A |
| main.rs:391:15:391:18 | SelfParam | Tr1 | main.rs:390:20:390:22 | Tr1 |
| main.rs:395:15:395:18 | SelfParam | | main.rs:390:5:392:5 | trait MyTrait1 |
| main.rs:395:15:395:18 | SelfParam | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:395:15:395:18 | SelfParam | A | main.rs:394:20:394:20 | A |
| main.rs:395:15:395:18 | SelfParam | A | main.rs:394:20:394:20 | A |
| main.rs:398:9:404:9 | { ... } | | main.rs:394:20:394:20 | A |
| main.rs:399:13:403:13 | if ... {...} else {...} | | main.rs:394:20:394:20 | A |
| main.rs:399:26:401:13 | { ... } | | main.rs:394:20:394:20 | A |
| main.rs:395:15:395:18 | SelfParam | Tr1 | main.rs:394:20:394:22 | Tr2 |
| main.rs:395:15:395:18 | SelfParam | Tr2 | main.rs:394:20:394:22 | Tr2 |
| main.rs:398:9:404:9 | { ... } | | main.rs:394:20:394:22 | Tr2 |
| main.rs:399:13:403:13 | if ... {...} else {...} | | main.rs:394:20:394:22 | Tr2 |
| main.rs:399:26:401:13 | { ... } | | main.rs:394:20:394:22 | Tr2 |
| main.rs:400:17:400:20 | self | | main.rs:390:5:392:5 | trait MyTrait1 |
| main.rs:400:17:400:20 | self | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:400:17:400:20 | self | A | main.rs:394:20:394:20 | A |
| main.rs:400:17:400:20 | self | A | main.rs:394:20:394:20 | A |
| main.rs:400:17:400:25 | self.m1(...) | | main.rs:394:20:394:20 | A |
| main.rs:401:20:403:13 | { ... } | | main.rs:394:20:394:20 | A |
| main.rs:402:17:402:30 | ...::m1(...) | | main.rs:394:20:394:20 | A |
| main.rs:400:17:400:20 | self | Tr1 | main.rs:394:20:394:22 | Tr2 |
| main.rs:400:17:400:20 | self | Tr2 | main.rs:394:20:394:22 | Tr2 |
| main.rs:400:17:400:25 | self.m1(...) | | main.rs:394:20:394:22 | Tr2 |
| main.rs:401:20:403:13 | { ... } | | main.rs:394:20:394:22 | Tr2 |
| main.rs:402:17:402:30 | ...::m1(...) | | main.rs:394:20:394:22 | Tr2 |
| main.rs:402:26:402:29 | self | | main.rs:390:5:392:5 | trait MyTrait1 |
| main.rs:402:26:402:29 | self | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:402:26:402:29 | self | A | main.rs:394:20:394:20 | A |
| main.rs:402:26:402:29 | self | A | main.rs:394:20:394:20 | A |
| main.rs:402:26:402:29 | self | Tr1 | main.rs:394:20:394:22 | Tr2 |
| main.rs:402:26:402:29 | self | Tr2 | main.rs:394:20:394:22 | Tr2 |
| main.rs:408:15:408:18 | SelfParam | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:408:15:408:18 | SelfParam | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:408:15:408:18 | SelfParam | A | main.rs:375:5:378:5 | struct MyThing |
| main.rs:408:15:408:18 | SelfParam | A | main.rs:407:20:407:20 | A |
| main.rs:408:15:408:18 | SelfParam | A.A | main.rs:407:20:407:20 | A |
| main.rs:411:9:417:9 | { ... } | | main.rs:407:20:407:20 | A |
| main.rs:412:13:416:13 | if ... {...} else {...} | | main.rs:407:20:407:20 | A |
| main.rs:412:26:414:13 | { ... } | | main.rs:407:20:407:20 | A |
| main.rs:408:15:408:18 | SelfParam | Tr2 | main.rs:375:5:378:5 | struct MyThing |
| main.rs:408:15:408:18 | SelfParam | Tr2.A | main.rs:407:20:407:22 | Tr3 |
| main.rs:408:15:408:18 | SelfParam | Tr3 | main.rs:407:20:407:22 | Tr3 |
| main.rs:411:9:417:9 | { ... } | | main.rs:407:20:407:22 | Tr3 |
| main.rs:412:13:416:13 | if ... {...} else {...} | | main.rs:407:20:407:22 | Tr3 |
| main.rs:412:26:414:13 | { ... } | | main.rs:407:20:407:22 | Tr3 |
| main.rs:413:17:413:20 | self | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:413:17:413:20 | self | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:413:17:413:20 | self | A | main.rs:375:5:378:5 | struct MyThing |
| main.rs:413:17:413:20 | self | A | main.rs:407:20:407:20 | A |
| main.rs:413:17:413:20 | self | A.A | main.rs:407:20:407:20 | A |
| main.rs:413:17:413:20 | self | Tr2 | main.rs:375:5:378:5 | struct MyThing |
| main.rs:413:17:413:20 | self | Tr2.A | main.rs:407:20:407:22 | Tr3 |
| main.rs:413:17:413:20 | self | Tr3 | main.rs:407:20:407:22 | Tr3 |
| main.rs:413:17:413:25 | self.m2(...) | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:413:17:413:25 | self.m2(...) | A | main.rs:407:20:407:20 | A |
| main.rs:413:17:413:27 | ... .a | | main.rs:407:20:407:20 | A |
| main.rs:414:20:416:13 | { ... } | | main.rs:407:20:407:20 | A |
| main.rs:413:17:413:25 | self.m2(...) | A | main.rs:407:20:407:22 | Tr3 |
| main.rs:413:17:413:27 | ... .a | | main.rs:407:20:407:22 | Tr3 |
| main.rs:414:20:416:13 | { ... } | | main.rs:407:20:407:22 | Tr3 |
| main.rs:415:17:415:30 | ...::m2(...) | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:415:17:415:30 | ...::m2(...) | A | main.rs:407:20:407:20 | A |
| main.rs:415:17:415:32 | ... .a | | main.rs:407:20:407:20 | A |
| main.rs:415:17:415:30 | ...::m2(...) | A | main.rs:407:20:407:22 | Tr3 |
| main.rs:415:17:415:32 | ... .a | | main.rs:407:20:407:22 | Tr3 |
| main.rs:415:26:415:29 | self | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:415:26:415:29 | self | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:415:26:415:29 | self | A | main.rs:375:5:378:5 | struct MyThing |
| main.rs:415:26:415:29 | self | A | main.rs:407:20:407:20 | A |
| main.rs:415:26:415:29 | self | A.A | main.rs:407:20:407:20 | A |
| main.rs:415:26:415:29 | self | Tr2 | main.rs:375:5:378:5 | struct MyThing |
| main.rs:415:26:415:29 | self | Tr2.A | main.rs:407:20:407:22 | Tr3 |
| main.rs:415:26:415:29 | self | Tr3 | main.rs:407:20:407:22 | Tr3 |
| main.rs:421:15:421:18 | SelfParam | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:421:15:421:18 | SelfParam | A | main.rs:420:10:420:10 | T |
| main.rs:421:26:423:9 | { ... } | | main.rs:420:10:420:10 | T |
@@ -520,58 +520,58 @@ inferType
| main.rs:445:13:445:13 | x | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:445:13:445:13 | x | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:445:13:445:13 | x | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:445:13:445:13 | x | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:445:13:445:13 | x | Tr2 | main.rs:385:5:386:14 | struct S1 |
| main.rs:445:17:445:33 | MyThing {...} | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:445:17:445:33 | MyThing {...} | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:445:17:445:33 | MyThing {...} | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:445:17:445:33 | MyThing {...} | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:445:17:445:33 | MyThing {...} | Tr2 | main.rs:385:5:386:14 | struct S1 |
| main.rs:445:30:445:31 | S1 | | main.rs:385:5:386:14 | struct S1 |
| main.rs:446:13:446:13 | y | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:446:13:446:13 | y | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:446:13:446:13 | y | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:446:13:446:13 | y | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:446:13:446:13 | y | Tr2 | main.rs:387:5:388:14 | struct S2 |
| main.rs:446:17:446:33 | MyThing {...} | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:446:17:446:33 | MyThing {...} | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:446:17:446:33 | MyThing {...} | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:446:17:446:33 | MyThing {...} | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:446:17:446:33 | MyThing {...} | Tr2 | main.rs:387:5:388:14 | struct S2 |
| main.rs:446:30:446:31 | S2 | | main.rs:387:5:388:14 | struct S2 |
| main.rs:448:26:448:26 | x | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:448:26:448:26 | x | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:448:26:448:26 | x | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:448:26:448:26 | x | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:448:26:448:26 | x | Tr2 | main.rs:385:5:386:14 | struct S1 |
| main.rs:448:26:448:31 | x.m2(...) | | main.rs:385:5:386:14 | struct S1 |
| main.rs:449:26:449:26 | y | | main.rs:375:5:378:5 | struct MyThing |
| main.rs:449:26:449:26 | y | | main.rs:394:5:405:5 | trait MyTrait2 |
| main.rs:449:26:449:26 | y | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:449:26:449:26 | y | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:449:26:449:26 | y | Tr2 | main.rs:387:5:388:14 | struct S2 |
| main.rs:449:26:449:31 | y.m2(...) | | main.rs:387:5:388:14 | struct S2 |
| main.rs:451:13:451:13 | x | | main.rs:380:5:383:5 | struct MyThing2 |
| main.rs:451:13:451:13 | x | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:451:13:451:13 | x | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:451:13:451:13 | x | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:451:13:451:13 | x | Tr3 | main.rs:385:5:386:14 | struct S1 |
| main.rs:451:17:451:34 | MyThing2 {...} | | main.rs:380:5:383:5 | struct MyThing2 |
| main.rs:451:17:451:34 | MyThing2 {...} | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:451:17:451:34 | MyThing2 {...} | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:451:17:451:34 | MyThing2 {...} | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:451:17:451:34 | MyThing2 {...} | Tr3 | main.rs:385:5:386:14 | struct S1 |
| main.rs:451:31:451:32 | S1 | | main.rs:385:5:386:14 | struct S1 |
| main.rs:452:13:452:13 | y | | main.rs:380:5:383:5 | struct MyThing2 |
| main.rs:452:13:452:13 | y | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:452:13:452:13 | y | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:452:13:452:13 | y | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:452:13:452:13 | y | Tr3 | main.rs:387:5:388:14 | struct S2 |
| main.rs:452:17:452:34 | MyThing2 {...} | | main.rs:380:5:383:5 | struct MyThing2 |
| main.rs:452:17:452:34 | MyThing2 {...} | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:452:17:452:34 | MyThing2 {...} | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:452:17:452:34 | MyThing2 {...} | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:452:17:452:34 | MyThing2 {...} | Tr3 | main.rs:387:5:388:14 | struct S2 |
| main.rs:452:31:452:32 | S2 | | main.rs:387:5:388:14 | struct S2 |
| main.rs:454:26:454:26 | x | | main.rs:380:5:383:5 | struct MyThing2 |
| main.rs:454:26:454:26 | x | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:454:26:454:26 | x | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:454:26:454:26 | x | A | main.rs:385:5:386:14 | struct S1 |
| main.rs:454:26:454:26 | x | Tr3 | main.rs:385:5:386:14 | struct S1 |
| main.rs:454:26:454:31 | x.m3(...) | | main.rs:385:5:386:14 | struct S1 |
| main.rs:455:26:455:26 | y | | main.rs:380:5:383:5 | struct MyThing2 |
| main.rs:455:26:455:26 | y | | main.rs:407:5:418:5 | trait MyTrait3 |
| main.rs:455:26:455:26 | y | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:455:26:455:26 | y | A | main.rs:387:5:388:14 | struct S2 |
| main.rs:455:26:455:26 | y | Tr3 | main.rs:387:5:388:14 | struct S2 |
| main.rs:455:26:455:31 | y.m3(...) | | main.rs:387:5:388:14 | struct S2 |
| main.rs:473:22:473:22 | x | | file://:0:0:0:0 | & |
| main.rs:473:22:473:22 | x | &T | main.rs:473:11:473:19 | T |
@@ -1026,7 +1026,7 @@ resolveMethodCallExpr
| main.rs:340:26:340:31 | x.m2(...) | main.rs:315:9:321:9 | fn m2 |
| main.rs:369:26:369:31 | x.m1(...) | main.rs:357:9:362:9 | fn m1 |
| main.rs:370:26:370:31 | y.m1(...) | main.rs:357:9:362:9 | fn m1 |
| main.rs:400:17:400:25 | self.m1(...) | main.rs:391:9:391:25 | fn m1 |
| main.rs:400:17:400:25 | self.m1(...) | main.rs:391:9:391:27 | fn m1 |
| main.rs:413:17:413:25 | self.m2(...) | main.rs:395:9:404:9 | fn m2 |
| main.rs:442:26:442:31 | x.m1(...) | main.rs:421:9:423:9 | fn m1 |
| main.rs:443:26:443:31 | y.m1(...) | main.rs:421:9:423:9 | fn m1 |

View File

@@ -12,7 +12,7 @@ query predicate resolveMethodCallExpr(MethodCallExpr mce, Function f) {
}
query predicate resolveFieldExpr(FieldExpr fe, AstNode target) {
target = resolveRecordFieldExpr(fe)
target = resolveStructFieldExpr(fe)
or
target = resolveTupleFieldExpr(fe)
}

View File

@@ -106,28 +106,32 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
/**
* A path into a type.
*
* Paths are represented in left-to-right order, for example, a path `"0.1"` into the
* type `C1<C2<A,B>,C3<C,D>>` points at the type `B`.
* Paths are represented in left-to-right order, for example, a path `"A0.B1"`
* into the type `A<B<S,T>,C<U,V>>` points at the type `T`, assuming that the
* first type parameter of `A` is named `A0` and the second type parameter of
* `B` is named `B1`.
*
* Type paths are used to represent constructed types without using a `newtype`, which
* makes it practically feasible to do type inference in mutual recursion with call
* resolution.
*
* As an example, the type above can be represented by the following set of tuples
* As an example, the type above can be represented by the following set of
* tuples, if assuming the same naming convention for type parameters as
* above:
*
* `TypePath` | `Type`
* ---------- | --------
* `""` | ``C1`2``
* `"0"` | ``C2`2``
* `"0.0"` | `A`
* `"0.1"` | `B`
* `"1"` | ``C3`2``
* `"1.0"` | `C`
* `"1.1"` | `D`
* `TypePath` | `Type`
* ----------- | --------
* `""` | ``A`2``
* `"A0"` | ``B`2``
* `"A0.B0"` | `S`
* `"A0.B1"` | `T`
* `"A1"` | ``C`2``
* `"A1.C0"` | `U`
* `"A1.C1"` | `V`
*
* Note that while we write type paths using type parameter positions (e.g. `"0.1"`),
* the actual implementation uses unique type parameter identifiers, in order to not
* mix up type parameters from different types.
* Note that while we write type paths using type parameter names, the actual
* implementation uses unique type parameter identifiers, in order to not mix
* up type parameters from different types.
*/
class TypePath extends String {
bindingset[this]
@@ -439,7 +443,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
* Gets the declared type of this declaration at `path` for position `dpos`.
*
* For example, if this declaration is the method `int M(bool b)`,
* then the declared type at parameter position `0` is `bool` and the
* then the declared type at parameter position `0` is `bool`, the
* declared type at the `this` position is the class type, and the
* declared return type is `int`.
*/
Type getDeclaredType(DeclarationPosition dpos, TypePath path);
@@ -540,7 +545,11 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
/**
* Gets the type of the type argument at `path` in `a` that corresponds to
* the type parameter `tp` in `target`.
* the type parameter `tp` in `target`, if any.
*
* Note that this predicate crucially does not depend on type inference,
* and hence can appear in negated position, e.g., as in
* `directTypeMatch`.
*/
bindingset[a, target]
pragma[inline_late]
@@ -605,19 +614,21 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
*
* class Sub<T4> : Mid<C<T4>> { }
*
* new Sub<int>().ToString();
* new Sub<int>().ToString();
* // ^^^^^^^^^^^^^^ node at `apos`
* // ^^^^^^^^^^^^^^^^^^^^^^^^^ `a`
* ```
*
* for the node `new Sub<int>()`, which is the receiver of a method call, we
* have:
* where the method call is an access and `new Sub<int>()` is at an
* access position, which is the receiver of a method call, we have:
*
* `baseMention` | `path` | `t`
* ------------- | --------- | ---
* `Mid<C<T4>>` | `"0"` | ``C`1``
* `Mid<C<T4>>` | `"0.1"` | `int`
* `Base<C<T3>>` | `"0"` | ``C`1``
* `Base<C<T3>>` | `"0.0"` | ``C`1``
* `Base<C<T3>>` | `"0.0.1"` | `int`
* `baseMention` | `path` | `t`
* ------------- | ------------ | ---
* `Mid<C<T4>>` | `"T3"` | ``C`1``
* `Mid<C<T4>>` | `"T3.T1"` | `int`
* `Base<C<T3>>` | `"T2"` | ``C`1``
* `Base<C<T3>>` | `"T2.T1"` | ``C`1``
* `Base<C<T3>>` | `"T2.T1.T1"` | `int`
*/
pragma[nomagic]
predicate hasBaseTypeMention(
@@ -635,28 +646,36 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
}
}
/**
* Holds if the type of `a` at `apos` has the base type `base`, and when
* viewed as an element of that type has the type `t` at `path`.
*/
pragma[nomagic]
private predicate accessBaseType(
Access a, AccessPosition apos, Declaration target, Type base, TypePath path, Type t
Access a, AccessPosition apos, Type base, TypePath path, Type t
) {
exists(TypeMention tm |
target = a.getTarget() and
AccessBaseType::hasBaseTypeMention(a, apos, tm, path, t) and
base = resolveTypeMentionRoot(tm)
)
}
/**
* Holds if the declared type at `decl` for `dpos` at the `path` is `tp`
* and `path` starts with a type parameter of `base`.
*/
pragma[nomagic]
private predicate declarationBaseType(
Declaration decl, DeclarationPosition dpos, Type base, TypePath path, Type t
Declaration decl, DeclarationPosition dpos, Type base, TypePath path, TypeParameter tp
) {
t = decl.getDeclaredType(dpos, path) and
tp = decl.getDeclaredType(dpos, path) and
path.isCons(base.getATypeParameter(), _)
}
/**
* Holds if the (transitive) base type `t` at `path` of `a` matches the type
* parameter `tp`, which is used in the declared types of `target`.
* Holds if the (transitive) base type `t` at `path` of `a` for some
* `AccessPosition` matches the type parameter `tp`, which is used in the
* declared types of `target`.
*
* For example, in
*
@@ -681,17 +700,18 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
*
* `path` | `t`
* --------- | -------
* `"0"` | ``C`1``
* `"0.0"` | ``C`1``
* `"0.0.1"` | `int`
* `""` | ``C`1``
* `"T1"` | ``C`1``
* `"T1.T1"` | `int`
*/
pragma[nomagic]
private predicate baseTypeMatch(
Access a, Declaration target, TypePath path, Type t, TypeParameter tp
) {
not exists(getTypeArgument(a, target, tp, _)) and
target = a.getTarget() and
exists(AccessPosition apos, DeclarationPosition dpos, Type base, TypePath pathToTypeParam |
accessBaseType(a, apos, target, base, pathToTypeParam.append(path), t) and
accessBaseType(a, apos, base, pathToTypeParam.append(path), t) and
declarationBaseType(target, dpos, base, pathToTypeParam, tp) and
accessDeclarationPositionMatch(apos, dpos)
)
@@ -710,17 +730,6 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
t = getTypeArgument(a, target, tp, path)
}
pragma[nomagic]
private predicate implicitTypeMatch(
Access a, Declaration target, TypePath path, Type t, TypeParameter tp
) {
// We can get the type of `tp` from one of the access positions
directTypeMatch(a, target, path, t, tp)
or
// We can get the type of `tp` by going up the type hiearchy
baseTypeMatch(a, target, path, t, tp)
}
pragma[inline]
private predicate typeMatch(
Access a, Declaration target, TypePath path, Type t, TypeParameter tp
@@ -729,9 +738,11 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
// at the target.
explicitTypeMatch(a, target, path, t, tp)
or
// No explicit type argument, so we deduce the parameter from other
// information
implicitTypeMatch(a, target, path, t, tp)
// We can infer the type of `tp` from one of the access positions
directTypeMatch(a, target, path, t, tp)
or
// We can infer the type of `tp` by going up the type hiearchy
baseTypeMatch(a, target, path, t, tp)
}
/**
@@ -750,27 +761,27 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
*
* class Sub<T4> : Mid<C<T4>> { }
*
* new Sub<int>().Method();
* new Sub<int>().Method(); // Note: Sub<int> is a subtype of Base<C<C<int>>>
* // ^^^^^^^^^^^^^^^^^^^^^^^ `a`
* ```
*
* we infer the following types for the return position:
*
* `path` | `t`
* ----------- | -------
* `"0"` | ``C`1``
* `"0.0"` | ``C`1``
* `"0.0.0"` | ``C`1``
* `"0.0.0.1"` | `int`
* `path` | `t`
* ------------ | -------
* `""` | ``C`1``
* `"T1"` | ``C`1``
* `"T1.T1"` | ``C`1``
* `"T1.T1.T1"` | `int`
*
* We also infer the following types for the receiver position:
*
* `path` | `t`
* ----------- | -------
* `"0"` | ``Base`1``
* `"0.0"` | ``C`1``
* `"0.0.0"` | ``C`1``
* `"0.0.0.1"` | `int`
* `path` | `t`
* ------------ | -------
* `""` | ``Base`1``
* `"T2"` | ``C`1``
* `"T2.T1"` | ``C`1``
* `"T2.T1.T1"` | `int`
*/
pragma[nomagic]
Type inferAccessType(Access a, AccessPosition apos, TypePath path) {