Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
* the canonical path `path` and the method name `method`, and if it borrows its
* first `borrows` arguments.
*/
private predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
arity = 1 and
(
// Negation
Expand Down
7 changes: 7 additions & 0 deletions rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ module Impl {
* ```
*/
class Union extends Generated::Union {
/** Gets the record field named `name`, if any. */
pragma[nomagic]
StructField getStructField(string name) {
result = this.getStructFieldList().getAField() and
result.getName().getText() = name
}

override string toStringImpl() { result = "union " + this.getName().getText() }
}
}
40 changes: 40 additions & 0 deletions rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,43 @@ class StringStruct extends Struct {
pragma[nomagic]
StringStruct() { this.getCanonicalPath() = "alloc::string::String" }
}

/**
* The [`Deref` trait][1].
*
* [1]: https://doc.rust-lang.org/core/ops/trait.Deref.html
*/
class DerefTrait extends Trait {
pragma[nomagic]
DerefTrait() { this.getCanonicalPath() = "core::ops::deref::Deref" }

/** Gets the `deref` function. */
Function getDerefFunction() { result = this.(TraitItemNode).getAssocItem("deref") }

/** Gets the `Target` associated type. */
pragma[nomagic]
TypeAlias getTargetType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Target"
}
}

/**
* The [`Index` trait][1].
*
* [1]: https://doc.rust-lang.org/std/ops/trait.Index.html
*/
class IndexTrait extends Trait {
pragma[nomagic]
IndexTrait() { this.getCanonicalPath() = "core::ops::index::Index" }

/** Gets the `index` function. */
Function getIndexFunction() { result = this.(TraitItemNode).getAssocItem("index") }

/** Gets the `Output` associated type. */
pragma[nomagic]
TypeAlias getOutputType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Output"
}
}
16 changes: 14 additions & 2 deletions rust/ql/lib/codeql/rust/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,8 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {

TraitItemNode resolveTraitTy() { result = resolvePath(this.getTraitPath()) }

predicate isBlanket() { this.resolveSelfTy() instanceof TypeParam }

override AssocItemNode getAnAssocItem() { result = this.getADescendant() }

override string getName() { result = "(impl)" }
Expand Down Expand Up @@ -721,7 +723,7 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
}
}

final private class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
final class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
pragma[nomagic]
Path getABoundPath() {
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
Expand Down Expand Up @@ -1444,6 +1446,16 @@ module TraitIsVisible<relevantTraitVisibleSig/2 relevantTraitVisible> {
predicate traitIsVisible(Element element, Trait trait) {
exists(ItemNode encl | traitLookup(encl, element, trait) and trait = encl.getASuccessor(_, _))
}

/** Holds if the trait `trait` is _not_ visible at `element`. */
pragma[nomagic]
predicate traitIsNotVisible(Element element, Trait trait) {
exists(ItemNode top |
traitLookup(top, element, trait) and
not exists(getOuterScope(top)) and
not trait = top.getASuccessor(_, _)
)
}
}

pragma[nomagic]
Expand Down Expand Up @@ -1740,7 +1752,7 @@ private module Debug {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
filepath.matches("%/main.rs") and
startline = 52
startline = 167
Comment on lines 1754 to +1755
Copy link
Preview

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hardcoded line number (167) in the debug module appears to be a leftover from development/testing. Consider removing this specific line constraint or making it configurable to avoid issues when the test file structure changes.

See below for a potential fix:

      filepath.matches("%/main.rs")

Copilot uses AI. Check for mistakes.

Copy link
Preview

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This hardcoded line number in the debug module should be removed or made configurable. Having hardcoded debug coordinates in production code can cause confusion and makes the code less maintainable.

See below for a potential fix:

  /**
   * Returns a relevant locatable for debugging, configurable by line number.
   */
  private Locatable getRelevantLocatable(int startline) {
    exists(string filepath, int sline, int startcolumn, int endline, int endcolumn |
      result.getLocation().hasLocationInfo(filepath, sline, startcolumn, endline, endcolumn) and
      filepath.matches("%/main.rs") and
      sline = startline
    )
  }

  /** Convenience: default line number for debugging. */
  private int defaultDebugStartLine() { result = 167 }

  /** Overload for backward compatibility: uses default line number. */
  private Locatable getRelevantLocatable() { result = getRelevantLocatable(defaultDebugStartLine()) }

  predicate debugUnqualifiedPathLookup(
    RelevantPath p, string name, Namespace ns, ItemNode encl, string path
  ) {
    p = getRelevantLocatable(defaultDebugStartLine()) and
    unqualifiedPathLookup(encl, name, ns, p) and
    path = p.toStringDebug()
  }

  ItemNode debugResolvePath(RelevantPath path) {
    path = getRelevantLocatable(defaultDebugStartLine()) and
    result = resolvePath(path)
  }

  predicate debugUseImportEdge(Use use, string name, ItemNode item, SuccessorKind kind) {
    use = getRelevantLocatable(defaultDebugStartLine()) and
    useImportEdge(use, name, item, kind)
  }

  ItemNode debugGetASuccessor(ItemNode i, string name, SuccessorKind kind) {
    i = getRelevantLocatable(defaultDebugStartLine()) and
    result = i.getASuccessor(name, kind)
  }

  predicate debugFileImportEdge(Module mod, string name, ItemNode item, SuccessorKind kind) {
    mod = getRelevantLocatable(defaultDebugStartLine()) and
    fileImportEdge(mod, name, item, kind)
  }

  predicate debugFileImport(Module m, SourceFile f) {
    m = getRelevantLocatable(defaultDebugStartLine()) and
    fileImport(m, f)
  }

  predicate debugPreludeEdge(SourceFile f, string name, ItemNode i) {
    preludeEdge(f, name, i) and
    f = getRelevantLocatable(defaultDebugStartLine())
  }

  string debugGetCanonicalPath(ItemNode i, Crate c) {
    result = i.getCanonicalPath(c) and
    i = getRelevantLocatable(defaultDebugStartLine())

Copilot uses AI. Check for mistakes.

)
}

Expand Down
64 changes: 63 additions & 1 deletion rust/ql/lib/codeql/rust/internal/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ newtype TType =
TStruct(Struct s) or
TEnum(Enum e) or
TTrait(Trait t) or
TUnion(Union u) or
TArrayType() or // todo: add size?
TRefType() or // todo: add mut?
TImplTraitType(ImplTraitTypeRepr impl) or
TDynTraitType(Trait t) { t = any(DynTraitTypeRepr dt).getTrait() } or
TSliceType() or
TNeverType() or
TPtrType() or
TTupleTypeParameter(int arity, int i) { exists(TTuple(arity)) and i in [0 .. arity - 1] } or
TTypeParamTypeParameter(TypeParam t) or
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
Expand All @@ -57,7 +60,8 @@ newtype TType =
} or
TRefTypeParameter() or
TSelfTypeParameter(Trait t) or
TSliceTypeParameter()
TSliceTypeParameter() or
TPtrTypeParameter()

private predicate implTraitTypeParam(ImplTraitTypeRepr implTrait, int i, TypeParam tp) {
implTrait.isInReturnPos() and
Expand Down Expand Up @@ -224,6 +228,31 @@ class TraitType extends Type, TTrait {
override Location getLocation() { result = trait.getLocation() }
}

/** A union type. */
class UnionType extends StructOrEnumType, TUnion {
private Union union;

UnionType() { this = TUnion(union) }

override ItemNode asItemNode() { result = union }

override StructField getStructField(string name) { result = union.getStructField(name) }

override TupleField getTupleField(int i) { none() }

override TypeParameter getPositionalTypeParameter(int i) {
result = TTypeParamTypeParameter(union.getGenericParamList().getTypeParam(i))
}

override TypeMention getTypeParameterDefault(int i) {
result = union.getGenericParamList().getTypeParam(i).getDefaultType()
}

override string toString() { result = union.getName().getText() }

override Location getLocation() { result = union.getLocation() }
}

/**
* An array type.
*
Expand Down Expand Up @@ -374,6 +403,33 @@ class SliceType extends Type, TSliceType {
override Location getLocation() { result instanceof EmptyLocation }
}

class NeverType extends Type, TNeverType {
override StructField getStructField(string name) { none() }

override TupleField getTupleField(int i) { none() }

override TypeParameter getPositionalTypeParameter(int i) { none() }

override string toString() { result = "!" }

override Location getLocation() { result instanceof EmptyLocation }
}

class PtrType extends Type, TPtrType {
override StructField getStructField(string name) { none() }

override TupleField getTupleField(int i) { none() }

override TypeParameter getPositionalTypeParameter(int i) {
i = 0 and
result = TPtrTypeParameter()
}

override string toString() { result = "*" }

override Location getLocation() { result instanceof EmptyLocation }
}

/** A type parameter. */
abstract class TypeParameter extends Type {
override StructField getStructField(string name) { none() }
Expand Down Expand Up @@ -529,6 +585,12 @@ class SliceTypeParameter extends TypeParameter, TSliceTypeParameter {
override Location getLocation() { result instanceof EmptyLocation }
}

class PtrTypeParameter extends TypeParameter, TPtrTypeParameter {
override string toString() { result = "*T" }

override Location getLocation() { result instanceof EmptyLocation }
}

/**
* The implicit `Self` type parameter of a trait, that refers to the
* implementing type of the trait.
Expand Down
Loading
Loading