diff --git a/rust/ql/lib/codeql/rust/internal/CachedStages.qll b/rust/ql/lib/codeql/rust/internal/CachedStages.qll index 4041b2731f97..2a7447ed7a3f 100644 --- a/rust/ql/lib/codeql/rust/internal/CachedStages.qll +++ b/rust/ql/lib/codeql/rust/internal/CachedStages.qll @@ -120,7 +120,7 @@ module Stages { or exists(resolvePath(_)) or - exists(any(ItemNode i).getASuccessor(_)) + exists(any(ItemNode i).getASuccessorFull(_)) or exists(any(ItemNode i).getASuccessorRec(_)) or diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index a6cc51a21c54..5bc45afecf17 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -172,9 +172,14 @@ abstract class ItemNode extends Locatable { result = this.(TypeParamItemNode).resolveABound().getASuccessorRec(name).(AssocItemNode) } - /** Gets a successor named `name` of this item, if any. */ + /** + * Gets a successor named `name` of this item, if any. + * + * Whenever a function exists in both source code and in library code, + * both are included + */ cached - ItemNode getASuccessor(string name) { + ItemNode getASuccessorFull(string name) { Stages::PathResolutionStage::ref() and result = this.getASuccessorRec(name) or @@ -202,6 +207,22 @@ abstract class ItemNode extends Locatable { result.(CrateItemNode).isPotentialDollarCrateTarget() } + /** Gets a successor named `name` of this item, if any. */ + pragma[nomagic] + ItemNode getASuccessor(string name) { + result = this.getASuccessorFull(name) and + ( + // when a function exists in both source code and in library code, it is because + // we also extracted the source code as library code, and hence we only want + // the function from source code + result.fromSource() + or + not result instanceof Function + or + not this.getASuccessorFull(name).(Function).fromSource() + ) + } + /** Gets the location of this item. */ Location getLocation() { result = super.getLocation() } } @@ -234,7 +255,7 @@ abstract private class ModuleLikeNode extends ItemNode { private class SourceFileItemNode extends ModuleLikeNode, SourceFile { pragma[nomagic] ModuleLikeNode getSuper() { - result = any(ModuleItemNode mod | fileImport(mod, this)).getASuccessor("super") + result = any(ModuleItemNode mod | fileImport(mod, this)).getASuccessorFull("super") } override string getName() { result = "(source file)" } @@ -297,7 +318,7 @@ class CrateItemNode extends ItemNode instanceof Crate { predicate isPotentialDollarCrateTarget() { exists(string name, RelevantPath p | p.isDollarCrateQualifiedPath(name) and - exists(this.getASuccessor(name)) + exists(this.getASuccessorFull(name)) ) } @@ -323,7 +344,14 @@ abstract private class AssocItemNode extends ItemNode, AssocItem { private class ConstItemNode extends AssocItemNode instanceof Const { override string getName() { result = Const.super.getName().getText() } - override predicate hasImplementation() { super.hasBody() } + override predicate hasImplementation() { + super.hasBody() + or + // for trait items from library code, we do not currently know if they + // have default implementations or not, so we assume they do + not this.fromSource() and + this = any(TraitItemNode t).getAnAssocItem() + } override Namespace getNamespace() { result.isValue() } @@ -359,7 +387,14 @@ private class VariantItemNode extends ItemNode instanceof Variant { class FunctionItemNode extends AssocItemNode instanceof Function { override string getName() { result = Function.super.getName().getText() } - override predicate hasImplementation() { super.hasBody() } + override predicate hasImplementation() { + super.hasBody() + or + // for trait items from library code, we do not currently know if they + // have default implementations or not, so we assume they do + not this.fromSource() and + this = any(TraitItemNode t).getAnAssocItem() + } override Namespace getNamespace() { result.isValue() } @@ -862,6 +897,12 @@ class RelevantPath extends Path { this.getQualifier().(RelevantPath).isCratePath("$crate", _) and this.getText() = name } + + // TODO: Remove once the crate graph extractor generates publicly visible paths + predicate requiresExtractorWorkaround() { + not this.fromSource() and + this = any(RelevantPath p).getQualifier() + } } private predicate isModule(ItemNode m) { m instanceof Module } @@ -916,8 +957,8 @@ private predicate unqualifiedPathLookup(ItemNode encl, string name, Namespace ns } pragma[nomagic] -private ItemNode getASuccessor(ItemNode pred, string name, Namespace ns) { - result = pred.getASuccessor(name) and +private ItemNode getASuccessorFull(ItemNode pred, string name, Namespace ns) { + result = pred.getASuccessorFull(name) and ns = result.getNamespace() } @@ -954,7 +995,7 @@ private predicate keywordLookup(ItemNode encl, string name, Namespace ns, Releva pragma[nomagic] private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns) { - exists(ItemNode encl, string name | result = getASuccessor(encl, name, ns) | + exists(ItemNode encl, string name | result = getASuccessorFull(encl, name, ns) | unqualifiedPathLookup(encl, name, ns, p) or keywordLookup(encl, name, ns, p) @@ -978,7 +1019,7 @@ private ItemNode resolvePath0(RelevantPath path, Namespace ns) { or exists(ItemNode q, string name | q = resolvePathQualifier(path, name) and - result = getASuccessor(q, name, ns) + result = getASuccessorFull(q, name, ns) ) or result = resolveUseTreeListItem(_, _, path) and @@ -1029,6 +1070,7 @@ pragma[nomagic] private ItemNode resolvePathPrivate( RelevantPath path, ModuleLikeNode itemParent, ModuleLikeNode pathParent ) { + not path.requiresExtractorWorkaround() and result = resolvePath1(path) and itemParent = result.getImmediateParentModule() and not result.isPublic() and @@ -1062,7 +1104,11 @@ private ModuleLikeNode getAPrivateVisibleModule(ModuleLikeNode itemParent) { cached ItemNode resolvePath(RelevantPath path) { result = resolvePath1(path) and - result.isPublic() + ( + result.isPublic() + or + path.requiresExtractorWorkaround() + ) or exists(ModuleLikeNode itemParent, ModuleLikeNode pathParent | result = resolvePathPrivate(path, itemParent, pathParent) and @@ -1098,12 +1144,12 @@ private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path mid = resolveUseTreeListItem(use, midTree) and tree = midTree.getUseTreeList().getAUseTree() and isUseTreeSubPathUnqualified(tree, path, pragma[only_bind_into](name)) and - result = mid.getASuccessor(pragma[only_bind_into](name)) + result = mid.getASuccessorFull(pragma[only_bind_into](name)) ) or exists(ItemNode q, string name | q = resolveUseTreeListItemQualifier(use, tree, path, name) and - result = q.getASuccessor(name) + result = q.getASuccessorFull(name) ) } @@ -1133,7 +1179,7 @@ private predicate useImportEdge(Use use, string name, ItemNode item) { then exists(ItemNode encl, Namespace ns | encl.getADescendant() = use and - item = getASuccessor(used, name, ns) and + item = getASuccessorFull(used, name, ns) and // glob imports can be shadowed not declares(encl, ns, name) and not name = ["super", "self", "Self", "$crate", "crate"]