Skip to content

Commit 833aeb2

Browse files
authored
Merge pull request #423 from github/lcartey/a2-10-1-point-of-decl
Identifier hiding: consider point of declaration
2 parents b586e45 + 70e705d commit 833aeb2

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `A2-10-1`, `RULE-5-3`:
2+
- Reduce false positives by considering point of declaration for local variables.
3+
- Reduce false negatives by considering catch block parameters to be in scope in the catch block.

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

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,16 @@ private Element getParentScope(Element e) {
4242
then result = e.getParentScope()
4343
else (
4444
// Statements do no have a parent scope, so return the enclosing block.
45-
result = e.(Stmt).getEnclosingBlock() or result = e.(Expr).getEnclosingBlock()
45+
result = e.(Stmt).getEnclosingBlock()
46+
or
47+
result = e.(Expr).getEnclosingBlock()
48+
or
49+
// Catch block parameters don't have an enclosing scope, so attach them to the
50+
// the block itself
51+
exists(CatchBlock cb |
52+
e = cb.getParameter() and
53+
result = cb
54+
)
4655
)
4756
}
4857

@@ -209,7 +218,42 @@ private predicate hides_candidateStrict(UserVariable v1, UserVariable v2) {
209218
v2 = getPotentialScopeOfVariableStrict(v1) and
210219
v1.getName() = v2.getName() and
211220
// Member variables cannot hide other variables nor be hidden because the can be referenced through their qualified name.
212-
not (v1.isMember() or v2.isMember())
221+
not (v1.isMember() or v2.isMember()) and
222+
(
223+
// If v1 is a local variable, ensure that v1 is declared before v2
224+
(
225+
v1 instanceof LocalVariable and
226+
// Ignore variables declared in conditional expressions, as they apply to
227+
// the nested scope
228+
not v1 = any(ConditionDeclExpr cde).getVariable() and
229+
// Ignore variables declared in loops
230+
not exists(Loop l | l.getADeclaration() = v1)
231+
)
232+
implies
233+
exists(BlockStmt bs, DeclStmt v1Stmt, Stmt v2Stmt |
234+
v1 = v1Stmt.getADeclaration() and
235+
getEnclosingStmt(v2).getParentStmt*() = v2Stmt
236+
|
237+
bs.getIndexOfStmt(v1Stmt) <= bs.getIndexOfStmt(v2Stmt)
238+
)
239+
)
240+
}
241+
242+
/**
243+
* Gets the enclosing statement of the given variable, if any.
244+
*/
245+
private Stmt getEnclosingStmt(LocalScopeVariable v) {
246+
result.(DeclStmt).getADeclaration() = v
247+
or
248+
exists(ConditionDeclExpr cde |
249+
cde.getVariable() = v and
250+
result = cde.getEnclosingStmt()
251+
)
252+
or
253+
exists(CatchBlock cb |
254+
cb.getParameter() = v and
255+
result = cb.getEnclosingStmt()
256+
)
213257
}
214258

215259
/** Holds if `v2` hides `v1`. */

cpp/common/test/rules/identifierhidden/IdentifierHidden.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
| test.cpp:23:13:23:15 | id1 | Variable is hiding variable $@. | test.cpp:1:5:1:7 | id1 | id1 |
66
| test.cpp:26:12:26:14 | id1 | Variable is hiding variable $@. | test.cpp:1:5:1:7 | id1 | id1 |
77
| test.cpp:27:14:27:16 | id1 | Variable is hiding variable $@. | test.cpp:26:12:26:14 | id1 | id1 |
8+
| test.cpp:65:11:65:11 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i |
9+
| test.cpp:67:9:67:9 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i |
10+
| test.cpp:70:12:70:12 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i |
11+
| test.cpp:75:16:75:16 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i |

cpp/common/test/rules/identifierhidden/test.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,38 @@ template <class T> constexpr T foo1 = T(1.1L);
4040
template <class T, class R> T f(T r) {
4141
T v = foo1<T> * r * r; // COMPLIANT
4242
T v1 = foo1<R> * r * r; // COMPLIANT
43+
}
44+
45+
void test_scope_order() {
46+
{
47+
{
48+
int i; // COMPLIANT
49+
}
50+
int i; // COMPLIANT
51+
}
52+
53+
for (int i = 0; i < 10; i++) { // COMPLIANT
54+
}
55+
56+
try {
57+
58+
} catch (int i) { // COMPLIANT
59+
}
60+
61+
int i; // COMPLIANT
62+
63+
{
64+
{
65+
int i; // NON_COMPLIANT
66+
}
67+
int i; // NON_COMPLIANT
68+
}
69+
70+
for (int i = 0; i < 10; i++) { // NON_COMPLIANT
71+
}
72+
73+
try {
74+
75+
} catch (int i) { // NON_COMPLIANT
76+
}
4377
}

0 commit comments

Comments
 (0)