@@ -11,7 +11,118 @@ private import codeql.rust.elements.internal.generated.Element
1111 * be referenced directly.
1212 */
1313module Impl {
14+ private import rust
15+ private import codeql.rust.elements.internal.generated.ParentChild
16+ private import codeql.rust.elements.internal.generated.Synth
17+ private import codeql.rust.elements.internal.generated.Raw
18+ private import codeql.rust.elements.internal.LocationImpl
19+
20+ /**
21+ * Provides logic for classifying elements with respect to macro expansions.
22+ */
23+ cached
24+ module MacroExpansion {
25+ /**
26+ * Holds if `e` is superseded by an attribute macro expansion. That is, `e` is
27+ * a transitive child of an item with an attribute macro expansion.
28+ *
29+ * Since this predicate is referenced in the charpred of `Element`, we need to
30+ * use the parent-child relation on raw elements to avoid non-monotonicity.
31+ */
32+ private predicate supersededByAttributeMacroExpansionRaw ( Raw:: Item item , Raw:: Element e ) {
33+ exists ( item .getAttributeMacroExpansion ( ) ) and
34+ e = Raw:: getImmediateChild ( item , _) and
35+ not e = item .getAttributeMacroExpansion ( ) and
36+ // Don't consider attributes themselves to be superseded. E.g., in `#[a] fn
37+ // f() {}` the macro expansion supersedes `fn f() {}` but not `#[a]`.
38+ not e instanceof Raw:: Attr
39+ or
40+ exists ( Raw:: Element parent |
41+ e = Raw:: getImmediateChild ( parent , _) and
42+ supersededByAttributeMacroExpansionRaw ( item , parent )
43+ )
44+ }
45+
46+ private predicate isMacroExpansion ( AstNode macro , AstNode expansion ) {
47+ expansion = macro .( MacroCall ) .getMacroCallExpansion ( )
48+ or
49+ expansion = macro .( Adt ) .getDeriveMacroExpansion ( _)
50+ or
51+ expansion = macro .( Item ) .getAttributeMacroExpansion ( )
52+ }
53+
54+ /**
55+ * Gets the immediately enclosing macro invocation for element `e`, if any.
56+ *
57+ * The result is either a `MacroCall`, and `Adt` with a derive macro expansion, or
58+ * an `Item` with an attribute macro expansion.
59+ */
60+ cached
61+ AstNode getImmediatelyEnclosingMacroInvocation ( Element e ) {
62+ isMacroExpansion ( result , e )
63+ or
64+ exists ( Element mid |
65+ result = getImmediatelyEnclosingMacroInvocation ( mid ) and
66+ mid = getImmediateParent ( e ) and
67+ not isMacroExpansion ( mid , e )
68+ )
69+ }
70+
71+ pragma [ nomagic]
72+ private predicate isAttributeMacroExpansionSourceLocation ( Item i , Location l ) {
73+ exists ( Raw:: Locatable e , @location_default loc |
74+ supersededByAttributeMacroExpansionRaw ( Synth:: convertElementToRaw ( i ) , e ) and
75+ locatable_locations ( e , loc ) and
76+ l = LocationImpl:: TLocationDefault ( loc )
77+ )
78+ }
79+
80+ /** Gets an AST node whose location is inside the token tree belonging to `mc`. */
81+ pragma [ nomagic]
82+ private AstNode getATokenTreeNode ( MacroCall mc ) {
83+ mc = getImmediatelyEnclosingMacroInvocation ( result ) and
84+ mc .getTokenTree ( ) .getLocation ( ) .contains ( result .getLocation ( ) )
85+ }
86+
87+ /** Holds if `n` is inside a macro expansion. */
88+ cached
89+ predicate isInMacroExpansion ( AstNode n ) { exists ( getImmediatelyEnclosingMacroInvocation ( n ) ) }
90+
91+ /**
92+ * Holds if `n` exists only as the result of a macro expansion.
93+ *
94+ * This is the same as `isInMacroExpansion(n)`, but excludes AST nodes corresponding
95+ * to macro arguments, including attribute macro targets.
96+ *
97+ * Note: This predicate is a heuristic based on location information and may not be
98+ * accurate in all cases.
99+ */
100+ cached
101+ predicate isFromMacroExpansion ( AstNode n ) {
102+ exists ( AstNode macro |
103+ macro = getImmediatelyEnclosingMacroInvocation ( n ) and
104+ not n = getATokenTreeNode ( macro ) and
105+ not isAttributeMacroExpansionSourceLocation ( macro , n .getLocation ( ) )
106+ )
107+ or
108+ isFromMacroExpansion ( getImmediatelyEnclosingMacroInvocation ( n ) )
109+ }
110+
111+ cached
112+ predicate isRelevantElement ( Generated:: Element e ) {
113+ exists ( Raw:: Element raw |
114+ raw = Synth:: convertElementToRaw ( e ) and
115+ not supersededByAttributeMacroExpansionRaw ( _, raw )
116+ )
117+ or
118+ // Synthetic elements are relevant when their parents are
119+ Synth:: convertFormatArgsExprToRaw ( _) = Synth:: getSynthParent ( e )
120+ }
121+ }
122+
14123 class Element extends Generated:: Element {
124+ Element ( ) { MacroExpansion:: isRelevantElement ( this ) }
125+
15126 override string toStringImpl ( ) { result = this .getAPrimaryQlClass ( ) }
16127
17128 /**
0 commit comments