-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Rust: Implement path resolution in QL #18579
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
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
paldepind
left a comment
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--> item2means thatitem2is available inside the scope ofitem1under 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
.tomlfiles in QL.Selfandcrateis partial.Foo<Bar>are not modeled.<Foo as Bar>are not modeled.#[path = "foo.rs"] mod bar;are not handled.