Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- `RULE-5-10-1` - `PoorlyFormedIdentifier.ql`:
- Fixed false positives where a local variable or function parameter was reported as
"defined in reserved namespace" merely because its enclosing function is the body of
an explicit template specialization that C++ permits users to add to namespace `std`
(for example, `std::hash<UserType>::operator()`'s parameter and local names).
15 changes: 14 additions & 1 deletion cpp/common/src/codingstandards/cpp/Identifiers.qll
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,20 @@ private module IdentifierIntroductionImpl {

override string getAnIdent() { result = this.getName() }

override Namespace getNamespace() { result = variable.getNamespace() }
override Namespace getNamespace() {
// A parameter or local variable is scoped to the body of its enclosing function, not to
// that function's enclosing namespace. It does not itself become a new member of the
// namespace, so it cannot "pollute" a reserved namespace such as `std`, regardless of which
// namespace its enclosing function happens to be declared in. This matters in particular
// for the bodies of explicit template specializations that C++ explicitly permits users to
// add to namespace `std` (such as `std::hash<UserType>`), where parameter and local names
// are otherwise ordinary user-chosen identifiers that merely happen to be lexically nested
// inside `namespace std { ... }`. The function or class that actually introduces the
// specialization's name is still checked against `isReservedNamespace` independently, via
// `FunctionDeclarationEntryIdentifier` / `TypeDeclarationEntryIdentifier`.
not variable instanceof LocalScopeVariable and
result = variable.getNamespace()
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@
| test.cpp:186:7:186:12 | wint_t | Identifier 'wint_t' is a reserved name. |
| test.cpp:203:1:203:42 | __PRETTY_FUNCTION__ | Identifier '__PRETTY_FUNCTION__' contains double underscores. |
| test.cpp:203:1:203:42 | __PRETTY_FUNCTION__ | Identifier '__PRETTY_FUNCTION__' starts with underscore. |
| test.cpp:263:6:263:21 | new_std_function | Identifier 'new_std_function' is defined in reserved namespace. |
41 changes: 40 additions & 1 deletion cpp/misra/test/rules/RULE-5-10-1/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,43 @@ struct hash<int> { // COMPLIANT - rule does not apply to template
std::size_t operator()(const int &x) const {
return static_cast<std::size_t>(x);
}
};
};

// Test case for RULE-5-10-1 false positive fix: a local variable or function
// parameter is scoped to the body of its enclosing function, not to the
// namespace that function happens to be declared in. This matters for the
// body of an explicit template specialization that C++ explicitly permits
// users to add to namespace `std` (such as `std::hash<UserType>`): the
// parameter and local names below are ordinary user-chosen identifiers and
// do not themselves become new members of namespace `std`.
struct UserTypeForHash {
int payload;
};

namespace std {
template <typename T>
struct hash; // forward declaration of the primary
// template that is specialized below

template <> struct hash<UserTypeForHash> {
std::size_t
operator()(const UserTypeForHash &value) const noexcept { // COMPLIANT -
// 'value' is a
// parameter
// scoped to the
// function body,
// not a member
// of namespace
// std
std::size_t result = static_cast<std::size_t>(
value.payload); // COMPLIANT - 'result' is a local variable scoped to
// the function body, not a member of namespace std
return result;
}
};

// A genuinely new function declared directly in namespace std remains a
// violation: this is not a permitted specialization, and it does introduce a
// new name into the reserved namespace.
void new_std_function() {} // NON_COMPLIANT - namespace std is reserved
} // namespace std
Loading