@@ -1221,6 +1221,28 @@ private module MethodCallResolution {
12211221 )
12221222 }
12231223
1224+ /**
1225+ * Holds if method `m` with the name `name` and the arity `arity` exists in
1226+ * `i`, and the type of the `self` parameter is `selfType`.
1227+ *
1228+ * `strippedTypePath` points to the type `strippedType` inside `selfType`,
1229+ * which is the (possibly complex-stripped) root type of `selfType`.
1230+ */
1231+ pragma [ nomagic]
1232+ private predicate methodInfo0 (
1233+ Function m , string name , int arity , ImplOrTraitItemNode i , FunctionType selfType ,
1234+ TypePath strippedTypePath , Type strippedType
1235+ ) {
1236+ exists ( FunctionTypePosition pos |
1237+ m = i .getASuccessor ( name ) and
1238+ arity = m .getParamList ( ) .getNumberOfParams ( ) and
1239+ strippedType = selfType .getTypeAt ( strippedTypePath ) and
1240+ isComplexRootStripped ( strippedTypePath , strippedType ) and
1241+ selfType .appliesTo ( m , pos , i ) and
1242+ pos .isSelf ( )
1243+ )
1244+ }
1245+
12241246 /**
12251247 * Holds if method `m` with the name `name` and the arity `arity` exists in
12261248 * `i`, and the type of the `self` parameter is `selfType`.
@@ -1269,16 +1291,17 @@ private module MethodCallResolution {
12691291 pragma [ nomagic]
12701292 private predicate methodTraitInfo ( string name , int arity , Trait trait ) {
12711293 exists ( ImplItemNode i |
1272- methodInfo ( _, name , arity , i , _, _, _) and
1294+ methodInfo0 ( _, name , arity , i , _, _, _) and
12731295 trait = i .resolveTraitTy ( )
12741296 )
12751297 or
1276- methodInfo ( _, name , arity , trait , _, _, _)
1298+ methodInfo0 ( _, name , arity , trait , _, _, _)
12771299 }
12781300
12791301 pragma [ nomagic]
12801302 private predicate methodCallTraitCandidate ( Element mc , Trait trait ) {
1281- exists ( string name , int arity | mc .( MethodCall ) .hasNameAndArity ( name , arity ) |
1303+ exists ( string name , int arity |
1304+ mc .( MethodCall ) .hasNameAndArity ( name , arity ) and
12821305 methodTraitInfo ( name , arity , trait )
12831306 )
12841307 }
@@ -1473,7 +1496,9 @@ private module MethodCallResolution {
14731496 */
14741497 pragma [ nomagic]
14751498 Function resolveCallTarget ( string derefChainBorrow ) {
1476- result = MkMethodCallCand ( this , derefChainBorrow ) .( MethodCallCand ) .resolveCallTarget ( )
1499+ exists ( MethodCallCand mcc | mcc = MkMethodCallCand ( this , derefChainBorrow ) |
1500+ result = mcc .resolveCallTarget ( )
1501+ )
14771502 }
14781503
14791504 predicate receiverHasImplicitDeref ( AstNode receiver ) {
@@ -1561,7 +1586,7 @@ private module MethodCallResolution {
15611586 * resolve to a method in an `impl` block for the type of the receiver.
15621587 */
15631588 pragma [ nomagic]
1564- private predicate hasNoInherentTarget ( ) {
1589+ predicate hasNoInherentTarget ( ) {
15651590 exists ( TypePath strippedTypePath , Type strippedType , string name , int arity |
15661591 this .hasInfo ( _, strippedTypePath , strippedType , name , arity ) and
15671592 forall ( Impl i |
@@ -1620,6 +1645,8 @@ private module MethodCallResolution {
16201645 result = this .resolveAmbigousCallTargetCand ( pos , path , type ) and
16211646 type = this .inferPositionalArgumentType ( pos , path )
16221647 )
1648+ or
1649+ result = BlanketImplementation:: getMethodFromBlanketImpl ( this )
16231650 }
16241651
16251652 string toString ( ) { result = mc_ .toString ( ) + " [" + derefChainBorrow + "]" }
@@ -1668,6 +1695,135 @@ private module MethodCallResolution {
16681695 methodInfo ( _, _, _, _, constraint , _, _)
16691696 }
16701697 }
1698+
1699+ private module BlanketImplementation {
1700+ private ImplItemNode getPotentialDuplicated (
1701+ string fileName , string traitName , int arity , string tpName
1702+ ) {
1703+ tpName = result .getBlanketImplementationTypeParam ( ) .getName ( ) and
1704+ fileName = result .getLocation ( ) .getFile ( ) .getBaseName ( ) and
1705+ traitName = result .resolveTraitTy ( ) .getName ( ) and
1706+ arity = result .resolveTraitTy ( ) .( Trait ) .getNumberOfGenericParams ( )
1707+ }
1708+
1709+ private predicate duplicatedImpl ( Impl impl1 , Impl impl2 ) {
1710+ exists ( string fileName , string traitName , int arity , string tpName |
1711+ impl1 = getPotentialDuplicated ( fileName , traitName , arity , tpName ) and
1712+ impl2 = getPotentialDuplicated ( fileName , traitName , arity , tpName ) and
1713+ impl1 .getLocation ( ) .getFile ( ) .getAbsolutePath ( ) <
1714+ impl2 .getLocation ( ) .getFile ( ) .getAbsolutePath ( )
1715+ )
1716+ }
1717+
1718+ /**
1719+ * Holds if `impl` is a canonical blanket implementation.
1720+ *
1721+ * Libraries can often occur several times in the database for different
1722+ * library versions. This causes the same blanket implementations to exist
1723+ * multiple times, and these add no useful information.
1724+ *
1725+ * We detect these duplicates based on some simple heuristics (same trait
1726+ * name, file name, etc.). For these duplicates we select the one with the
1727+ * greatest file name (which usually is also the one with the greatest library
1728+ * version in the path) as the "canonical" implementation.
1729+ */
1730+ private predicate isCanonicalImpl ( Impl impl ) {
1731+ not duplicatedImpl ( impl , _) and impl .( ImplItemNode ) .isBlanketImplementation ( )
1732+ }
1733+
1734+ /**
1735+ * Holds if `impl` is a blanket implementation for a type parameter and
1736+ * `traitBound` is the first non-trivial trait bound of that type parameter.
1737+ */
1738+ private predicate blanketImplementationTraitBound ( ImplItemNode impl , Trait traitBound ) {
1739+ traitBound =
1740+ min ( Trait trait , int i |
1741+ trait = impl .getBlanketImplementationTypeParam ( ) .resolveBound ( i ) and
1742+ // Exclude traits that are known to not narrow things down very much.
1743+ not trait .getName ( ) .getText ( ) =
1744+ [
1745+ "Sized" , "Clone" ,
1746+ // The auto traits
1747+ "Send" , "Sync" , "Unpin" , "UnwindSafe" , "RefUnwindSafe"
1748+ ]
1749+ |
1750+ trait order by i
1751+ )
1752+ }
1753+
1754+ /**
1755+ * Holds if `impl` is a relevant blanket implementation that requires the
1756+ * trait `traitBound` and provides `f`, a method with name `name` and arity
1757+ * `arity`.
1758+ */
1759+ private predicate blanketImplementationMethod (
1760+ ImplItemNode impl , Trait traitBound , string name , int arity , Function f
1761+ ) {
1762+ isCanonicalImpl ( impl ) and
1763+ blanketImplementationTraitBound ( impl , traitBound ) and
1764+ f .getParamList ( ) .hasSelfParam ( ) and
1765+ arity = f .getParamList ( ) .getNumberOfParams ( ) and
1766+ (
1767+ f = impl .getAssocItem ( name )
1768+ or
1769+ // If the trait has a method with a default implementation, then that
1770+ // target is interesting as well.
1771+ not exists ( impl .getAssocItem ( name ) ) and
1772+ f = impl .resolveTraitTy ( ) .getAssocItem ( name )
1773+ ) and
1774+ // If the method is already available through one of the trait bounds on the
1775+ // type parameter (because they implement the trait targeted by the impl
1776+ // block) then ignore it.
1777+ not impl .getBlanketImplementationTypeParam ( )
1778+ .resolveABound ( )
1779+ .( TraitItemNode )
1780+ .getASuccessor ( name ) = f
1781+ }
1782+
1783+ pragma [ nomagic]
1784+ predicate methodCallMatchesBlanketImpl (
1785+ MethodCallCand mcc , MethodCall mc , Type t , ImplItemNode impl , Trait traitBound ,
1786+ Trait traitImpl , Function f
1787+ ) {
1788+ // Only check method calls where we have ruled out inherent method targets.
1789+ // Ideally we would also check if non-blanket method targets have been ruled
1790+ // out.
1791+ mcc .hasNoInherentTarget ( ) and
1792+ exists ( string name , int arity |
1793+ mcc .hasInfo ( mc , _, _, name , arity ) and
1794+ // isMethodCall(mc, t, name, arity) and
1795+ t = mcc .getTypeAt ( TypePath:: nil ( ) ) and
1796+ blanketImplementationMethod ( impl , traitBound , name , arity , f )
1797+ ) and
1798+ traitImpl = impl .resolveTraitTy ( )
1799+ }
1800+
1801+ module SatisfiesConstraintInput implements SatisfiesConstraintInputSig< MethodCallCand > {
1802+ pragma [ nomagic]
1803+ predicate relevantConstraint ( MethodCallCand mcc , Type constraint ) {
1804+ exists ( MethodCall mc , Trait traitBound , Trait traitImpl |
1805+ methodCallMatchesBlanketImpl ( mcc , mc , _, _, traitBound , traitImpl , _) and
1806+ methodCallVisibleTraitCandidate ( mc , traitImpl ) and
1807+ traitBound = constraint .( TraitType ) .getTrait ( )
1808+ )
1809+ }
1810+
1811+ predicate useUniversalConditions ( ) { none ( ) }
1812+ }
1813+
1814+ predicate hasBlanketImpl (
1815+ MethodCallCand mcc , MethodCall mc , Type t , Impl impl , Trait traitBound , Function f
1816+ ) {
1817+ SatisfiesConstraint< MethodCallCand , SatisfiesConstraintInput > :: satisfiesConstraintType ( mcc ,
1818+ TTrait ( traitBound ) , _, _) and
1819+ methodCallMatchesBlanketImpl ( mcc , mc , t , impl , traitBound , _, f )
1820+ }
1821+
1822+ pragma [ nomagic]
1823+ Function getMethodFromBlanketImpl ( MethodCallCand mcc ) {
1824+ hasBlanketImpl ( mcc , _, _, _, _, result )
1825+ }
1826+ }
16711827}
16721828
16731829/**
0 commit comments