@@ -122,39 +122,77 @@ class Scope extends Element {
122
122
or
123
123
not exists ( Internal:: getParentScope ( this ) ) and result = 0
124
124
}
125
- }
126
125
127
- class GeneratedBlockStmt extends BlockStmt {
128
- GeneratedBlockStmt ( ) { this .getLocation ( ) instanceof UnknownLocation }
129
- }
126
+ /**
127
+ * Holds if `name` is declared in this scope, or in a nested scope.
128
+ */
129
+ private predicate isNameDeclaredInThisOrNestedScope ( string name ) {
130
+ name = getAVariable ( ) .getName ( )
131
+ or
132
+ isNameDeclaredInNestedScope ( name )
133
+ }
134
+
135
+ /**
136
+ * Holds if `name` is declared in a nested scope.
137
+ */
138
+ private predicate isNameDeclaredInNestedScope ( string name ) {
139
+ exists ( Scope child |
140
+ child .getStrictParent ( ) = this and
141
+ child .isNameDeclaredInThisOrNestedScope ( name )
142
+ )
143
+ }
144
+
145
+ /**
146
+ * Holds if `name` is declared in this scope and is hidden in a child scope.
147
+ */
148
+ private predicate isDeclaredNameHiddenByChild ( string name ) {
149
+ isNameDeclaredInNestedScope ( name ) and
150
+ name = getAVariable ( ) .getName ( )
151
+ }
152
+
153
+ /**
154
+ * Gets a variable with `name` which is hidden in at least one nested scope.
155
+ */
156
+ UserVariable getAHiddenVariable ( string name ) {
157
+ result = getAVariable ( ) and
158
+ result .getName ( ) = name and
159
+ isDeclaredNameHiddenByChild ( name )
160
+ }
130
161
131
- /** Gets a variable that is in the potential scope of variable `v`. */
132
- private UserVariable getPotentialScopeOfVariable_candidate ( UserVariable v ) {
133
- exists ( Scope s |
134
- result = s . getAVariable ( ) and
162
+ /**
163
+ * Holds if `name` is declared above this scope and hidden by this or a nested scope.
164
+ */
165
+ private predicate isNameDeclaredAboveHiddenByThisOrNested ( string name ) {
135
166
(
136
- // Variable in an ancestor scope, but only if there are less than 100 variables in this scope
137
- v = s .getAnAncestor ( ) .getAVariable ( ) and
138
- s .getNumberOfVariables ( ) < 100
167
+ this .getStrictParent ( ) .isDeclaredNameHiddenByChild ( name ) or
168
+ this .getStrictParent ( ) .isNameDeclaredAboveHiddenByThisOrNested ( name )
169
+ ) and
170
+ isNameDeclaredInThisOrNestedScope ( name )
171
+ }
172
+
173
+ /**
174
+ * Gets a variable with `name` which is declared above and hidden by a variable in this or a nested scope.
175
+ */
176
+ UserVariable getAHidingVariable ( string name ) {
177
+ isNameDeclaredAboveHiddenByThisOrNested ( name ) and
178
+ (
179
+ // Declared in this scope
180
+ getAVariable ( ) .getName ( ) = name and
181
+ result = getAVariable ( ) and
182
+ result .getName ( ) = name
139
183
or
140
- // In the same scope, but not the same variable, and choose just one to report
141
- v = s .getAVariable ( ) and
142
- not result = v and
143
- v .getName ( ) <= result .getName ( )
184
+ // Declared in a child scope
185
+ exists ( Scope child |
186
+ child .getStrictParent ( ) = this and
187
+ child .isNameDeclaredInThisOrNestedScope ( name ) and
188
+ result = child .getAHidingVariable ( name )
189
+ )
144
190
)
145
- )
191
+ }
146
192
}
147
193
148
- /** Gets a variable that is in the potential scope of variable `v`. */
149
- private UserVariable getOuterScopesOfVariable_candidate ( UserVariable v ) {
150
- exists ( Scope s |
151
- result = s .getAVariable ( ) and
152
- (
153
- // Variable in an ancestor scope, but only if there are less than 100 variables in this scope
154
- v = s .getAnAncestor ( ) .getAVariable ( ) and
155
- s .getNumberOfVariables ( ) < 100
156
- )
157
- )
194
+ class GeneratedBlockStmt extends BlockStmt {
195
+ GeneratedBlockStmt ( ) { this .getLocation ( ) instanceof UnknownLocation }
158
196
}
159
197
160
198
/** Holds if there exists a translation unit that includes both `f1` and `f2`. */
@@ -167,12 +205,17 @@ predicate inSameTranslationUnit(File f1, File f2) {
167
205
}
168
206
169
207
/**
170
- * Gets a user variable which occurs in the "outer scope" of variable `v`.
208
+ * Holds if there exists a translation unit that includes both `f1` and `f2`.
209
+ *
210
+ * This version is late bound.
171
211
*/
172
- cached
173
- UserVariable getPotentialScopeOfVariableStrict ( UserVariable v ) {
174
- result = getOuterScopesOfVariable_candidate ( v ) and
175
- inSameTranslationUnit ( v .getFile ( ) , result .getFile ( ) )
212
+ bindingset [ f1, f2]
213
+ pragma [ inline_late]
214
+ predicate inSameTranslationUnitLate ( File f1 , File f2 ) {
215
+ exists ( TranslationUnit c |
216
+ c .getAUserFile ( ) = f1 and
217
+ c .getAUserFile ( ) = f2
218
+ )
176
219
}
177
220
178
221
/** A file that is a C/C++ source file */
@@ -200,12 +243,14 @@ class TranslationUnit extends SourceFile {
200
243
}
201
244
}
202
245
203
- /** Holds if `v2` may hide `v1`. */
204
- private predicate hides_candidateStrict ( UserVariable v1 , UserVariable v2 ) {
205
- not v1 = v2 and
206
- v2 = getPotentialScopeOfVariableStrict ( v1 ) and
207
- v1 .getName ( ) = v2 .getName ( ) and
208
- // Member variables cannot hide other variables nor be hidden because the can be referenced through their qualified name.
246
+ /** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */
247
+ predicate hides_candidateStrict ( UserVariable v1 , UserVariable v2 ) {
248
+ exists ( Scope s , string name |
249
+ v1 = s .getStrictParent ( ) .getAHiddenVariable ( name ) and
250
+ v2 = s .getAHidingVariable ( name ) and
251
+ not v1 = v2
252
+ ) and
253
+ inSameTranslationUnitLate ( v1 .getFile ( ) , v2 .getFile ( ) ) and
209
254
not ( v1 .isMember ( ) or v2 .isMember ( ) ) and
210
255
(
211
256
// If v1 is a local variable, ensure that v1 is declared before v2
0 commit comments