Skip to content

Commit 1bd839c

Browse files
committed
Scope: Improve performance of hidesStrict
Improves performance by: - Capturing for each scope the list of names defined by nested scopes - Use that to determine hidden identifiers for a scope. - Separately determine the hiding identifiers for a scope. This addresses performance issues in the now deleted predicate getOuterScopesOfVariable_candidate().
1 parent 63a60b1 commit 1bd839c

File tree

1 file changed

+82
-37
lines changed

1 file changed

+82
-37
lines changed

cpp/common/src/codingstandards/cpp/Scope.qll

Lines changed: 82 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)