Skip to content

Commit c12bbc6

Browse files
committed
Rust: Calculate canonical paths in QL
1 parent 73193d6 commit c12bbc6

5 files changed

Lines changed: 297 additions & 2 deletions

File tree

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
@@ -190,6 +190,33 @@ abstract class ItemNode extends Locatable {
190190
this = result.(CrateItemNode).getASourceFile()
191191
}
192192

193+
/**
194+
* Gets the canonical path of this item, if any.
195+
*
196+
* See [The Rust Reference][1] for more details.
197+
*
198+
* [1]: https://doc.rust-lang.org/reference/paths.html#canonical-paths
199+
*/
200+
cached
201+
abstract string getCanonicalPath(Crate c);
202+
203+
/** Gets the canonical path prefix that this node provides for `child`. */
204+
pragma[nomagic]
205+
string getCanonicalPathPrefixFor(Crate c, ItemNode child) {
206+
child.getImmediateParent() = this and
207+
result = this.getCanonicalPath(c)
208+
}
209+
210+
/** Gets the canonical path prefix of this node, if any. */
211+
pragma[nomagic]
212+
final string getCanonicalPathPrefix(Crate c) {
213+
result = any(ItemNode parent).getCanonicalPathPrefixFor(c, this)
214+
}
215+
216+
/** Gets the canonical path prefix of this node, if any. */
217+
pragma[nomagic]
218+
final Crate getACanonicalPathCrate() { exists(this.getCanonicalPathPrefix(result)) }
219+
193220
/** Gets the location of this item. */
194221
Location getLocation() { result = super.getLocation() }
195222
}
@@ -226,6 +253,8 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
226253
override predicate isPublic() { any() }
227254

228255
override TypeParam getTypeParam(int i) { none() }
256+
257+
override string getCanonicalPath(Crate c) { none() }
229258
}
230259

231260
class CrateItemNode extends ItemNode instanceof Crate {
@@ -273,12 +302,44 @@ class CrateItemNode extends ItemNode instanceof Crate {
273302
override predicate isPublic() { any() }
274303

275304
override TypeParam getTypeParam(int i) { none() }
305+
306+
override string getCanonicalPath(Crate c) { c = this and result = Crate.super.getName() }
307+
308+
override string getCanonicalPathPrefixFor(Crate c, ItemNode child) {
309+
exists(ModuleLikeNode m |
310+
result = this.getCanonicalPath(c) and
311+
m = this.getModuleNode()
312+
|
313+
child = m
314+
or
315+
child.getImmediateParent() = m.(SourceFile) and
316+
not m = child.(SourceFileItemNode).getSuper()
317+
)
318+
}
276319
}
277320

278321
/** An item that can occur in a trait or an `impl` block. */
279322
abstract private class AssocItemNode extends ItemNode, AssocItem {
280323
/** Holds if this associated item has an implementation. */
281324
abstract predicate hasImplementation();
325+
326+
bindingset[c]
327+
private string getCanonicalPathPart(Crate c, int i) {
328+
i = 0 and
329+
result = this.getCanonicalPathPrefix(c)
330+
or
331+
i = 1 and
332+
result = "::"
333+
or
334+
i = 2 and
335+
result = this.getName()
336+
}
337+
338+
language[monotonicAggregates]
339+
override string getCanonicalPath(Crate c) {
340+
c = this.getACanonicalPathCrate() and
341+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
342+
}
282343
}
283344

284345
private class ConstItemNode extends AssocItemNode instanceof Const {
@@ -301,6 +362,24 @@ private class EnumItemNode extends ItemNode instanceof Enum {
301362
override Visibility getVisibility() { result = Enum.super.getVisibility() }
302363

303364
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
365+
366+
bindingset[c]
367+
private string getCanonicalPathPart(Crate c, int i) {
368+
i = 0 and
369+
result = this.getCanonicalPathPrefix(c)
370+
or
371+
i = 1 and
372+
result = "::"
373+
or
374+
i = 2 and
375+
result = this.getName()
376+
}
377+
378+
language[monotonicAggregates]
379+
override string getCanonicalPath(Crate c) {
380+
c = this.getACanonicalPathCrate() and
381+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
382+
}
304383
}
305384

306385
private class VariantItemNode extends ItemNode instanceof Variant {
@@ -315,6 +394,24 @@ private class VariantItemNode extends ItemNode instanceof Variant {
315394
}
316395

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

320417
class FunctionItemNode extends AssocItemNode instanceof Function {
@@ -436,6 +533,47 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
436533
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
437534

438535
override Visibility getVisibility() { result = Impl.super.getVisibility() }
536+
537+
pragma[nomagic]
538+
private string getCanonicalPathTraitPart(Crate c) {
539+
exists(Crate c2 | result = this.resolveTraitTy().getCanonicalPath(c2) |
540+
c = c2
541+
or
542+
c2 = c.getADependency()
543+
)
544+
}
545+
546+
bindingset[c]
547+
private string getCanonicalPathPart(Crate c, int i) {
548+
i = 0 and
549+
result = "<"
550+
or
551+
i = 1 and
552+
result = this.resolveSelfTy().getCanonicalPath(c)
553+
or
554+
if exists(this.getTraitPath())
555+
then
556+
i = 2 and
557+
result = " as "
558+
or
559+
i = 3 and
560+
result = this.getCanonicalPathTraitPart(c)
561+
or
562+
i = 4 and
563+
result = ">"
564+
else (
565+
i = 2 and
566+
result = ">"
567+
)
568+
}
569+
570+
language[monotonicAggregates]
571+
override string getCanonicalPath(Crate c) {
572+
c = this.getACanonicalPathCrate() and
573+
exists(int m | if exists(this.getTraitPath()) then m = 4 else m = 2 |
574+
result = strictconcat(int i | i in [0 .. m] | this.getCanonicalPathPart(c, i) order by i)
575+
)
576+
}
439577
}
440578

441579
private class MacroCallItemNode extends AssocItemNode instanceof MacroCall {
@@ -448,6 +586,8 @@ private class MacroCallItemNode extends AssocItemNode instanceof MacroCall {
448586
override TypeParam getTypeParam(int i) { none() }
449587

450588
override Visibility getVisibility() { none() }
589+
590+
override string getCanonicalPath(Crate c) { none() }
451591
}
452592

453593
private class ModuleItemNode extends ModuleLikeNode instanceof Module {
@@ -458,6 +598,44 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
458598
override Visibility getVisibility() { result = Module.super.getVisibility() }
459599

460600
override TypeParam getTypeParam(int i) { none() }
601+
602+
bindingset[c]
603+
private string getCanonicalPathPart(Crate c, int i) {
604+
i = 0 and
605+
result = this.getCanonicalPathPrefix(c)
606+
or
607+
i = 1 and
608+
result = "::"
609+
or
610+
i = 2 and
611+
result = this.getName()
612+
}
613+
614+
language[monotonicAggregates]
615+
override string getCanonicalPath(Crate c) {
616+
c = this.getACanonicalPathCrate() and
617+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
618+
}
619+
620+
pragma[nomagic]
621+
private ItemNode getACanonicalPathChild() {
622+
exists(SourceFile f |
623+
fileImport(this, f) and
624+
sourceFileEdge(f, _, result)
625+
)
626+
or
627+
this = result.getImmediateParent()
628+
or
629+
exists(ItemNode mid |
630+
mid = this.getACanonicalPathChild() and
631+
mid.(MacroCallItemNode) = result.getImmediateParent()
632+
)
633+
}
634+
635+
override string getCanonicalPathPrefixFor(Crate c, ItemNode child) {
636+
child = this.getACanonicalPathChild() and
637+
result = this.getCanonicalPath(c)
638+
}
461639
}
462640

463641
private class StructItemNode extends ItemNode instanceof Struct {
@@ -473,6 +651,24 @@ private class StructItemNode extends ItemNode instanceof Struct {
473651
override Visibility getVisibility() { result = Struct.super.getVisibility() }
474652

475653
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
654+
655+
bindingset[c]
656+
private string getCanonicalPathPart(Crate c, int i) {
657+
i = 0 and
658+
result = this.getCanonicalPathPrefix(c)
659+
or
660+
i = 1 and
661+
result = "::"
662+
or
663+
i = 2 and
664+
result = this.getName()
665+
}
666+
667+
language[monotonicAggregates]
668+
override string getCanonicalPath(Crate c) {
669+
c = this.getACanonicalPathCrate() and
670+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
671+
}
476672
}
477673

478674
class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
@@ -492,6 +688,36 @@ class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
492688
override Visibility getVisibility() { result = Trait.super.getVisibility() }
493689

494690
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
691+
692+
bindingset[c]
693+
private string getCanonicalPathPart(Crate c, int i) {
694+
i = 0 and
695+
result = "<_ as "
696+
or
697+
i = 1 and
698+
result = this.getCanonicalPathPrefix(c)
699+
or
700+
i = 2 and
701+
result = "::"
702+
or
703+
i = 3 and
704+
result = this.getName()
705+
or
706+
i = 4 and
707+
result = ">"
708+
}
709+
710+
language[monotonicAggregates]
711+
override string getCanonicalPath(Crate c) {
712+
c = this.getACanonicalPathCrate() and
713+
result = strictconcat(int i | i in [1 .. 3] | this.getCanonicalPathPart(c, i) order by i)
714+
}
715+
716+
language[monotonicAggregates]
717+
override string getCanonicalPathPrefixFor(Crate c, ItemNode child) {
718+
result = strictconcat(int i | i in [0 .. 4] | this.getCanonicalPathPart(c, i) order by i) and
719+
child = this.getAnAssocItem()
720+
}
495721
}
496722

497723
class TypeAliasItemNode extends AssocItemNode instanceof TypeAlias {
@@ -514,6 +740,24 @@ private class UnionItemNode extends ItemNode instanceof Union {
514740
override Visibility getVisibility() { result = Union.super.getVisibility() }
515741

516742
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
743+
744+
bindingset[c]
745+
private string getCanonicalPathPart(Crate c, int i) {
746+
i = 0 and
747+
result = this.getCanonicalPathPrefix(c)
748+
or
749+
i = 1 and
750+
result = "::"
751+
or
752+
i = 2 and
753+
result = this.getName()
754+
}
755+
756+
language[monotonicAggregates]
757+
override string getCanonicalPath(Crate c) {
758+
c = this.getACanonicalPathCrate() and
759+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
760+
}
517761
}
518762

519763
private class UseItemNode extends ItemNode instanceof Use {
@@ -524,6 +768,8 @@ private class UseItemNode extends ItemNode instanceof Use {
524768
override Visibility getVisibility() { result = Use.super.getVisibility() }
525769

526770
override TypeParam getTypeParam(int i) { none() }
771+
772+
override string getCanonicalPath(Crate c) { none() }
527773
}
528774

529775
private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
@@ -534,6 +780,8 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
534780
override Visibility getVisibility() { none() }
535781

536782
override TypeParam getTypeParam(int i) { none() }
783+
784+
override string getCanonicalPath(Crate c) { none() }
537785
}
538786

539787
private class TypeParamItemNode extends ItemNode instanceof TypeParam {
@@ -589,6 +837,8 @@ private class TypeParamItemNode extends ItemNode instanceof TypeParam {
589837
override TypeParam getTypeParam(int i) { none() }
590838

591839
override Location getLocation() { result = TypeParam.super.getName().getLocation() }
840+
841+
override string getCanonicalPath(Crate c) { none() }
592842
}
593843

594844
/** 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
@@ -36,6 +36,12 @@ query predicate multipleTupleFields(FieldExpr fe, TupleField field) {
3636
strictcount(fe.getTupleField()) > 1
3737
}
3838

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

0 commit comments

Comments
 (0)