-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Rust: Account for attribute expansions in path resolution #20454
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: Account for attribute expansions in path resolution #20454
Conversation
b31d5db
to
261134a
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.
Pull Request Overview
This PR improves Rust path resolution by accounting for attribute macro expansions. When items have attribute macros applied, they may be expanded/transformed, and the original items should be excluded from path resolution to prevent duplicate or incorrect resolution targets.
- Introduces a new predicate to identify items superceded by attribute macro expansions
- Filters out superceded items from the ItemNode class hierarchy
- Updates test expectations to reflect improved path resolution accuracy
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
rust/ql/lib/codeql/rust/internal/PathResolution.qll |
Adds logic to exclude items superceded by attribute macro expansions from path resolution |
rust/ql/lib/utils/test/PathResolutionInlineExpectationsTest.qll |
Removes macro filtering from test expectations |
rust/ql/test/library-tests/path-resolution/main.rs |
Adds test cases for attribute macro scenarios |
rust/ql/test/library-tests/path-resolution/proc_macro.rs |
Adds identity macro for testing |
.expected files |
Updated test expectations reflecting improved path resolution |
* Holds if `n` is superceded by an attribute macro expansion. That is, `n` is | ||
* an item or a transitive child of an item with an attribute macro expansion. | ||
*/ | ||
predicate supercededByAttributeMacroExpansion(AstNode n) { | ||
n.(Item).hasAttributeMacroExpansion() | ||
or | ||
exists(AstNode parent | | ||
n.getParentNode() = parent and | ||
supercededByAttributeMacroExpansion(parent) and | ||
// Don't exclude expansions themselves as they supercede other nodes. | ||
not n = parent.(Item).getAttributeMacroExpansion() and | ||
// Don't consider attributes themselves to be superceded. E.g., in `#[a] fn | ||
// f() {}` the macro expansion supercedes `fn f() {}` but not `#[a]`. |
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.
The word 'superceded' should be spelled 'superseded' in the predicate name, comments, and documentation.
* Holds if `n` is superceded by an attribute macro expansion. That is, `n` is | |
* an item or a transitive child of an item with an attribute macro expansion. | |
*/ | |
predicate supercededByAttributeMacroExpansion(AstNode n) { | |
n.(Item).hasAttributeMacroExpansion() | |
or | |
exists(AstNode parent | | |
n.getParentNode() = parent and | |
supercededByAttributeMacroExpansion(parent) and | |
// Don't exclude expansions themselves as they supercede other nodes. | |
not n = parent.(Item).getAttributeMacroExpansion() and | |
// Don't consider attributes themselves to be superceded. E.g., in `#[a] fn | |
// f() {}` the macro expansion supercedes `fn f() {}` but not `#[a]`. | |
* Holds if `n` is superseded by an attribute macro expansion. That is, `n` is | |
* an item or a transitive child of an item with an attribute macro expansion. | |
*/ | |
predicate supersededByAttributeMacroExpansion(AstNode n) { | |
n.(Item).hasAttributeMacroExpansion() | |
or | |
exists(AstNode parent | | |
n.getParentNode() = parent and | |
supersededByAttributeMacroExpansion(parent) and | |
// Don't exclude expansions themselves as they supersede other nodes. | |
not n = parent.(Item).getAttributeMacroExpansion() and | |
// Don't consider attributes themselves to be superseded. E.g., in `#[a] fn | |
// f() {}` the macro expansion supersedes `fn f() {}` but not `#[a]`. |
Copilot uses AI. Check for mistakes.
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 | ||
commmentAt(value, filepath, line) |
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.
The function name 'commmentAt' has an extra 'm' and should be 'commentAt'.
Copilot uses AI. Check for mistakes.
*/ | ||
abstract class ItemNode extends Locatable { | ||
ItemNode() { | ||
// Exclude items that are superceded by the expansion of an attribute macro. |
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.
nit: superseded
path = p.toStringDebug() | ||
} | ||
|
||
predicate debugItemNode(ItemNode item) { item = getRelevantLocatable() } |
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.
Actually, I think it is easier just to make getRelevantLocatable
public (I already do that in on of my PRs).
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.
In this case I wanted to see the ItemNode
s in a given range. getRelevantLocatable
would give all Locateable
s wouldn't it?
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.
Yes; perhaps your use case was different from mine; I would add calls to Debug::getRelevantLocatable
throughout the source code when debugging.
The annotated impl block was filtered away, but it's children where not. This caused the associated type `Foo` to appear as if it was an item in the scope outside of the impl block.
261134a
to
afb6d30
Compare
We should do the same for the CFG (on a separate PR). |
Note, since
getImmediateParent
finds the enclosingItemNode
wherever it may be, simply removing items that have an expanded macro attribute is enough to enable path resolution to find things in inside the expansion.Going per-commit shows a bug that my first approach introduced, and then a test and fix for that.