-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Rust: Add telemetry for comparing against rust-analyzer
#19025
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/** | ||
* INTERNAL: Do not use. | ||
* | ||
* Provides functionality for comparing data from `rust-analyzer` with data computed | ||
* in QL. | ||
*/ | ||
|
||
import rust | ||
|
||
private signature module ResolvableSig { | ||
class Source { | ||
string toString(); | ||
|
||
Location getLocation(); | ||
} | ||
|
||
class Target { | ||
string toString(); | ||
|
||
Location getLocation(); | ||
} | ||
} | ||
|
||
private signature module CompareSig<ResolvableSig R> { | ||
predicate isResolvable(R::Source s); | ||
|
||
R::Target resolve(R::Source s); | ||
} | ||
|
||
private module Compare<ResolvableSig R, CompareSig<R> RustAnalyzer, CompareSig<R> Ql> { | ||
private import R | ||
|
||
predicate same(Source s, Target t) { | ||
t = RustAnalyzer::resolve(s) and | ||
t = Ql::resolve(s) | ||
Check warningCode scanning / CodeQL Redundant assignment. Warning The variable t Error loading related location Loading the same value Error loading related location Loading |
||
} | ||
|
||
predicate sameCount(int c) { c = count(Source s | same(s, _)) } | ||
|
||
predicate diff(Source s, Target t1, Target t2) { | ||
t1 = RustAnalyzer::resolve(s) and | ||
t2 = Ql::resolve(s) and | ||
t1 != t2 | ||
} | ||
|
||
predicate diffCount(int c) { c = count(Source s | not same(s, _) and diff(s, _, _)) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we exclude those that are in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't want to report cases where our QL implementation resolves to multiple items, and one of them is correct. We have a consistency check for multiple resolutions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, that makes sense :) |
||
|
||
predicate rustAnalyzerUnique(Source s) { | ||
RustAnalyzer::isResolvable(s) and | ||
not Ql::isResolvable(s) | ||
} | ||
|
||
predicate rustAnalyzerUniqueCount(int c) { c = count(Source s | rustAnalyzerUnique(s)) } | ||
|
||
predicate qlUnique(Source s) { | ||
not RustAnalyzer::isResolvable(s) and | ||
Ql::isResolvable(s) | ||
} | ||
|
||
predicate qlUniqueCount(int c) { c = count(Source s | qlUnique(s)) } | ||
|
||
predicate summary(string key, int value) { | ||
key = "rust-analyzer unique" and rustAnalyzerUniqueCount(value) | ||
or | ||
key = "QL unique" and qlUniqueCount(value) | ||
or | ||
key = "same" and sameCount(value) | ||
or | ||
key = "different" and diffCount(value) | ||
} | ||
} | ||
|
||
private module PathResolution implements ResolvableSig { | ||
class Source extends Resolvable { | ||
Source() { not this instanceof MethodCallExpr } | ||
} | ||
|
||
class Target = Item; | ||
} | ||
|
||
private module RustAnalyzerPathResolution implements CompareSig<PathResolution> { | ||
predicate isResolvable(PathResolution::Source s) { s.hasResolvedPath() } | ||
|
||
Item resolve(PathResolution::Source s) { s.resolvesAsItem(result) } | ||
} | ||
|
||
private module QlPathResolution implements CompareSig<PathResolution> { | ||
private import codeql.rust.internal.PathResolution | ||
|
||
private Path getPath(Resolvable r) { | ||
result = r.(PathExpr).getPath() | ||
or | ||
result = r.(RecordExpr).getPath() | ||
or | ||
result = r.(PathPat).getPath() | ||
or | ||
result = r.(RecordPat).getPath() | ||
or | ||
result = r.(TupleStructPat).getPath() | ||
} | ||
|
||
predicate isResolvable(PathResolution::Source s) { exists(resolve(s)) } | ||
|
||
Item resolve(PathResolution::Source s) { result = resolvePath(getPath(s)) } | ||
} | ||
|
||
module PathResolutionCompare = | ||
Compare<PathResolution, RustAnalyzerPathResolution, QlPathResolution>; | ||
|
||
private module CallGraph implements ResolvableSig { | ||
class Source = CallExprBase; | ||
|
||
class Target = Item; | ||
} | ||
|
||
private module RustAnalyzerCallGraph implements CompareSig<CallGraph> { | ||
private import codeql.rust.elements.internal.CallExprBaseImpl::Impl as CallExprBaseImpl | ||
|
||
predicate isResolvable(CallExprBase c) { | ||
CallExprBaseImpl::getCallResolvable(c).hasResolvedPath() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this different from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question, there is a subtle difference: Since we don't yet have entities for all dependencies in the DB (such as built-in types), we may reference that can resolve to a canonical path, but where there is no corresponding |
||
} | ||
|
||
Item resolve(CallExprBase c) { CallExprBaseImpl::getCallResolvable(c).resolvesAsItem(result) } | ||
} | ||
|
||
private module QlCallGraph implements CompareSig<CallGraph> { | ||
private import codeql.rust.internal.PathResolution as PathResolution | ||
|
||
predicate isResolvable(CallExprBase c) { exists(resolve(c)) } | ||
|
||
Item resolve(CallExprBase c) { result = c.getStaticTarget() } | ||
} | ||
|
||
module CallGraphCompare = Compare<CallGraph, RustAnalyzerCallGraph, QlCallGraph>; |
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 guess I would expect the value to come after a
:
. Maybe,
or some other symbol would work better?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 would rather not change it, since we already have logic in DCA that depends on the exact wording of the string.