
The languages for this rule fall into two categories: * CFamily, JS, and PLSQL: "Variables should not be shadowed" (general case of shadowing) * C#, Flex, Java, PHP, Swift: "Local variables should not shadow field/property/enum case/..." (narrow case of shadowing) For CFamily, these tickets are also handled: CPP-2785 CPP-3589
146 lines
3.8 KiB
Plaintext
146 lines
3.8 KiB
Plaintext
include::../why-general.adoc[]
|
|
|
|
|
|
The examples below show typical situations in which shadowing can occur.
|
|
|
|
* Parameter shadowing
|
|
+
|
|
[source,cpp]
|
|
----
|
|
void f(int x, bool b) {
|
|
int y = 4;
|
|
if (b) {
|
|
int x = 7; // Noncompliant: the parameter "x" is shadowed.
|
|
int y = 9; // Noncompliant: the local variable "y" is shadowed.
|
|
// ...
|
|
}
|
|
}
|
|
----
|
|
|
|
* Member variable shadowing
|
|
+
|
|
[source,cpp]
|
|
----
|
|
class Foo {
|
|
private:
|
|
int myField;
|
|
|
|
public:
|
|
void doSomething() {
|
|
int myField = 0; // Noncompliant: Foo::myField is shadowed.
|
|
// ...
|
|
}
|
|
};
|
|
----
|
|
|
|
* Global variable shadowing
|
|
+
|
|
[source,cpp]
|
|
----
|
|
namespace ns {
|
|
int state;
|
|
|
|
void bar() {
|
|
int state = 0; // Noncompliant: the namespace variable is shadowed.
|
|
}
|
|
}
|
|
----
|
|
|
|
=== Exceptions
|
|
|
|
It is common practice to have constructor arguments shadowing the fields they initialize in the _member initializer list_.
|
|
This pattern avoids the need to select new names for the constructor arguments and will not be reported by this rule.
|
|
|
|
[source,cpp]
|
|
----
|
|
class Point {
|
|
public:
|
|
Point(int x, int y)
|
|
: x(x) // Compliant by exception: the parameter "x" is used
|
|
// in the member initializer list.
|
|
{
|
|
y = y; // Noncompliant: the parameter is assigned to itself
|
|
// and the member "y" is not initialized.
|
|
}
|
|
|
|
private:
|
|
int x;
|
|
int y;
|
|
};
|
|
----
|
|
|
|
=== Caveats
|
|
|
|
==== Shadowing in `if`, `else if`, and `else`
|
|
|
|
Variables can be introduced in the condition of an `if` statement.
|
|
Their scope includes the optional `else` statement, which may be surprising.
|
|
Consequently, such variables can be shadowed in an `else if` statement.
|
|
This can be even more confusing and result in unintended behavior, as illustrated in this example:
|
|
|
|
[source,cpp]
|
|
----
|
|
using ExpectedData = std::expected<std::string, std::error_code>;
|
|
|
|
if (ExpectedData e = readData()) {
|
|
printMessage(e.value());
|
|
} else if (ExpectedData e = readFallbackSource()) { // Noncompliant
|
|
printMessage(e.value());
|
|
} else {
|
|
logError(
|
|
"Initial source failed with: ",
|
|
e.error() // Contrary to the intention, the second "e" is used.
|
|
);
|
|
}
|
|
----
|
|
|
|
==== Shadowing of inaccessible declarations
|
|
|
|
This rule also raises issues on some variables, although they do not shadow another variable according to a strict interpretation of the {cpp} language. There are mainly two reasons for this.
|
|
|
|
. Primarily, the readability and maintainability of the code are impaired.
|
|
Readers need an advanced understanding of the {cpp} language to understand the subtle differences.
|
|
|
|
. Secondly, a small change can lead to actual shadowing.
|
|
This can lead to subtle bugs when updating the code.
|
|
|
|
Here is an example with nested classes:
|
|
|
|
[source,cpp]
|
|
----
|
|
class A {
|
|
public:
|
|
int x;
|
|
class B;
|
|
};
|
|
|
|
class A::B {
|
|
void f(int x) { // Noncompliant: The parameter "x" shadows the field "A::x".
|
|
// ...
|
|
}
|
|
};
|
|
----
|
|
|
|
In the above example, `A::x` cannot be used from `A::B` member functions because it is not a `static` field.
|
|
This can lead to surprising effects when moving code around, particularly if the declaration of `A::x` was changed from `int x;` to `static int x;`.
|
|
|
|
You should always avoid shadowing to avoid any confusion and increase the maintainability of your code.
|
|
|
|
== Resources
|
|
|
|
=== External coding guidelines
|
|
|
|
* MISRA C:2004, 5.2 - Identifiers in an inner scope shall not use the same name as an identifier in an outer scope, and therefore hide that identifier
|
|
* MISRA {cpp}:2008, 2-10-2 - Identifiers declared in an inner scope shall not hide an identifier declared in an outer scope
|
|
* MISRA C:2012, 5.3 - An identifier declared in an inner scope shall not hide an identifier declared in an outer scope
|
|
|
|
=== Standards
|
|
|
|
* CERT - https://wiki.sei.cmu.edu/confluence/display/c/DCL01-C.+Do+not+reuse+variable+names+in+subscopes[DCL01-C. Do not reuse variable names in subscopes]
|
|
|
|
=== Related rules
|
|
|
|
* S2387 - Child class fields should not shadow parent class fields
|
|
|
|
include::../rspecator.adoc[]
|