-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rust: Implement path resolution in QL #18579
Conversation
707d17c
to
9bfd713
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.
Tip: Copilot code review supports C#, Go, Java, JavaScript, Markdown, Python, Ruby and TypeScript, with more languages coming soon. Learn more
pragma[inline_late] | ||
predicate isPublic() { exists(this.getVisibility()) } | ||
|
||
/** Gets an element that has this item as immediately enlcosing item. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** Gets an element that has this item as immediately enlcosing item. */ | |
/** Gets an element that has this item as immediately enclosing item. */ |
commmentAt(value, filepath, line) and | ||
inMacro = false | ||
or | ||
( | ||
not commmentAt(_, filepath, line) | ||
or | ||
inMacro = true | ||
) and | ||
value = i.getName() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes it easier to see that the first disjunct is (roughly) being negated in the second disjunct.
commmentAt(value, filepath, line) and | |
inMacro = false | |
or | |
( | |
not commmentAt(_, filepath, line) | |
or | |
inMacro = true | |
) and | |
value = i.getName() | |
commmentAt(value, filepath, line) and inMacro = false | |
or | |
not (commmentAt(_, filepath, line) and inMacro = false) and |
) | ||
} | ||
|
||
private class RelevantPath extends Path { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private class RelevantPath extends Path { | |
/** A path that does not access a local variable. */ | |
private class RelevantPath extends Path { |
override Visibility getVisibility() { none() } | ||
} | ||
|
||
private predicate sourceFileEdge(SourceFile f, string name, ItemNode item) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private predicate sourceFileEdge(SourceFile f, string name, ItemNode item) { | |
/** Holds if `item` has the name `name` and is a top-level item inside `f`. */ | |
private predicate sourceFileEdge(SourceFile f, string name, ItemNode item) { |
/** Holds if this item is declared as `pub`. */ | ||
bindingset[this] | ||
pragma[inline_late] | ||
predicate isPublic() { exists(this.getVisibility()) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this predicate handle pub(...)
things eventually? If not hasVisibility
might be a better name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think eventually pub(...)
should be handled.
RelevantPath() { not this = any(VariableAccess va).(PathExpr).getPath() } | ||
|
||
pragma[nomagic] | ||
predicate isRoot(string name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name gives me the intuition that the path is related to the crate root, but I don't think that's the case. Would it make sense to call it something along the lines of isUnqualifiedPath
?
* may be looked up inside enclosing item `encl`. | ||
*/ | ||
pragma[nomagic] | ||
private predicate rootPathLookup(RelevantPath root, string name, ItemNode encl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of the other predicates here have ItemNode
as a result, could this one be the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I prefer it as-is, because encl
is not functionally determined.
@@ -0,0 +1,464 @@ | |||
/** Provides functionality for resolving paths. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** Provides functionality for resolving paths. */ | |
/** Provides the `resolvePath` predicate for resolving paths. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to keep it as-is, since we are also exposing other related concepts, such as ItemNode
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. What about adding another sentence that mentions resolvePath
then? It seems to be the primary export, so I think it's helpful to mention explicitly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
* any item (named `name`) inside the imported source file `f`. Using this | ||
* edge, `m2::foo` can resolve to `f::foo`, which results in the edge | ||
* `m1::use m2 --foo--> f::foo`. Lastly, all edges out of `use` nodes are | ||
* lifted to predecessors in the graph, so we get an edge `m1 --foo--> f::foo`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all helps a lot with understanding 👍
@@ -0,0 +1,201 @@ | |||
mod my; // I1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps the directory name modules
-> path-resolution
would make it more clear what is being tested?
4a57786
to
0d5e408
Compare
4361307
to
1cb524f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great :)
This PR adds an initial implementation of path resolution in QL, that is, resolving paths to items.
The implementation is based on the idea of an item graph, which is a labeled directed graph, where an edge
item1 --name--> item2
means thatitem2
is available inside the scope ofitem1
under the namename
. For example, if we havethen there is an edge
m1 --m2--> m1::m2
.The implementation has a lot of known limitations for now, for example
.toml
files in QL.Self
andcrate
is partial.Foo<Bar>
are not modeled.<Foo as Bar>
are not modeled.#[path = "foo.rs"] mod bar;
are not handled.