353 lines · cpp
1// RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -fno-delayed-template-parsing2 3namespace std {4 5template <typename _Tp>6struct remove_reference { typedef _Tp type; };7template <typename _Tp>8struct remove_reference<_Tp&> { typedef _Tp type; };9template <typename _Tp>10struct remove_reference<_Tp&&> { typedef _Tp type; };11 12template <typename _Tp>13constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {14 return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);15}16 17} // std18 19template <typename T>20struct Iterator {21 void operator++() {}22 const T& operator*() {23 static T* TT = new T();24 return *TT;25 }26 bool operator!=(const Iterator &) { return false; }27 typedef const T& const_reference;28};29template <typename T>30struct View {31 View() = default;32 T begin() { return T(); }33 T begin() const { return T(); }34 T end() { return T(); }35 T end() const { return T(); }36 typedef typename T::const_reference const_reference;37};38 39struct ConstructorConvertible {40};41 42struct S {43 S();44 S(const S &);45 S(const ConstructorConvertible&) {}46 ~S();47 S &operator=(const S &);48};49 50struct Point {51 ~Point() {}52 int x, y;53};54 55struct Convertible {56 operator S() const {57 return S();58 }59};60 61void negativeConstReference() {62 for (const S &S1 : View<Iterator<S>>()) {63 }64}65 66void negativeUserDefinedConversion() {67 Convertible C[0];68 for (const S S1 : C) {69 }70}71 72void negativeImplicitConstructorConversion() {73 ConstructorConvertible C[0];74 for (const S S1 : C) {75 }76}77 78template <typename T>79void uninstantiated() {80 for (const S S1 : View<Iterator<S>>()) {}81 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not a reference type; this creates a copy in each iteration; consider making this a reference [performance-for-range-copy]82 // CHECK-FIXES: for (const S& S1 : View<Iterator<S>>()) {}83 84 // Don't warn on dependent types.85 for (const T t1 : View<Iterator<T>>()) {86 }87}88 89template <typename T>90void instantiated() {91 for (const S S2 : View<Iterator<S>>()) {}92 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}93 // CHECK-FIXES: for (const S& S2 : View<Iterator<S>>()) {}94 95 for (const auto [X, Y] : View<Iterator<Point>>()) {}96 // CHECK-MESSAGES: [[@LINE-1]]:19: warning: the loop variable's type is97 // CHECK-FIXES: for (const auto& [X, Y] : View<Iterator<Point>>()) {}98 99 for (const T T2 : View<Iterator<T>>()) {}100 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}101 // CHECK-FIXES: for (const T& T2 : View<Iterator<T>>()) {}102}103 104template <typename T>105void instantiatedNegativeTypedefConstReference() {106 for (typename T::const_reference T2 : T()) {107 S S1 = T2;108 }109}110 111void f() {112 instantiated<int>();113 instantiated<S>();114 instantiatedNegativeTypedefConstReference<View<Iterator<S>>>();115}116 117struct Mutable {118 Mutable() {}119 Mutable(const Mutable &) = default;120 Mutable(Mutable&&) = default;121 Mutable(const Mutable &, const Mutable &) {}122 void setBool(bool B) {}123 bool constMethod() const {124 return true;125 }126 Mutable& operator[](int I) {127 return *this;128 }129 bool operator==(const Mutable &Other) const {130 return true;131 }132 ~Mutable() {}133};134 135Mutable& operator<<(Mutable &Out, bool B) {136 Out.setBool(B);137 return Out;138}139 140bool operator!=(const Mutable& M1, const Mutable& M2) {141 return false;142}143 144void use(const Mutable &M);145void use(int I);146void useTwice(const Mutable &M1, const Mutable &M2);147void useByValue(Mutable M);148void useByConstValue(const Mutable M);149void mutate(Mutable *M);150void mutate(Mutable &M);151void mutate(int &);152void onceConstOnceMutated(const Mutable &M1, Mutable &M2);153 154void negativeVariableIsMutated() {155 for (auto M : View<Iterator<Mutable>>()) {156 mutate(M);157 }158 for (auto M : View<Iterator<Mutable>>()) {159 mutate(&M);160 }161 for (auto M : View<Iterator<Mutable>>()) {162 M.setBool(true);163 }164}165 166void negativeOnceConstOnceMutated() {167 for (auto M : View<Iterator<Mutable>>()) {168 onceConstOnceMutated(M, M);169 }170}171 172void negativeVarIsMoved() {173 for (auto M : View<Iterator<Mutable>>()) {174 auto Moved = std::move(M);175 }176}177 178void negativeNonConstOperatorIsInvoked() {179 for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {180 auto& N = NonConstOperatorInvokee[0];181 }182}183 184void negativeNonConstNonMemberOperatorInvoked() {185 for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {186 NonConstOperatorInvokee << true;187 }188}189 190void negativeConstCheapToCopy() {191 for (const int I : View<Iterator<int>>()) {192 }193}194 195void negativeConstCheapToCopyTypedef() {196 typedef const int ConstInt;197 for (ConstInt C : View<Iterator<ConstInt>>()) {198 }199}200 201void negativeCheapToCopy() {202 for (int I : View<Iterator<int>>()) {203 use(I);204 }205}206 207void negativeCheapToCopyTypedef() {208 typedef int Int;209 for (Int I : View<Iterator<Int>>()) {210 use(I);211 }212}213 214void positiveOnlyConstMethodInvoked() {215 for (auto M : View<Iterator<Mutable>>()) {216 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]217 // CHECK-FIXES: for (const auto& M : View<Iterator<Mutable>>()) {218 M.constMethod();219 }220}221 222void positiveOnlyUsedAsConstArguments() {223 for (auto UsedAsConst : View<Iterator<Mutable>>()) {224 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]225 // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Mutable>>()) {226 use(UsedAsConst);227 useTwice(UsedAsConst, UsedAsConst);228 useByValue(UsedAsConst);229 useByConstValue(UsedAsConst);230 }231}232 233void positiveOnlyAccessedFieldAsConst() {234 for (auto UsedAsConst : View<Iterator<Point>>()) {235 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]236 // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Point>>()) {237 use(UsedAsConst.x);238 use(UsedAsConst.y);239 }240}241 242void positiveOnlyUsedAsConstBinding() {243 for (auto [X, Y] : View<Iterator<Point>>()) {244 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but245 // CHECK-FIXES: for (const auto& [X, Y] : View<Iterator<Point>>()) {246 use(X);247 use(Y);248 }249}250 251void negativeMutatedBinding() {252 for (auto [X, Y] : View<Iterator<Point>>()) {253 use(X);254 mutate(Y);255 }256}257 258void positiveOnlyUsedInCopyConstructor() {259 for (auto A : View<Iterator<Mutable>>()) {260 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]261 // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {262 Mutable Copy = A;263 Mutable Copy2(A);264 }265}266 267void positiveTwoConstConstructorArgs() {268 for (auto A : View<Iterator<Mutable>>()) {269 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]270 // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {271 Mutable Copy(A, A);272 }273}274 275void PositiveConstMemberOperatorInvoked() {276 for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {277 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]278 // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {279 bool result = ConstOperatorInvokee == Mutable();280 }281}282 283void PositiveConstNonMemberOperatorInvoked() {284 for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {285 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]286 // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {287 bool result = ConstOperatorInvokee != Mutable();288 }289}290 291void IgnoreLoopVariableNotUsedInLoopBody() {292 for (auto _ : View<Iterator<S>>()) {293 }294}295 296template <typename T>297struct ValueReturningIterator {298 void operator++() {}299 T operator*() { return T(); }300 bool operator!=(const ValueReturningIterator &) { return false; }301 typedef const T &const_reference;302};303 304void negativeValueIterator() {305 // Check does not trigger for iterators that return elements by value.306 for (const S SS : View<ValueReturningIterator<S>>()) {307 }308}309 310View<Iterator<S>> createView(S) { return View<Iterator<S>>(); }311 312void positiveValueIteratorUsedElseWhere() {313 for (const S SS : createView(*ValueReturningIterator<S>())) {314 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not a reference type; this creates a copy in each iteration; consider making this a reference [performance-for-range-copy]315 // CHECK-FIXES: for (const S& SS : createView(*ValueReturningIterator<S>())) {316 }317}318 319void positiveConstMemberExpr() {320 struct Struct {321 Mutable Member;322 };323 for (Struct SS : View<Iterator<Struct>>()) {324 // CHECK-MESSAGES: [[@LINE-1]]:15: warning: loop variable is copied325 // CHECK-FIXES: for (const Struct& SS : View<Iterator<Struct>>()) {326 auto MemberCopy = SS.Member;327 const auto &ConstRef = SS.Member;328 bool b = SS.Member.constMethod();329 use(SS.Member);330 useByConstValue(SS.Member);331 useByValue(SS.Member);332 }333}334 335void negativeNonConstMemberExpr() {336 struct Struct {337 Mutable Member;338 };339 for (Struct SS : View<Iterator<Struct>>()) {340 SS.Member.setBool(true);341 }342 for (Struct SS : View<Iterator<Struct>>()) {343 SS.Member[1];344 }345 for (Struct SS : View<Iterator<Struct>>()) {346 mutate(SS.Member);347 }348 for (Struct SS : View<Iterator<Struct>>()) {349 mutate(&SS.Member);350 }351}352 353