[clang-tidy] Make performance-inefficient-vector-operation work on members

Fixes https://llvm.org/PR50157

Adds support for when the container being read from in a range-for is a member of a struct.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D101624
This commit is contained in:
Nathan James 2022-04-08 14:17:37 +01:00
parent b20719dc7d
commit 0e0b0feff1
No known key found for this signature in database
GPG key ID: CC007AFCDA90AA5F
3 changed files with 41 additions and 2 deletions

View file

@ -68,6 +68,10 @@ ast_matchers::internal::Matcher<Expr> supportedContainerTypesMatcher() {
"::std::unordered_map", "::std::array", "::std::deque")));
}
AST_MATCHER(Expr, hasSideEffects) {
return Node.HasSideEffects(Finder->getASTContext());
}
} // namespace
InefficientVectorOperationCheck::InefficientVectorOperationCheck(
@ -145,7 +149,10 @@ void InefficientVectorOperationCheck::addMatcher(
// FIXME: Support more complex range-expressions.
Finder->addMatcher(
cxxForRangeStmt(
hasRangeInit(declRefExpr(supportedContainerTypesMatcher())),
hasRangeInit(
anyOf(declRefExpr(supportedContainerTypesMatcher()),
memberExpr(hasObjectExpression(unless(hasSideEffects())),
supportedContainerTypesMatcher()))),
HasInterestingLoopBody, InInterestingCompoundStmt)
.bind(RangeLoopName),
this);

View file

@ -127,6 +127,10 @@ New check aliases
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^
- Improved :doc:`performance-inefficient-vector-operation
<clang-tidy/checks/performance-inefficient-vector-operation>` to work when
the vector is a member of a structure.
- Fixed a false positive in :doc:`readability-non-const-parameter
<clang-tidy/checks/readability-non-const-parameter>` when the parameter is referenced by an lvalue

View file

@ -44,7 +44,7 @@ class vector {
void reserve(size_t n);
void resize(size_t n);
size_t size();
size_t size() const;
const_reference operator[] (size_type) const;
reference operator[] (size_type);
@ -359,3 +359,31 @@ void f(std::vector<int>& t) {
}
}
}
struct StructWithFieldContainer {
std::vector<int> Numbers;
std::vector<int> getNumbers() const {
std::vector<int> Result;
// CHECK-FIXES: Result.reserve(Numbers.size());
for (auto Number : Numbers) {
Result.push_back(Number);
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
}
return Result;
}
};
StructWithFieldContainer getStructWithField();
void foo(const StructWithFieldContainer &Src) {
std::vector<int> A;
// CHECK-FIXES: A.reserve(Src.Numbers.size());
for (auto Number : Src.Numbers) {
A.push_back(Number);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'push_back' is called
}
std::vector<int> B;
for (auto Number : getStructWithField().Numbers) {
B.push_back(Number);
}
}