@@ -122,39 +122,77 @@ class Scope extends Element {
122122 or
123123 not exists ( Internal:: getParentScope ( this ) ) and result = 0
124124 }
125- }
126125
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+ }
130161
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 ) {
135166 (
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
139183 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+ )
144190 )
145- )
191+ }
146192}
147193
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 }
158196}
159197
160198/** Holds if there exists a translation unit that includes both `f1` and `f2`. */
@@ -167,12 +205,17 @@ predicate inSameTranslationUnit(File f1, File f2) {
167205}
168206
169207/**
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.
171211 */
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+ )
176219}
177220
178221/** A file that is a C/C++ source file */
@@ -200,12 +243,14 @@ class TranslationUnit extends SourceFile {
200243 }
201244}
202245
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
209254 not ( v1 .isMember ( ) or v2 .isMember ( ) ) and
210255 (
211256 // If v1 is a local variable, ensure that v1 is declared before v2
0 commit comments