@@ -11,7 +11,115 @@ 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+ private predicate supersededByAttributeMacroExpansionRaw ( Raw:: Item item , Raw:: Element e ) {
30+ exists ( item .getAttributeMacroExpansion ( ) ) and
31+ e = Raw:: getImmediateChild ( item , _) and
32+ not e = item .getAttributeMacroExpansion ( ) and
33+ // Don't consider attributes themselves to be superseded. E.g., in `#[a] fn
34+ // f() {}` the macro expansion supersedes `fn f() {}` but not `#[a]`.
35+ not e instanceof Raw:: Attr
36+ or
37+ exists ( Raw:: Element parent |
38+ e = Raw:: getImmediateChild ( parent , _) and
39+ supersededByAttributeMacroExpansionRaw ( item , parent )
40+ )
41+ }
42+
43+ private predicate isMacroExpansion ( AstNode macro , AstNode expansion ) {
44+ expansion = macro .( MacroCall ) .getMacroCallExpansion ( )
45+ or
46+ expansion = macro .( Adt ) .getDeriveMacroExpansion ( _)
47+ or
48+ expansion = macro .( Item ) .getAttributeMacroExpansion ( )
49+ }
50+
51+ /**
52+ * Gets the immediately enclosing macro invocation for element `e`, if any.
53+ *
54+ * The result is either a `MacroCall`, and `Adt` with a derive macro expansion, or
55+ * an `Item` with an attribute macro expansion.
56+ */
57+ cached
58+ AstNode getImmediatelyEnclosingMacroInvocation ( Element e ) {
59+ isMacroExpansion ( result , e )
60+ or
61+ exists ( Element mid |
62+ result = getImmediatelyEnclosingMacroInvocation ( mid ) and
63+ mid = getImmediateParent ( e ) and
64+ not isMacroExpansion ( mid , e )
65+ )
66+ }
67+
68+ pragma [ nomagic]
69+ private predicate isAttributeMacroExpansionSourceLocation ( Item i , Location l ) {
70+ exists ( Raw:: Locatable e , @location_default loc |
71+ supersededByAttributeMacroExpansionRaw ( Synth:: convertElementToRaw ( i ) , e ) and
72+ locatable_locations ( e , loc ) and
73+ l = LocationImpl:: TLocationDefault ( loc )
74+ )
75+ }
76+
77+ /** Gets an AST node whose location is inside the token tree belonging to `mc`. */
78+ pragma [ nomagic]
79+ private AstNode getATokenTreeNode ( MacroCall mc ) {
80+ mc = getImmediatelyEnclosingMacroInvocation ( result ) and
81+ mc .getTokenTree ( ) .getLocation ( ) .contains ( result .getLocation ( ) )
82+ }
83+
84+ /** Holds if `n` is inside a macro expansion. */
85+ cached
86+ predicate isInMacroExpansion ( AstNode n ) { exists ( getImmediatelyEnclosingMacroInvocation ( n ) ) }
87+
88+ /**
89+ * Holds if `n` exists only as the result of a macro expansion.
90+ *
91+ * This is the same as `isInMacroExpansion(n)`, but excludes AST nodes corresponding
92+ * to macro arguments, including attribute macro targets.
93+ *
94+ * Note: This predicate is a heuristic based on location information and may not be
95+ * accurate in all cases.
96+ */
97+ cached
98+ predicate isFromMacroExpansion ( AstNode n ) {
99+ exists ( AstNode macro |
100+ macro = getImmediatelyEnclosingMacroInvocation ( n ) and
101+ not n = getATokenTreeNode ( macro ) and
102+ not isAttributeMacroExpansionSourceLocation ( macro , n .getLocation ( ) )
103+ )
104+ or
105+ isFromMacroExpansion ( getImmediatelyEnclosingMacroInvocation ( n ) )
106+ }
107+
108+ cached
109+ predicate isRelevantElement ( Generated:: Element e ) {
110+ exists ( Raw:: Element raw |
111+ raw = Synth:: convertElementToRaw ( e ) and
112+ not supersededByAttributeMacroExpansionRaw ( _, raw )
113+ )
114+ or
115+ // Synthetic elements are relevant when their parent is
116+ Synth:: convertFormatArgsExprToRaw ( _) = Synth:: getSynthParent ( e )
117+ }
118+ }
119+
14120 class Element extends Generated:: Element {
121+ Element ( ) { MacroExpansion:: isRelevantElement ( this ) }
122+
15123 override string toStringImpl ( ) { result = this .getAPrimaryQlClass ( ) }
16124
17125 /**
0 commit comments