mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Merge branch 'main' into mapfix
This commit is contained in:
@@ -8,7 +8,8 @@ module Impl {
|
||||
TPositionalArgumentPosition(int i) {
|
||||
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
|
||||
} or
|
||||
TSelfArgumentPosition()
|
||||
TSelfArgumentPosition() or
|
||||
TTypeQualifierArgumentPosition()
|
||||
|
||||
/** An argument position in a call. */
|
||||
class ArgumentPosition extends TArgumentPosition {
|
||||
@@ -16,13 +17,28 @@ module Impl {
|
||||
int asPosition() { this = TPositionalArgumentPosition(result) }
|
||||
|
||||
/** Holds if this call position is a self argument. */
|
||||
predicate isSelf() { this instanceof TSelfArgumentPosition }
|
||||
predicate isSelf() { this = TSelfArgumentPosition() }
|
||||
|
||||
/**
|
||||
* Holds if this call position is a type qualifier, that is, not an actual
|
||||
* argument, but rather an annotation that is needed to resolve the call target,
|
||||
* just like actual arguments may be needed to resolve the call target.
|
||||
*
|
||||
* Example:
|
||||
* ```rust
|
||||
* Vec<i64>::new();
|
||||
* // ^^^^^^^^ type qualifier
|
||||
* ```
|
||||
*/
|
||||
predicate isTypeQualifier() { this = TTypeQualifierArgumentPosition() }
|
||||
|
||||
/** Gets a string representation of this argument position. */
|
||||
string toString() {
|
||||
result = this.asPosition().toString()
|
||||
or
|
||||
this.isSelf() and result = "self"
|
||||
or
|
||||
this.isTypeQualifier() and result = "type qualifier"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class SuccessorKind extends TSuccessorKind {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind kind) {
|
||||
private ItemNode getAChildSuccessor0(ItemNode item, string name, SuccessorKind kind) {
|
||||
item = result.getImmediateParent() and
|
||||
name = result.getName() and
|
||||
// Associated items in `impl` and `trait` blocks are handled elsewhere
|
||||
@@ -116,7 +116,7 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki
|
||||
if result instanceof TypeParam
|
||||
then kind.isInternal()
|
||||
else
|
||||
if result.isPublic()
|
||||
if result.isPublic() or item instanceof SourceFile
|
||||
then kind.isBoth()
|
||||
else kind.isInternal()
|
||||
or
|
||||
@@ -130,6 +130,41 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki
|
||||
result = item
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private NamedItemNode getANamedNonModuleChildSuccessor(
|
||||
ItemNode item, string name, Namespace ns, int startline, int startcolumn, int endline,
|
||||
int endcolumn
|
||||
) {
|
||||
result.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn) and
|
||||
result = getAChildSuccessor0(item, name, _) and
|
||||
ns = result.getNamespace() and
|
||||
not result instanceof ModuleItemNode
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind kind) {
|
||||
result = getAChildSuccessor0(item, name, kind) and
|
||||
// In valid Rust code, there cannot be multiple children with the same name and namespace,
|
||||
// but to safeguard against combinatorial explosions in invalid code, we always pick the
|
||||
// last child, except for modules, where we take the union.
|
||||
(
|
||||
not result instanceof NamedItemNode
|
||||
or
|
||||
result instanceof ModuleItemNode
|
||||
or
|
||||
exists(Namespace ns |
|
||||
result =
|
||||
max(NamedItemNode i, int startline, int startcolumn, int endline, int endcolumn |
|
||||
i =
|
||||
getANamedNonModuleChildSuccessor(item, name, ns, startline, startcolumn, endline,
|
||||
endcolumn)
|
||||
|
|
||||
i order by startline, startcolumn, endline, endcolumn
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private module UseOption = Option<Use>;
|
||||
|
||||
private class UseOption = UseOption::Option;
|
||||
@@ -288,10 +323,6 @@ abstract class ItemNode extends Locatable {
|
||||
cached
|
||||
ItemNode getASuccessor(string name, SuccessorKind kind, UseOption useOpt) {
|
||||
Stages::PathResolutionStage::ref() and
|
||||
sourceFileEdge(this, name, result) and
|
||||
kind.isBoth() and
|
||||
useOpt.isNone()
|
||||
or
|
||||
result = getAChildSuccessor(this, name, kind) and
|
||||
useOpt.isNone()
|
||||
or
|
||||
@@ -471,6 +502,8 @@ abstract class ItemNode extends Locatable {
|
||||
Location getLocation() { result = super.getLocation() }
|
||||
}
|
||||
|
||||
abstract class NamedItemNode extends ItemNode { }
|
||||
|
||||
abstract class TypeItemNode extends ItemNode { }
|
||||
|
||||
/** A module or a source file. */
|
||||
@@ -509,7 +542,7 @@ private class SourceFileItemNode extends ModuleLikeNode instanceof SourceFile {
|
||||
override string getCanonicalPath(Crate c) { none() }
|
||||
}
|
||||
|
||||
class CrateItemNode extends ItemNode instanceof Crate {
|
||||
class CrateItemNode extends NamedItemNode instanceof Crate {
|
||||
/**
|
||||
* Gets the source file that defines this crate.
|
||||
*/
|
||||
@@ -565,7 +598,7 @@ class CrateItemNode extends ItemNode instanceof Crate {
|
||||
override string getCanonicalPath(Crate c) { c = this and result = Crate.super.getName() }
|
||||
}
|
||||
|
||||
class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
|
||||
class ExternCrateItemNode extends NamedItemNode instanceof ExternCrate {
|
||||
override string getName() {
|
||||
result = super.getRename().getName().getText()
|
||||
or
|
||||
@@ -573,7 +606,7 @@ class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
|
||||
result = super.getIdentifier().getText()
|
||||
}
|
||||
|
||||
override Namespace getNamespace() { none() }
|
||||
override Namespace getNamespace() { result.isType() }
|
||||
|
||||
override Visibility getVisibility() { result = ExternCrate.super.getVisibility() }
|
||||
|
||||
@@ -587,7 +620,7 @@ class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
|
||||
}
|
||||
|
||||
/** An item that can occur in a trait or an `impl` block. */
|
||||
abstract private class AssocItemNode extends ItemNode instanceof AssocItem {
|
||||
abstract private class AssocItemNode extends NamedItemNode instanceof AssocItem {
|
||||
/** Holds if this associated item has an implementation. */
|
||||
abstract predicate hasImplementation();
|
||||
|
||||
@@ -626,7 +659,7 @@ private class ConstItemNode extends AssocItemNode instanceof Const {
|
||||
override TypeParam getTypeParam(int i) { none() }
|
||||
}
|
||||
|
||||
private class TypeItemTypeItemNode extends TypeItemNode instanceof TypeItem {
|
||||
private class TypeItemTypeItemNode extends NamedItemNode, TypeItemNode instanceof TypeItem {
|
||||
override string getName() { result = TypeItem.super.getName().getText() }
|
||||
|
||||
override Namespace getNamespace() { result.isType() }
|
||||
@@ -659,7 +692,7 @@ private class TypeItemTypeItemNode extends TypeItemNode instanceof TypeItem {
|
||||
}
|
||||
|
||||
/** An item that can be referenced with arguments. */
|
||||
abstract class ParameterizableItemNode extends ItemNode {
|
||||
abstract class ParameterizableItemNode extends NamedItemNode {
|
||||
/** Gets the arity this item. */
|
||||
abstract int getArity();
|
||||
}
|
||||
@@ -911,7 +944,7 @@ private class ImplTraitTypeReprItemNodeImpl extends ImplTraitTypeReprItemNode {
|
||||
ItemNode resolveABoundCand() { result = resolvePathCand(this.getABoundPath()) }
|
||||
}
|
||||
|
||||
private class ModuleItemNode extends ModuleLikeNode instanceof Module {
|
||||
private class ModuleItemNode extends NamedItemNode, ModuleLikeNode instanceof Module {
|
||||
override string getName() { result = Module.super.getName().getText() }
|
||||
|
||||
override Namespace getNamespace() { result.isType() }
|
||||
@@ -929,7 +962,7 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
|
||||
(
|
||||
exists(SourceFile f |
|
||||
fileImport(this, f) and
|
||||
sourceFileEdge(f, _, child)
|
||||
child = getAChildSuccessor(f, _, _)
|
||||
)
|
||||
or
|
||||
this = child.getImmediateParent()
|
||||
@@ -1001,7 +1034,7 @@ private class StructItemNode extends TypeItemTypeItemNode, ParameterizableItemNo
|
||||
}
|
||||
}
|
||||
|
||||
final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof Trait {
|
||||
final class TraitItemNode extends ImplOrTraitItemNode, NamedItemNode, TypeItemNode instanceof Trait {
|
||||
pragma[nomagic]
|
||||
Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() }
|
||||
|
||||
@@ -1126,7 +1159,7 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
|
||||
pragma[nomagic]
|
||||
private Path getWherePredPath(WherePred wp) { result = wp.getTypeRepr().(PathTypeRepr).getPath() }
|
||||
|
||||
final class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
|
||||
final class TypeParamItemNode extends NamedItemNode, TypeItemNode instanceof TypeParam {
|
||||
/** Gets a where predicate for this type parameter, if any */
|
||||
pragma[nomagic]
|
||||
private WherePred getAWherePred() {
|
||||
@@ -1214,7 +1247,7 @@ final private class TypeParamItemNodeImpl extends TypeParamItemNode instanceof T
|
||||
ItemNode resolveABoundCand() { result = resolvePathCand(this.getABoundPathCand()) }
|
||||
}
|
||||
|
||||
abstract private class MacroItemNode extends ItemNode {
|
||||
abstract private class MacroItemNode extends NamedItemNode {
|
||||
override Namespace getNamespace() { result.isMacro() }
|
||||
|
||||
override TypeParam getTypeParam(int i) { none() }
|
||||
@@ -1256,12 +1289,6 @@ private class MacroDefItemNode extends MacroItemNode instanceof MacroDef {
|
||||
override Attr getAnAttr() { result = MacroDef.super.getAnAttr() }
|
||||
}
|
||||
|
||||
/** Holds if `item` has the name `name` and is a top-level item inside `f`. */
|
||||
private predicate sourceFileEdge(SourceFile f, string name, ItemNode item) {
|
||||
item = f.(ItemNode).getADescendant() and
|
||||
name = item.getName()
|
||||
}
|
||||
|
||||
/** Holds if `f` is available as `mod name;` inside `folder`. */
|
||||
pragma[nomagic]
|
||||
private predicate fileModule(SourceFile f, string name, Folder folder) {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Provides classes and helper predicates for associated types.
|
||||
*/
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import TypeMention
|
||||
private import Type
|
||||
private import TypeInference
|
||||
|
||||
/** An associated type, that is, a type alias in a trait block. */
|
||||
final class AssocType extends TypeAlias {
|
||||
Trait trait;
|
||||
|
||||
AssocType() { this = trait.getAssocItemList().getAnAssocItem() }
|
||||
|
||||
Trait getTrait() { result = trait }
|
||||
|
||||
string getText() { result = this.getName().getText() }
|
||||
}
|
||||
|
||||
/** Gets an associated type of `trait` or of a supertrait of `trait`. */
|
||||
AssocType getTraitAssocType(Trait trait) { result.getTrait() = trait.getSupertrait*() }
|
||||
|
||||
/** Holds if `path` is of the form `<type as trait>::name` */
|
||||
pragma[nomagic]
|
||||
predicate pathTypeAsTraitAssoc(Path path, TypeRepr typeRepr, Path traitPath, string name) {
|
||||
exists(PathSegment segment |
|
||||
segment = path.getQualifier().getSegment() and
|
||||
typeRepr = segment.getTypeRepr() and
|
||||
traitPath = segment.getTraitTypeRepr().getPath() and
|
||||
name = path.getText()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `assoc` is accessed on `tp` in `path`.
|
||||
*
|
||||
* That is, this is the case when `path` is of the form `<tp as
|
||||
* Trait>::AssocType` or `tp::AssocType`; and `AssocType` resolves to `assoc`.
|
||||
*/
|
||||
predicate tpAssociatedType(TypeParam tp, AssocType assoc, Path path) {
|
||||
resolvePath(path.getQualifier()) = tp and
|
||||
resolvePath(path) = assoc
|
||||
or
|
||||
exists(PathTypeRepr typeRepr, Path traitPath, string name |
|
||||
pathTypeAsTraitAssoc(path, typeRepr, traitPath, name) and
|
||||
tp = resolvePath(typeRepr.getPath()) and
|
||||
assoc = resolvePath(traitPath).(TraitItemNode).getAssocItem(name)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a type bound for `tp` that gives rise to `assoc` being
|
||||
* present for `tp`.
|
||||
*/
|
||||
predicate tpBoundAssociatedType(
|
||||
TypeParam tp, TypeBound bound, Path path, TraitItemNode trait, AssocType assoc
|
||||
) {
|
||||
bound = tp.getATypeBound() and
|
||||
path = bound.getTypeRepr().(PathTypeRepr).getPath() and
|
||||
trait = resolvePath(path) and
|
||||
assoc = getTraitAssocType(trait)
|
||||
}
|
||||
@@ -20,13 +20,12 @@ class DerefImplItemNode extends ImplItemNode {
|
||||
Type resolveSelfTypeAt(TypePath path) { result = resolveImplSelfTypeAt(this, path) }
|
||||
|
||||
/**
|
||||
* Holds if the target type of the dereference implemention mentions a type
|
||||
* parameter at `path`.
|
||||
* Holds if the target type of the dereference implementation mentions type
|
||||
* parameter `tp` at `path`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate targetHasTypeParameterAt(TypePath path) {
|
||||
this.getAssocItem("Target").(TypeAlias).getTypeRepr().(TypeMention).getTypeAt(path) instanceof
|
||||
TypeParameter
|
||||
predicate targetHasTypeParameterAt(TypePath path, TypeParameter tp) {
|
||||
tp = this.getAssocItem("Target").(TypeAlias).getTypeRepr().(TypeMention).getTypeAt(path)
|
||||
}
|
||||
|
||||
/** Gets the first type parameter of the type being implemented, if any. */
|
||||
|
||||
@@ -77,32 +77,23 @@ pragma[nomagic]
|
||||
private predicate implHasSibling(ImplItemNode impl, Trait trait) { implSiblings(trait, impl, _) }
|
||||
|
||||
/**
|
||||
* Holds if type parameter `tp` of `trait` occurs in the function `f` with the name
|
||||
* `functionName` at position `pos` and path `path`.
|
||||
*
|
||||
* Note that `pos` can also be the special `return` position, which is sometimes
|
||||
* needed to disambiguate associated function calls like `Default::default()`
|
||||
* (in this case, `tp` is the special `Self` type parameter).
|
||||
*/
|
||||
bindingset[trait]
|
||||
pragma[inline_late]
|
||||
predicate traitTypeParameterOccurrence(
|
||||
TraitItemNode trait, Function f, string functionName, FunctionPosition pos, TypePath path,
|
||||
TypeParameter tp
|
||||
) {
|
||||
f = trait.getASuccessor(functionName) and
|
||||
tp = getAssocFunctionTypeAt(f, trait, pos, path) and
|
||||
tp = trait.(TraitTypeAbstraction).getATypeParameter()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if resolving the function `f` in `impl` with the name `functionName`
|
||||
* requires inspecting the type of applied _arguments_ at position `pos` in
|
||||
* order to determine whether it is the correct resolution.
|
||||
* Holds if `f` is a function declared inside `trait`, and the type of `f` at
|
||||
* `pos` and `path` is `traitTp`, which is a type parameter of `trait`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate functionResolutionDependsOnArgument(
|
||||
ImplItemNode impl, Function f, FunctionPosition pos, TypePath path, Type type
|
||||
predicate traitTypeParameterOccurrence(
|
||||
TraitItemNode trait, Function f, string functionName, FunctionPosition pos, TypePath path,
|
||||
TypeParameter traitTp
|
||||
) {
|
||||
f = trait.getAssocItem(functionName) and
|
||||
traitTp = getAssocFunctionTypeAt(f, trait, pos, path) and
|
||||
traitTp = trait.(TraitTypeAbstraction).getATypeParameter()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate functionResolutionDependsOnArgumentCand(
|
||||
ImplItemNode impl, Function f, string functionName, TypeParameter traitTp, FunctionPosition pos,
|
||||
TypePath path
|
||||
) {
|
||||
/*
|
||||
* As seen in the example below, when an implementation has a sibling for a
|
||||
@@ -129,11 +120,114 @@ predicate functionResolutionDependsOnArgument(
|
||||
* method. In that case we will still resolve several methods.
|
||||
*/
|
||||
|
||||
exists(TraitItemNode trait, string functionName |
|
||||
exists(TraitItemNode trait |
|
||||
implHasSibling(impl, trait) and
|
||||
traitTypeParameterOccurrence(trait, _, functionName, pos, path, _) and
|
||||
type = getAssocFunctionTypeAt(f, impl, pos, path) and
|
||||
traitTypeParameterOccurrence(trait, _, functionName, pos, path, traitTp) and
|
||||
f = impl.getASuccessor(functionName) and
|
||||
not pos.isSelfOrTypeQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate functionResolutionDependsOnPositionalArgumentCand(
|
||||
ImplItemNode impl, Function f, string functionName, TypeParameter traitTp
|
||||
) {
|
||||
exists(FunctionPosition pos |
|
||||
functionResolutionDependsOnArgumentCand(impl, f, functionName, traitTp, pos, _) and
|
||||
pos.isPosition()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Type getAssocFunctionNonTypeParameterTypeAt(
|
||||
ImplItemNode impl, Function f, FunctionPosition pos, TypePath path
|
||||
) {
|
||||
result = getAssocFunctionTypeAt(f, impl, pos, path) and
|
||||
not result instanceof TypeParameter
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` inside `impl` has a sibling implementation inside `sibling`, where
|
||||
* those two implementations agree on the instantiation of `traitTp`, which occurs
|
||||
* in a positional position inside `f`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate hasEquivalentPositionalSibling(
|
||||
ImplItemNode impl, ImplItemNode sibling, Function f, TypeParameter traitTp
|
||||
) {
|
||||
exists(string functionName, FunctionPosition pos, TypePath path |
|
||||
functionResolutionDependsOnArgumentCand(impl, f, functionName, traitTp, pos, path) and
|
||||
pos.isPosition()
|
||||
|
|
||||
exists(Function f1 |
|
||||
implSiblings(_, impl, sibling) and
|
||||
f1 = sibling.getASuccessor(functionName)
|
||||
|
|
||||
forall(TypePath path0, Type t |
|
||||
t = getAssocFunctionNonTypeParameterTypeAt(impl, f, pos, path0) and
|
||||
path = path0.getAPrefix()
|
||||
|
|
||||
t = getAssocFunctionNonTypeParameterTypeAt(sibling, f1, pos, path0)
|
||||
) and
|
||||
forall(TypePath path0, Type t |
|
||||
t = getAssocFunctionNonTypeParameterTypeAt(sibling, f1, pos, path0) and
|
||||
path = path0.getAPrefix()
|
||||
|
|
||||
t = getAssocFunctionNonTypeParameterTypeAt(impl, f, pos, path0)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if resolving the function `f` in `impl` requires inspecting the type
|
||||
* of applied _arguments_ or possibly knowing the return type.
|
||||
*
|
||||
* `traitTp` is a type parameter of the trait being implemented by `impl`, and
|
||||
* we need to check that the type of `f` corresponding to `traitTp` is satisfied
|
||||
* at any one of the positions `pos` in which that type occurs in `f`.
|
||||
*
|
||||
* Type parameters that only occur in return positions are only included when
|
||||
* all other type parameters that occur in a positional position are insufficient
|
||||
* to disambiguate.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* trait Trait1<T1> {
|
||||
* fn f(self, x: T1) -> T1;
|
||||
* }
|
||||
*
|
||||
* impl Trait1<i32> for i32 {
|
||||
* fn f(self, x: i32) -> i32 { 0 } // f1
|
||||
* }
|
||||
*
|
||||
* impl Trait1<i64> for i32 {
|
||||
* fn f(self, x: i64) -> i64 { 0 } // f2
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The type for `T1` above occurs in both a positional position and a return position
|
||||
* in `f`, so both may be used to disambiguate between `f1` and `f2`. That is, `f(0i32)`
|
||||
* is sufficient to resolve to `f1`, and so is `let y: i64 = f(Default::default())`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate functionResolutionDependsOnArgument(
|
||||
ImplItemNode impl, Function f, TypeParameter traitTp, FunctionPosition pos
|
||||
) {
|
||||
exists(string functionName |
|
||||
functionResolutionDependsOnArgumentCand(impl, f, functionName, traitTp, pos, _)
|
||||
|
|
||||
if functionResolutionDependsOnPositionalArgumentCand(impl, f, functionName, traitTp)
|
||||
then any()
|
||||
else
|
||||
// `traitTp` only occurs in return position; check that it is indeed needed for disambiguation
|
||||
exists(ImplItemNode sibling |
|
||||
implSiblings(_, impl, sibling) and
|
||||
forall(TypeParameter otherTraitTp |
|
||||
functionResolutionDependsOnPositionalArgumentCand(impl, f, functionName, otherTraitTp)
|
||||
|
|
||||
hasEquivalentPositionalSibling(impl, sibling, f, otherTraitTp)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ class FunctionPosition extends TFunctionPosition {
|
||||
|
||||
ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) }
|
||||
|
||||
predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() }
|
||||
|
||||
predicate isSelfOrTypeQualifier() { this.isSelf() or this.isTypeQualifier() }
|
||||
|
||||
predicate isReturn() { this = TReturnFunctionPosition() }
|
||||
|
||||
/** Gets the corresponding position when `f` is invoked via a function call. */
|
||||
@@ -82,7 +86,9 @@ private newtype TAssocFunctionType =
|
||||
// through `i`. This ensures that `parent` is either a supertrait of `i` or
|
||||
// `i` in an `impl` block implementing `parent`.
|
||||
(parent = i or BaseTypes::rootTypesSatisfaction(_, TTrait(parent), i, _, _)) and
|
||||
exists(pos.getTypeMention(f))
|
||||
// We always include the type qualifier position, even for non-methods, where it is used
|
||||
// to match type qualifiers against the `impl` or trait type, such as in `Vec::new`.
|
||||
(exists(pos.getTypeMention(f)) or pos.isTypeQualifier())
|
||||
}
|
||||
|
||||
bindingset[abs, constraint, tp]
|
||||
@@ -114,6 +120,10 @@ Type getAssocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition
|
||||
else result = getTraitConstraintTypeAt(i, constraint, tp, suffix)
|
||||
)
|
||||
)
|
||||
or
|
||||
f = i.getASuccessor(_) and
|
||||
pos.isTypeQualifier() and
|
||||
result = resolveImplOrTraitType(i, path)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,16 +193,19 @@ class AssocFunctionType extends MkAssocFunctionType {
|
||||
)
|
||||
}
|
||||
|
||||
private TypeMention getTypeMention() {
|
||||
exists(Function f, FunctionPosition pos |
|
||||
this.appliesTo(f, _, pos) and
|
||||
private AstNode getIdentifyingNode() {
|
||||
exists(Function f, ImplOrTraitItemNode i, FunctionPosition pos | this.appliesTo(f, i, pos) |
|
||||
result = pos.getTypeMention(f)
|
||||
or
|
||||
pos.isSelf() and
|
||||
not f.hasSelfParam() and
|
||||
result = [i.(Impl).getSelfTy().(AstNode), i.(Trait).getName()]
|
||||
)
|
||||
}
|
||||
|
||||
string toString() { result = this.getTypeMention().toString() }
|
||||
string toString() { result = this.getIdentifyingNode().toString() }
|
||||
|
||||
Location getLocation() { result = this.getTypeMention().getLocation() }
|
||||
Location getLocation() { result = this.getIdentifyingNode().getLocation() }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -294,10 +307,15 @@ module ArgIsInstantiationOf<
|
||||
*/
|
||||
signature module ArgsAreInstantiationsOfInputSig {
|
||||
/**
|
||||
* Holds if types need to be matched against the type `t` at position `pos` of
|
||||
* `f` inside `i`.
|
||||
* Holds if `f` inside `i` needs to have the type corresponding to type parameter
|
||||
* `tp` checked.
|
||||
*
|
||||
* If `i` is an inherent implementation, `tp` is a type parameter of the type being
|
||||
* implemented, otherwise `tp` is a type parameter of the trait (being implemented).
|
||||
*
|
||||
* `pos` is one of the positions in `f` in which the relevant type occours.
|
||||
*/
|
||||
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t);
|
||||
predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos);
|
||||
|
||||
/** A call whose argument types are to be checked. */
|
||||
class Call {
|
||||
@@ -318,23 +336,27 @@ signature module ArgsAreInstantiationsOfInputSig {
|
||||
*/
|
||||
module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
|
||||
pragma[nomagic]
|
||||
private predicate toCheckRanked(ImplOrTraitItemNode i, Function f, FunctionPosition pos, int rnk) {
|
||||
Input::toCheck(i, f, pos, _) and
|
||||
pos =
|
||||
rank[rnk + 1](FunctionPosition pos0, int j |
|
||||
Input::toCheck(i, f, pos0, _) and
|
||||
(
|
||||
j = pos0.asPosition()
|
||||
or
|
||||
pos0.isSelf() and j = -1
|
||||
or
|
||||
pos0.isReturn() and j = -2
|
||||
)
|
||||
private predicate toCheckRanked(
|
||||
ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos, int rnk
|
||||
) {
|
||||
Input::toCheck(i, f, tp, pos) and
|
||||
tp =
|
||||
rank[rnk + 1](TypeParameter tp0, int j |
|
||||
Input::toCheck(i, f, tp0, _) and
|
||||
j = getTypeParameterId(tp0)
|
||||
|
|
||||
pos0 order by j
|
||||
tp0 order by j
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate toCheck(
|
||||
ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos, AssocFunctionType t
|
||||
) {
|
||||
Input::toCheck(i, f, tp, pos) and
|
||||
t.appliesTo(f, i, pos)
|
||||
}
|
||||
|
||||
private newtype TCallAndPos =
|
||||
MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) }
|
||||
|
||||
@@ -356,26 +378,26 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
|
||||
string toString() { result = call.toString() + " [arg " + pos + "]" }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate potentialInstantiationOf0(
|
||||
CallAndPos cp, Input::Call call, TypeParameter tp, FunctionPosition pos, Function f,
|
||||
TypeAbstraction abs, AssocFunctionType constraint
|
||||
) {
|
||||
cp = MkCallAndPos(call, pragma[only_bind_into](pos)) and
|
||||
call.hasTargetCand(abs, f) and
|
||||
toCheck(abs, f, tp, pragma[only_bind_into](pos), constraint)
|
||||
}
|
||||
|
||||
private module ArgIsInstantiationOfToIndexInput implements
|
||||
IsInstantiationOfInputSig<CallAndPos, AssocFunctionType>
|
||||
{
|
||||
pragma[nomagic]
|
||||
private predicate potentialInstantiationOf0(
|
||||
CallAndPos cp, Input::Call call, FunctionPosition pos, int rnk, Function f,
|
||||
TypeAbstraction abs, AssocFunctionType constraint
|
||||
) {
|
||||
cp = MkCallAndPos(call, pragma[only_bind_into](pos)) and
|
||||
call.hasTargetCand(abs, f) and
|
||||
toCheckRanked(abs, f, pragma[only_bind_into](pos), rnk) and
|
||||
Input::toCheck(abs, f, pragma[only_bind_into](pos), constraint)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate potentialInstantiationOf(
|
||||
CallAndPos cp, TypeAbstraction abs, AssocFunctionType constraint
|
||||
) {
|
||||
exists(Input::Call call, int rnk, Function f |
|
||||
potentialInstantiationOf0(cp, call, _, rnk, f, abs, constraint)
|
||||
exists(Input::Call call, TypeParameter tp, FunctionPosition pos, int rnk, Function f |
|
||||
potentialInstantiationOf0(cp, call, tp, pos, f, abs, constraint) and
|
||||
toCheckRanked(abs, f, tp, pos, rnk)
|
||||
|
|
||||
rnk = 0
|
||||
or
|
||||
@@ -383,54 +405,83 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate relevantConstraint(AssocFunctionType constraint) {
|
||||
Input::toCheck(_, _, _, constraint)
|
||||
}
|
||||
predicate relevantConstraint(AssocFunctionType constraint) { toCheck(_, _, _, _, constraint) }
|
||||
}
|
||||
|
||||
private module ArgIsInstantiationOfToIndex =
|
||||
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfToIndexInput>;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argIsInstantiationOf(
|
||||
Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i, Function f, int rnk
|
||||
) {
|
||||
ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
|
||||
toCheckRanked(i, f, _, pos, rnk)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argsAreInstantiationsOfToIndex(
|
||||
Input::Call call, ImplOrTraitItemNode i, Function f, int rnk
|
||||
) {
|
||||
exists(FunctionPosition pos |
|
||||
ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
|
||||
call.hasTargetCand(i, f) and
|
||||
toCheckRanked(i, f, pos, rnk)
|
||||
argIsInstantiationOf(call, pos, i, f, rnk) and
|
||||
call.hasTargetCand(i, f)
|
||||
|
|
||||
rnk = 0
|
||||
or
|
||||
argsAreInstantiationsOfToIndex(call, i, f, rnk - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all arguments of `call` have types that are instantiations of the
|
||||
* types of the corresponding parameters of `f` inside `i`.
|
||||
*
|
||||
* TODO: Check type parameter constraints as well.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate argsAreInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) {
|
||||
exists(int rnk |
|
||||
argsAreInstantiationsOfToIndex(call, i, f, rnk) and
|
||||
rnk = max(int r | toCheckRanked(i, f, _, r))
|
||||
rnk = max(int r | toCheckRanked(i, f, _, _, r))
|
||||
)
|
||||
}
|
||||
|
||||
private module ArgsAreNotInstantiationOfInput implements
|
||||
IsInstantiationOfInputSig<CallAndPos, AssocFunctionType>
|
||||
{
|
||||
pragma[nomagic]
|
||||
predicate potentialInstantiationOf(
|
||||
CallAndPos cp, TypeAbstraction abs, AssocFunctionType constraint
|
||||
) {
|
||||
potentialInstantiationOf0(cp, _, _, _, _, abs, constraint)
|
||||
}
|
||||
|
||||
predicate relevantConstraint(AssocFunctionType constraint) { toCheck(_, _, _, _, constraint) }
|
||||
}
|
||||
|
||||
private module ArgsAreNotInstantiationOf =
|
||||
ArgIsInstantiationOf<CallAndPos, ArgsAreNotInstantiationOfInput>;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argsAreNotInstantiationsOf0(
|
||||
Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i
|
||||
) {
|
||||
ArgIsInstantiationOfToIndex::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _)
|
||||
ArgsAreNotInstantiationOf::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if _some_ argument of `call` has a type that is not an instantiation of the
|
||||
* type of the corresponding parameter of `f` inside `i`.
|
||||
*
|
||||
* TODO: Check type parameter constraints as well.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate argsAreNotInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) {
|
||||
exists(FunctionPosition pos |
|
||||
argsAreNotInstantiationsOf0(call, pos, i) and
|
||||
call.hasTargetCand(i, f) and
|
||||
Input::toCheck(i, f, pos, _)
|
||||
Input::toCheck(i, f, _, pos)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,7 @@ private import codeql.rust.elements.internal.generated.Raw
|
||||
private import codeql.rust.elements.internal.generated.Synth
|
||||
private import codeql.rust.frameworks.stdlib.Stdlib
|
||||
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
|
||||
|
||||
/** Gets a type alias of `trait` or of a supertrait of `trait`. */
|
||||
private TypeAlias getTraitTypeAlias(Trait trait) {
|
||||
result = trait.getSupertrait*().getAssocItemList().getAnAssocItem()
|
||||
}
|
||||
private import AssociatedType
|
||||
|
||||
/**
|
||||
* Holds if a dyn trait type for the trait `trait` should have a type parameter
|
||||
@@ -31,7 +27,7 @@ private TypeAlias getTraitTypeAlias(Trait trait) {
|
||||
*/
|
||||
private predicate dynTraitTypeParameter(Trait trait, AstNode n) {
|
||||
trait = any(DynTraitTypeRepr dt).getTrait() and
|
||||
n = [trait.getGenericParamList().getATypeParam().(AstNode), getTraitTypeAlias(trait)]
|
||||
n = [trait.getGenericParamList().getATypeParam().(AstNode), getTraitAssocType(trait)]
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -43,8 +39,11 @@ newtype TType =
|
||||
TNeverType() or
|
||||
TUnknownType() or
|
||||
TTypeParamTypeParameter(TypeParam t) or
|
||||
TAssociatedTypeTypeParameter(Trait trait, TypeAlias typeAlias) {
|
||||
getTraitTypeAlias(trait) = typeAlias
|
||||
TAssociatedTypeTypeParameter(Trait trait, AssocType typeAlias) {
|
||||
getTraitAssocType(trait) = typeAlias
|
||||
} or
|
||||
TTypeParamAssociatedTypeTypeParameter(TypeParam tp, AssocType assoc) {
|
||||
tpAssociatedType(tp, assoc, _)
|
||||
} or
|
||||
TDynTraitTypeParameter(Trait trait, AstNode n) { dynTraitTypeParameter(trait, n) } or
|
||||
TImplTraitTypeParameter(ImplTraitTypeRepr implTrait, TypeParam tp) {
|
||||
@@ -464,6 +463,52 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara
|
||||
override Location getLocation() { result = typeAlias.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type parameter corresponding to an associated type accessed on a type
|
||||
* parameter, for example `T::AssociatedType` where `T` is a type parameter.
|
||||
*
|
||||
* These type parameters are created when a function signature accesses an
|
||||
* associated type on a type parameter. For example, in
|
||||
* ```rust
|
||||
* fn foo<T: SomeTrait>(arg: T::Assoc) { }
|
||||
* ```
|
||||
* we create a `TypeParamAssociatedTypeTypeParameter` for `Assoc` on `T` and the
|
||||
* mention `T::Assoc` resolves to this type parameter. If denoting the type
|
||||
* parameter by `T_Assoc` then the above function is treated as if it was
|
||||
* ```rust
|
||||
* fn foo<T: SomeTrait<Assoc = T_Assoc>, T_Assoc>(arg: T_Assoc) { }
|
||||
* ```
|
||||
*/
|
||||
class TypeParamAssociatedTypeTypeParameter extends TypeParameter,
|
||||
TTypeParamAssociatedTypeTypeParameter
|
||||
{
|
||||
private TypeParam typeParam;
|
||||
private AssocType assoc;
|
||||
|
||||
TypeParamAssociatedTypeTypeParameter() {
|
||||
this = TTypeParamAssociatedTypeTypeParameter(typeParam, assoc)
|
||||
}
|
||||
|
||||
/** Gets the type parameter that this associated type is accessed on. */
|
||||
TypeParam getTypeParam() { result = typeParam }
|
||||
|
||||
/** Gets the associated type alias. */
|
||||
AssocType getTypeAlias() { result = assoc }
|
||||
|
||||
/** Gets a path that accesses this type parameter. */
|
||||
Path getAPath() { tpAssociatedType(typeParam, assoc, result) }
|
||||
|
||||
override ItemNode getDeclaringItem() { result.getTypeParam(_) = typeParam }
|
||||
|
||||
override string toString() {
|
||||
result =
|
||||
typeParam.toString() + "::" + assoc.getName().getText() + "[" +
|
||||
assoc.getTrait().getName().getText() + "]"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = typeParam.getLocation() }
|
||||
}
|
||||
|
||||
/** Gets the associated type type-parameter corresponding directly to `typeAlias`. */
|
||||
AssociatedTypeTypeParameter getAssociatedTypeTypeParameter(TypeAlias typeAlias) {
|
||||
result.isDirect() and result.getTypeAlias() = typeAlias
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ private import codeql.rust.frameworks.stdlib.Stdlib
|
||||
private import Type
|
||||
private import TypeAbstraction
|
||||
private import TypeInference
|
||||
private import AssociatedType
|
||||
|
||||
bindingset[trait, name]
|
||||
pragma[inline_late]
|
||||
@@ -206,12 +207,11 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
|
||||
exists(TypeParamItemNode tp | this = tp.getABoundPath() and result = tp)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Type getDefaultPositionalTypeArgument(int i, TypePath path) {
|
||||
// If a type argument is not given in the path, then we use the default for
|
||||
// the type parameter if one exists for the type.
|
||||
not exists(getPathTypeArgument(this, i)) and
|
||||
// Defaults only apply to type mentions in type annotations
|
||||
this = any(PathTypeRepr ptp).getPath().getQualifier*() and
|
||||
exists(Type ty, TypePath prefix |
|
||||
ty = this.resolveRootType().getTypeParameterDefault(i).(TypeMention).getTypeAt(prefix) and
|
||||
if not ty = TSelfTypeParameter(resolved)
|
||||
@@ -226,10 +226,37 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isInTypeAnnotation() {
|
||||
this = any(PathTypeRepr ptp).getPath().getQualifier*()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TypeParameter getPositionalTypeParameter(int i) {
|
||||
result = this.resolveRootType().getPositionalTypeParameter(i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default type for the type parameter `tp` at `path`, if any.
|
||||
*
|
||||
* This predicate is restricted to mentions that are _not_ part of a type
|
||||
* annotation, such as a qualifier in a call, `Vec::new()`, where the
|
||||
* default type for type parameter `A` of `Vec` is `Global`.
|
||||
*
|
||||
* In these cases, whether or not the default type actually applies may
|
||||
* depend on the types of arguments.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Type getDefaultTypeForTypeParameterInNonAnnotationAt(TypeParameter tp, TypePath path) {
|
||||
not this.isInTypeAnnotation() and
|
||||
exists(int i |
|
||||
result = this.getDefaultPositionalTypeArgument(i, path) and
|
||||
tp = this.getPositionalTypeParameter(i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Type getPositionalTypeArgument(int i, TypePath path) {
|
||||
result = getPathTypeArgument(this, i).getTypeAt(path)
|
||||
or
|
||||
result = this.getDefaultPositionalTypeArgument(i, path)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,9 +264,12 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
|
||||
* type parameter does not correspond directly to a type mention.
|
||||
*/
|
||||
private Type getTypeForTypeParameterAt(TypeParameter tp, TypePath path) {
|
||||
exists(int i |
|
||||
result = this.getPositionalTypeArgument(pragma[only_bind_into](i), path) and
|
||||
tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i))
|
||||
exists(int i | tp = this.getPositionalTypeParameter(i) |
|
||||
result = this.getPositionalTypeArgument(i, path)
|
||||
or
|
||||
// Defaults only apply to type mentions in type annotations
|
||||
this.isInTypeAnnotation() and
|
||||
result = this.getDefaultPositionalTypeArgument(i, path)
|
||||
)
|
||||
or
|
||||
// Handle the special syntactic sugar for function traits. The syntactic
|
||||
@@ -290,6 +320,22 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
|
||||
tp = TAssociatedTypeTypeParameter(resolved, alias) and
|
||||
path.isEmpty()
|
||||
)
|
||||
or
|
||||
// If this path is a type parameter bound, then any associated types
|
||||
// accessed on the type parameter, which originate from this bound, should
|
||||
// be instantiated into the bound, as explained in the comment for
|
||||
// `TypeParamAssociatedTypeTypeParameter`.
|
||||
// ```rust
|
||||
// fn foo<T: SomeTrait<Assoc = T_Assoc>, T_Assoc>(arg: T_Assoc) { }
|
||||
// ^^^^^^^^^ ^^^^^ ^^^^^^^
|
||||
// this path result
|
||||
// ```
|
||||
exists(TypeParam typeParam, Trait trait, AssocType assoc |
|
||||
tpBoundAssociatedType(typeParam, _, this, trait, assoc) and
|
||||
tp = TAssociatedTypeTypeParameter(resolved, assoc) and
|
||||
result = TTypeParamAssociatedTypeTypeParameter(typeParam, assoc) and
|
||||
path.isEmpty()
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[name]
|
||||
@@ -299,7 +345,7 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
|
||||
|
||||
/** Gets the type mention in this path for the type parameter `tp`, if any. */
|
||||
pragma[nomagic]
|
||||
private TypeMention getTypeMentionImplForTypeParameter(TypeParameter tp) {
|
||||
private TypeMention getTypeMentionForAssociatedTypeTypeParameter(AssociatedTypeTypeParameter tp) {
|
||||
exists(TypeAlias alias, string name |
|
||||
result = this.getAssocTypeArg(name) and
|
||||
tp = TAssociatedTypeTypeParameter(resolved, alias) and
|
||||
@@ -343,6 +389,8 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
|
||||
or
|
||||
// Handles paths of the form `Self::AssocType` within a trait block
|
||||
result = TAssociatedTypeTypeParameter(resolvePath(this.getQualifier()), resolved)
|
||||
or
|
||||
result.(TypeParamAssociatedTypeTypeParameter).getAPath() = this
|
||||
}
|
||||
|
||||
override Type resolvePathTypeAt(TypePath typePath) {
|
||||
@@ -352,7 +400,7 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
|
||||
exists(TypeParameter tp, TypePath suffix | typePath = TypePath::cons(tp, suffix) |
|
||||
result = this.getTypeForTypeParameterAt(tp, suffix)
|
||||
or
|
||||
result = this.getTypeMentionImplForTypeParameter(tp).getTypeAt(suffix)
|
||||
result = this.getTypeMentionForAssociatedTypeTypeParameter(tp).getTypeAt(suffix)
|
||||
)
|
||||
or
|
||||
// When the path refers to a trait, then the implicit `Self` type parameter
|
||||
@@ -661,11 +709,10 @@ private predicate pathConcreteTypeAssocType(
|
||||
|
|
||||
// path of the form `<Type as Trait>::AssocType`
|
||||
// ^^^ tm ^^^^^^^^^ name
|
||||
exists(string name |
|
||||
name = path.getText() and
|
||||
trait = resolvePath(qualifier.getSegment().getTraitTypeRepr().getPath()) and
|
||||
getTraitAssocType(trait, name) = alias and
|
||||
tm = qualifier.getSegment().getTypeRepr()
|
||||
exists(string name, Path traitPath |
|
||||
pathTypeAsTraitAssoc(path, tm, traitPath, name) and
|
||||
trait = resolvePath(traitPath) and
|
||||
getTraitAssocType(trait, name) = alias
|
||||
)
|
||||
or
|
||||
// path of the form `Self::AssocType` within an `impl` block
|
||||
|
||||
Reference in New Issue
Block a user