Skip to content

Commit 84517f0

Browse files
committed
Rust: Calculate canonical paths in QL
1 parent 3da4a30 commit 84517f0

File tree

6 files changed

+320
-2
lines changed

6 files changed

+320
-2
lines changed

rust/ql/lib/codeql/rust/elements/internal/AddressableImpl.qll

Lines changed: 13 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/internal/PathResolution.qll

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,33 @@ abstract class ItemNode extends Locatable {
211211
).(Crate).getADependency*()
212212
}
213213

214+
/**
215+
* Gets the canonical path of this item, if any.
216+
*
217+
* See [The Rust Reference][1] for more details.
218+
*
219+
* [1]: https://doc.rust-lang.org/reference/paths.html#canonical-paths
220+
*/
221+
cached
222+
abstract string getCanonicalPath(Crate c);
223+
224+
/** Gets the canonical path prefix that this node provides for `child`. */
225+
pragma[nomagic]
226+
string getCanonicalPathPrefixFor(Crate c, ItemNode child) {
227+
child.getImmediateParent() = this and
228+
result = this.getCanonicalPath(c)
229+
}
230+
231+
/** Gets the canonical path prefix of this node, if any. */
232+
pragma[nomagic]
233+
final string getCanonicalPathPrefix(Crate c) {
234+
result = any(ItemNode parent).getCanonicalPathPrefixFor(c, this)
235+
}
236+
237+
/** Gets the canonical path prefix of this node, if any. */
238+
pragma[nomagic]
239+
final Crate getACanonicalPathCrate() { exists(this.getCanonicalPathPrefix(result)) }
240+
214241
/** Gets the location of this item. */
215242
Location getLocation() { result = super.getLocation() }
216243
}
@@ -257,6 +284,8 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
257284
override predicate isPublic() { any() }
258285

259286
override TypeParam getTypeParam(int i) { none() }
287+
288+
override string getCanonicalPath(Crate c) { none() }
260289
}
261290

262291
class CrateItemNode extends ItemNode instanceof Crate {
@@ -304,12 +333,44 @@ class CrateItemNode extends ItemNode instanceof Crate {
304333
override predicate isPublic() { any() }
305334

306335
override TypeParam getTypeParam(int i) { none() }
336+
337+
override string getCanonicalPath(Crate c) { c = this and result = Crate.super.getName() }
338+
339+
override string getCanonicalPathPrefixFor(Crate c, ItemNode child) {
340+
exists(ModuleLikeNode m |
341+
result = this.getCanonicalPath(c) and
342+
m = this.getModuleNode()
343+
|
344+
child = m
345+
or
346+
child.getImmediateParent() = m.(SourceFile) and
347+
not m = child.(SourceFileItemNode).getSuper()
348+
)
349+
}
307350
}
308351

309352
/** An item that can occur in a trait or an `impl` block. */
310353
abstract private class AssocItemNode extends ItemNode, AssocItem {
311354
/** Holds if this associated item has an implementation. */
312355
abstract predicate hasImplementation();
356+
357+
bindingset[c]
358+
private string getCanonicalPathPart(Crate c, int i) {
359+
i = 0 and
360+
result = this.getCanonicalPathPrefix(c)
361+
or
362+
i = 1 and
363+
result = "::"
364+
or
365+
i = 2 and
366+
result = this.getName()
367+
}
368+
369+
language[monotonicAggregates]
370+
override string getCanonicalPath(Crate c) {
371+
c = this.getACanonicalPathCrate() and
372+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
373+
}
313374
}
314375

315376
private class ConstItemNode extends AssocItemNode instanceof Const {
@@ -332,6 +393,24 @@ private class EnumItemNode extends ItemNode instanceof Enum {
332393
override Visibility getVisibility() { result = Enum.super.getVisibility() }
333394

334395
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
396+
397+
bindingset[c]
398+
private string getCanonicalPathPart(Crate c, int i) {
399+
i = 0 and
400+
result = this.getCanonicalPathPrefix(c)
401+
or
402+
i = 1 and
403+
result = "::"
404+
or
405+
i = 2 and
406+
result = this.getName()
407+
}
408+
409+
language[monotonicAggregates]
410+
override string getCanonicalPath(Crate c) {
411+
c = this.getACanonicalPathCrate() and
412+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
413+
}
335414
}
336415

337416
private class VariantItemNode extends ItemNode instanceof Variant {
@@ -346,6 +425,24 @@ private class VariantItemNode extends ItemNode instanceof Variant {
346425
}
347426

348427
override Visibility getVisibility() { result = super.getEnum().getVisibility() }
428+
429+
bindingset[c]
430+
private string getCanonicalPathPart(Crate c, int i) {
431+
i = 0 and
432+
result = this.getCanonicalPathPrefix(c)
433+
or
434+
i = 1 and
435+
result = "::"
436+
or
437+
i = 2 and
438+
result = this.getName()
439+
}
440+
441+
language[monotonicAggregates]
442+
override string getCanonicalPath(Crate c) {
443+
c = this.getACanonicalPathCrate() and
444+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
445+
}
349446
}
350447

351448
class FunctionItemNode extends AssocItemNode instanceof Function {
@@ -467,6 +564,47 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
467564
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
468565

469566
override Visibility getVisibility() { result = Impl.super.getVisibility() }
567+
568+
pragma[nomagic]
569+
private string getCanonicalPathTraitPart(Crate c) {
570+
exists(Crate c2 | result = this.resolveTraitTy().getCanonicalPath(c2) |
571+
c = c2
572+
or
573+
c2 = c.getADependency()
574+
)
575+
}
576+
577+
bindingset[c]
578+
private string getCanonicalPathPart(Crate c, int i) {
579+
i = 0 and
580+
result = "<"
581+
or
582+
i = 1 and
583+
result = this.resolveSelfTy().getCanonicalPath(c)
584+
or
585+
if exists(this.getTraitPath())
586+
then
587+
i = 2 and
588+
result = " as "
589+
or
590+
i = 3 and
591+
result = this.getCanonicalPathTraitPart(c)
592+
or
593+
i = 4 and
594+
result = ">"
595+
else (
596+
i = 2 and
597+
result = ">"
598+
)
599+
}
600+
601+
language[monotonicAggregates]
602+
override string getCanonicalPath(Crate c) {
603+
c = this.getACanonicalPathCrate() and
604+
exists(int m | if exists(this.getTraitPath()) then m = 4 else m = 2 |
605+
result = strictconcat(int i | i in [0 .. m] | this.getCanonicalPathPart(c, i) order by i)
606+
)
607+
}
470608
}
471609

472610
private class MacroCallItemNode extends AssocItemNode instanceof MacroCall {
@@ -479,6 +617,8 @@ private class MacroCallItemNode extends AssocItemNode instanceof MacroCall {
479617
override TypeParam getTypeParam(int i) { none() }
480618

481619
override Visibility getVisibility() { none() }
620+
621+
override string getCanonicalPath(Crate c) { none() }
482622
}
483623

484624
private class ModuleItemNode extends ModuleLikeNode instanceof Module {
@@ -489,6 +629,44 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
489629
override Visibility getVisibility() { result = Module.super.getVisibility() }
490630

491631
override TypeParam getTypeParam(int i) { none() }
632+
633+
bindingset[c]
634+
private string getCanonicalPathPart(Crate c, int i) {
635+
i = 0 and
636+
result = this.getCanonicalPathPrefix(c)
637+
or
638+
i = 1 and
639+
result = "::"
640+
or
641+
i = 2 and
642+
result = this.getName()
643+
}
644+
645+
language[monotonicAggregates]
646+
override string getCanonicalPath(Crate c) {
647+
c = this.getACanonicalPathCrate() and
648+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
649+
}
650+
651+
pragma[nomagic]
652+
private ItemNode getACanonicalPathChild() {
653+
exists(SourceFile f |
654+
fileImport(this, f) and
655+
sourceFileEdge(f, _, result)
656+
)
657+
or
658+
this = result.getImmediateParent()
659+
or
660+
exists(ItemNode mid |
661+
mid = this.getACanonicalPathChild() and
662+
mid.(MacroCallItemNode) = result.getImmediateParent()
663+
)
664+
}
665+
666+
override string getCanonicalPathPrefixFor(Crate c, ItemNode child) {
667+
child = this.getACanonicalPathChild() and
668+
result = this.getCanonicalPath(c)
669+
}
492670
}
493671

494672
private class StructItemNode extends ItemNode instanceof Struct {
@@ -504,6 +682,24 @@ private class StructItemNode extends ItemNode instanceof Struct {
504682
override Visibility getVisibility() { result = Struct.super.getVisibility() }
505683

506684
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
685+
686+
bindingset[c]
687+
private string getCanonicalPathPart(Crate c, int i) {
688+
i = 0 and
689+
result = this.getCanonicalPathPrefix(c)
690+
or
691+
i = 1 and
692+
result = "::"
693+
or
694+
i = 2 and
695+
result = this.getName()
696+
}
697+
698+
language[monotonicAggregates]
699+
override string getCanonicalPath(Crate c) {
700+
c = this.getACanonicalPathCrate() and
701+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
702+
}
507703
}
508704

509705
class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
@@ -524,6 +720,36 @@ class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
524720
override Visibility getVisibility() { result = Trait.super.getVisibility() }
525721

526722
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
723+
724+
bindingset[c]
725+
private string getCanonicalPathPart(Crate c, int i) {
726+
i = 0 and
727+
result = "<_ as "
728+
or
729+
i = 1 and
730+
result = this.getCanonicalPathPrefix(c)
731+
or
732+
i = 2 and
733+
result = "::"
734+
or
735+
i = 3 and
736+
result = this.getName()
737+
or
738+
i = 4 and
739+
result = ">"
740+
}
741+
742+
language[monotonicAggregates]
743+
override string getCanonicalPath(Crate c) {
744+
c = this.getACanonicalPathCrate() and
745+
result = strictconcat(int i | i in [1 .. 3] | this.getCanonicalPathPart(c, i) order by i)
746+
}
747+
748+
language[monotonicAggregates]
749+
override string getCanonicalPathPrefixFor(Crate c, ItemNode child) {
750+
result = strictconcat(int i | i in [0 .. 4] | this.getCanonicalPathPart(c, i) order by i) and
751+
child = this.getAnAssocItem()
752+
}
527753
}
528754

529755
class TypeAliasItemNode extends AssocItemNode instanceof TypeAlias {
@@ -546,6 +772,24 @@ private class UnionItemNode extends ItemNode instanceof Union {
546772
override Visibility getVisibility() { result = Union.super.getVisibility() }
547773

548774
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
775+
776+
bindingset[c]
777+
private string getCanonicalPathPart(Crate c, int i) {
778+
i = 0 and
779+
result = this.getCanonicalPathPrefix(c)
780+
or
781+
i = 1 and
782+
result = "::"
783+
or
784+
i = 2 and
785+
result = this.getName()
786+
}
787+
788+
language[monotonicAggregates]
789+
override string getCanonicalPath(Crate c) {
790+
c = this.getACanonicalPathCrate() and
791+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
792+
}
549793
}
550794

551795
private class UseItemNode extends ItemNode instanceof Use {
@@ -556,6 +800,8 @@ private class UseItemNode extends ItemNode instanceof Use {
556800
override Visibility getVisibility() { result = Use.super.getVisibility() }
557801

558802
override TypeParam getTypeParam(int i) { none() }
803+
804+
override string getCanonicalPath(Crate c) { none() }
559805
}
560806

561807
private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
@@ -566,6 +812,8 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
566812
override Visibility getVisibility() { none() }
567813

568814
override TypeParam getTypeParam(int i) { none() }
815+
816+
override string getCanonicalPath(Crate c) { none() }
569817
}
570818

571819
private class TypeParamItemNode extends ItemNode instanceof TypeParam {
@@ -622,6 +870,8 @@ private class TypeParamItemNode extends ItemNode instanceof TypeParam {
622870
override TypeParam getTypeParam(int i) { none() }
623871

624872
override Location getLocation() { result = TypeParam.super.getName().getLocation() }
873+
874+
override string getCanonicalPath(Crate c) { none() }
625875
}
626876

627877
/** Holds if `item` has the name `name` and is a top-level item inside `f`. */

rust/ql/lib/codeql/rust/internal/PathResolutionConsistency.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ query predicate multipleTupleFields(FieldExpr fe, TupleField field) {
3838
strictcount(fe.getTupleField()) > 1
3939
}
4040

41+
/** Holds if `p` may resolve to multiple items including `i`. */
42+
query predicate multipleCanonicalPaths(ItemNode i, Crate c, string path) {
43+
path = i.getCanonicalPath(c) and
44+
strictcount(i.getCanonicalPath(c)) > 1
45+
}
46+
4147
/**
4248
* Gets counts of path resolution inconsistencies of each type.
4349
*/

0 commit comments

Comments
 (0)