brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.8 KiB · c2a8ddc Raw
818 lines · cpp
1// RUN: %check_clang_tidy %s bugprone-unhandled-self-assignment %t -- -- -fno-delayed-template-parsing2 3namespace std {4 5template <class T>6void swap(T &x, T &y) {7}8 9template <class T>10T &&move(T &x) {11}12 13template <typename T> class default_delete {};14 15template <class T, typename Deleter = std::default_delete<T>>16class unique_ptr {17};18 19template <class T>20class shared_ptr {21};22 23template <class T>24class weak_ptr {25};26 27template <class T>28class auto_ptr {29};30 31namespace pmr {32    template <typename TYPE = void>33    class allocator {};34}35 36struct allocator_arg_t {} allocator_arg;37 38} // namespace std39 40void assert(int expression){};41 42///////////////////////////////////////////////////////////////////43/// Test cases correctly caught by the check.44 45class PtrField {46public:47  PtrField &operator=(const PtrField &object);48 49private:50  int *p;51};52 53PtrField &PtrField::operator=(const PtrField &object) {54  // CHECK-MESSAGES: [[@LINE-1]]:21: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]55  // ...56  return *this;57}58 59// Class with an inline operator definition.60class InlineDefinition {61public:62  InlineDefinition &operator=(const InlineDefinition &object) {63    // CHECK-MESSAGES: [[@LINE-1]]:21: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]64    // ...65    return *this;66  }67 68private:69  int *p;70};71 72class UniquePtrField {73public:74  UniquePtrField &operator=(const UniquePtrField &object) {75    // CHECK-MESSAGES: [[@LINE-1]]:19: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]76    // ...77    return *this;78  }79 80private:81  std::unique_ptr<int> p;82};83 84class SharedPtrField {85public:86  SharedPtrField &operator=(const SharedPtrField &object) {87    // CHECK-MESSAGES: [[@LINE-1]]:19: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]88    // ...89    return *this;90  }91 92private:93  std::shared_ptr<int> p;94};95 96class WeakPtrField {97public:98  WeakPtrField &operator=(const WeakPtrField &object) {99    // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]100    // ...101    return *this;102  }103 104private:105  std::weak_ptr<int> p;106};107 108class AutoPtrField {109public:110  AutoPtrField &operator=(const AutoPtrField &object) {111    // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]112    // ...113    return *this;114  }115 116private:117  std::auto_ptr<int> p;118};119 120// Class with C array field.121class CArrayField {122public:123  CArrayField &operator=(const CArrayField &object) {124    // CHECK-MESSAGES: [[@LINE-1]]:16: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]125    // ...126    return *this;127  }128 129private:130  int array[256];131};132 133// Make sure to not ignore cases when the operator definition calls134// a copy constructor of another class.135class CopyConstruct {136public:137  CopyConstruct &operator=(const CopyConstruct &object) {138    // CHECK-MESSAGES: [[@LINE-1]]:18: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]139    WeakPtrField a;140    WeakPtrField b(a);141    // ...142    return *this;143  }144 145private:146  int *p;147};148 149// Make sure to not ignore cases when the operator definition calls150// a copy assignment operator of another class.151class AssignOperator {152public:153  AssignOperator &operator=(const AssignOperator &object) {154    // CHECK-MESSAGES: [[@LINE-1]]:19: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]155    a.operator=(object.a);156    // ...157    return *this;158  }159 160private:161  int *p;162  WeakPtrField a;163};164 165class NotSelfCheck {166public:167  NotSelfCheck &operator=(const NotSelfCheck &object) {168    // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]169    if (&object == this->doSomething()) {170      // ...171    }172    return *this;173  }174 175  void *doSomething() {176    return p;177  }178 179private:180  int *p;181};182 183template <class T>184class TemplatePtrField {185public:186  TemplatePtrField<T> &operator=(const TemplatePtrField<T> &object) {187    // CHECK-MESSAGES: [[@LINE-1]]:24: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]188    // ...189    return *this;190  }191 192private:193  T *p;194};195 196template <class T>197class TemplateCArrayField {198public:199  TemplateCArrayField<T> &operator=(const TemplateCArrayField<T> &object) {200    // CHECK-MESSAGES: [[@LINE-1]]:27: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]201    // ...202    return *this;203  }204 205private:206  T p[256];207};208 209// Other template class's constructor is called inside a declaration.210template <class T>211class WrongTemplateCopyAndMove {212public:213  WrongTemplateCopyAndMove<T> &operator=(const WrongTemplateCopyAndMove<T> &object) {214    // CHECK-MESSAGES: [[@LINE-1]]:32: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]215    TemplatePtrField<T> temp;216    TemplatePtrField<T> temp2(temp);217    return *this;218  }219 220private:221  T *p;222};223 224// https://bugs.llvm.org/show_bug.cgi?id=44499225class Foo2;226template <int a>227bool operator!=(Foo2 &, Foo2 &) {228  class Bar2 {229    Bar2 &operator=(const Bar2 &other) {230      // CHECK-MESSAGES: [[@LINE-1]]:11: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]231      p = other.p;232      return *this;233    }234 235    int *p;236  };237}238 239// Missing call to `swap` function240class AllocatorAwareClassNoSwap {241  // pointer member to trigger bugprone-unhandled-self-assignment242  void *foo = nullptr;243 244  public:245    using allocator_type = std::pmr::allocator<>;246 247    AllocatorAwareClassNoSwap(const AllocatorAwareClassNoSwap& other) {248    }249 250    AllocatorAwareClassNoSwap(const AllocatorAwareClassNoSwap& other, const allocator_type& alloc) {251    }252 253    AllocatorAwareClassNoSwap& operator=(const AllocatorAwareClassNoSwap& other) {254        // CHECK-MESSAGES: [[@LINE-1]]:32: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]255        AllocatorAwareClassNoSwap tmp(other, get_allocator());256        return *this;257    }258 259    allocator_type get_allocator() const {260        return allocator_type();261    }262};263 264// "Wrong" type is passed to member `swap` function265class AllocatorAwareClassSwapWrongArgType {266  // pointer member to trigger bugprone-unhandled-self-assignment267  void *foo = nullptr;268 269  public:270    using allocator_type = std::pmr::allocator<>;271 272    AllocatorAwareClassSwapWrongArgType(const AllocatorAwareClassSwapWrongArgType& other) {273    }274 275    AllocatorAwareClassSwapWrongArgType(const AllocatorAwareClassSwapWrongArgType& other, const allocator_type& alloc) {276    }277 278    AllocatorAwareClassSwapWrongArgType& operator=(const AllocatorAwareClassSwapWrongArgType& other) {279        // CHECK-MESSAGES: [[@LINE-1]]:42: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]280        int tmp = 0;281        swap(tmp);282        283        return *this;284    }285 286    void swap(int&) noexcept {287    }288 289    allocator_type get_allocator() const {290        return allocator_type();291    }292};293 294 295// Making ADL `swap` call but with wrong argument type296class AllocatorAwareClassAdlSwapWrongArgType {297  // pointer member to trigger bugprone-unhandled-self-assignment298  void *foo = nullptr;299 300  public:301    using allocator_type = std::pmr::allocator<>;302 303    AllocatorAwareClassAdlSwapWrongArgType(const AllocatorAwareClassAdlSwapWrongArgType& other) {304    }305 306    AllocatorAwareClassAdlSwapWrongArgType(const AllocatorAwareClassAdlSwapWrongArgType& other, const allocator_type& alloc) {307    }308 309    AllocatorAwareClassAdlSwapWrongArgType& operator=(const AllocatorAwareClassAdlSwapWrongArgType& other) {310        // CHECK-MESSAGES: [[@LINE-1]]:45: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]311        int tmp = 0;312        swap(*this, tmp);313        314        return *this;315    }316 317    allocator_type get_allocator() const {318        return allocator_type();319    }320    321    friend void swap(AllocatorAwareClassAdlSwapWrongArgType&, int&) {322    }323};324 325// `this` isn't passed to `swap`326class AllocatorAwareClassAdlSwapWrongArgs {327  // pointer member to trigger bugprone-unhandled-self-assignment328  void *foo = nullptr;329 330  public:331    using allocator_type = std::pmr::allocator<>;332 333    AllocatorAwareClassAdlSwapWrongArgs(const AllocatorAwareClassAdlSwapWrongArgs& other) {334    }335 336    AllocatorAwareClassAdlSwapWrongArgs(const AllocatorAwareClassAdlSwapWrongArgs& other, const allocator_type& alloc) {337    }338 339    AllocatorAwareClassAdlSwapWrongArgs& operator=(const AllocatorAwareClassAdlSwapWrongArgs& other) {340        // CHECK-MESSAGES: [[@LINE-1]]:42: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]341        AllocatorAwareClassAdlSwapWrongArgs tmp1(other, get_allocator());342        AllocatorAwareClassAdlSwapWrongArgs tmp2(*this, get_allocator());343        swap(tmp1, tmp2);344        return *this;345    }346 347    allocator_type get_allocator() const {348        return allocator_type();349    }350    351    friend void swap(AllocatorAwareClassAdlSwapWrongArgs&, AllocatorAwareClassAdlSwapWrongArgs&) {352    }353};354 355///////////////////////////////////////////////////////////////////356/// Test cases correctly ignored by the check.357 358// Self-assignment is checked using the equality operator.359class SelfCheck1 {360public:361  SelfCheck1 &operator=(const SelfCheck1 &object) {362    if (this == &object)363      return *this;364    // ...365    return *this;366  }367 368private:369  int *p;370};371 372class SelfCheck2 {373public:374  SelfCheck2 &operator=(const SelfCheck2 &object) {375    if (&object == this)376      return *this;377    // ...378    return *this;379  }380 381private:382  int *p;383};384 385// Self-assignment is checked using the inequality operator.386class SelfCheck3 {387public:388  SelfCheck3 &operator=(const SelfCheck3 &object) {389    if (this != &object) {390      // ...391    }392    return *this;393  }394 395private:396  int *p;397};398 399class SelfCheck4 {400public:401  SelfCheck4 &operator=(const SelfCheck4 &object) {402    if (&object != this) {403      // ...404    }405    return *this;406  }407 408private:409  int *p;410};411 412template <class T>413class TemplateSelfCheck {414public:415  TemplateSelfCheck<T> &operator=(const TemplateSelfCheck<T> &object) {416    if (&object != this) {417      // ...418    }419    return *this;420  }421 422private:423  T *p;424};425 426// https://bugs.llvm.org/show_bug.cgi?id=44499427class Foo;428template <int a>429bool operator!=(Foo &, Foo &) {430  class Bar {431    Bar &operator=(const Bar &other) {432      if (this != &other) {433      }434      return *this;435    }436 437    int *p;438  };439}440 441// There is no warning if the copy assignment operator gets the object by value.442class PassedByValue {443public:444  PassedByValue &operator=(PassedByValue object) {445    // ...446    return *this;447  }448 449private:450  int *p;451};452 453// User-defined swap method calling std::swap inside.454class CopyAndSwap1 {455public:456  CopyAndSwap1 &operator=(const CopyAndSwap1 &object) {457    CopyAndSwap1 temp(object);458    doSwap(temp);459    return *this;460  }461 462private:463  int *p;464 465  void doSwap(CopyAndSwap1 &object) {466    using std::swap;467    swap(p, object.p);468  }469};470 471// User-defined swap method used with passed-by-value parameter.472class CopyAndSwap2 {473public:474  CopyAndSwap2 &operator=(CopyAndSwap2 object) {475    doSwap(object);476    return *this;477  }478 479private:480  int *p;481 482  void doSwap(CopyAndSwap2 &object) {483    using std::swap;484    swap(p, object.p);485  }486};487 488// Copy-and-swap method is used but without creating a separate method for it.489class CopyAndSwap3 {490public:491  CopyAndSwap3 &operator=(const CopyAndSwap3 &object) {492    CopyAndSwap3 temp(object);493    std::swap(p, temp.p);494    return *this;495  }496 497private:498  int *p;499};500 501template <class T>502class TemplateCopyAndSwap {503public:504  TemplateCopyAndSwap<T> &operator=(const TemplateCopyAndSwap<T> &object) {505    TemplateCopyAndSwap<T> temp(object);506    std::swap(p, temp.p);507    return *this;508  }509 510private:511  T *p;512};513 514// Move semantics is used on a temporary copy of the object.515class CopyAndMove1 {516public:517  CopyAndMove1 &operator=(const CopyAndMove1 &object) {518    CopyAndMove1 temp(object);519    *this = std::move(temp);520    return *this;521  }522 523private:524  int *p;525};526 527// There is no local variable for the temporary copy.528class CopyAndMove2 {529public:530  CopyAndMove2 &operator=(const CopyAndMove2 &object) {531    *this = CopyAndMove2(object);532    return *this;533  }534 535private:536  int *p;537};538 539template <class T>540class TemplateCopyAndMove {541public:542  TemplateCopyAndMove<T> &operator=(const TemplateCopyAndMove<T> &object) {543    TemplateCopyAndMove<T> temp(object);544    *this = std::move(temp);545    return *this;546  }547 548private:549  T *p;550};551 552// There is no local variable for the temporary copy.553template <class T>554class TemplateCopyAndMove2 {555public:556  TemplateCopyAndMove2<T> &operator=(const TemplateCopyAndMove2<T> &object) {557    *this = std::move(TemplateCopyAndMove2<T>(object));558    return *this;559  }560 561private:562  T *p;563};564 565// We should not catch move assignment operators.566class MoveAssignOperator {567public:568  MoveAssignOperator &operator=(MoveAssignOperator &&object) {569    // ...570    return *this;571  }572 573private:574  int *p;575};576 577// We ignore copy assignment operators without user-defined implementation.578class DefaultOperator {579public:580  DefaultOperator &operator=(const DefaultOperator &object) = default;581 582private:583  int *p;584};585 586class DeletedOperator {587public:588  DeletedOperator &operator=(const DefaultOperator &object) = delete;589 590private:591  int *p;592};593 594class ImplicitOperator {595private:596  int *p;597};598 599// Check ignores those classes which has no any pointer or array field.600class TrivialFields {601public:602  TrivialFields &operator=(const TrivialFields &object) {603    // ...604    return *this;605  }606 607private:608  int m;609  float f;610  double d;611  bool b;612};613 614// There is no warning when the class calls another assignment operator on 'this'615// inside the copy assignment operator's definition.616class AssignIsForwarded {617public:618  AssignIsForwarded &operator=(const AssignIsForwarded &object) {619    operator=(object.p);620    return *this;621  }622 623  AssignIsForwarded &operator=(int *pp) {624    if (p != pp) {625      delete p;626      p = new int(*pp);627    }628    return *this;629  }630 631private:632  int *p;633};634 635// Assertion is a valid way to say that self-assignment is not expected to happen.636class AssertGuard {637public:638  AssertGuard &operator=(const AssertGuard &object) {639    assert(this != &object);640    // ...641    return *this;642  }643 644private:645  int *p;646};647 648// Make sure we don't catch this operator=() as a copy assignment operator.649// Note that RHS has swapped template arguments.650template <typename Ty, typename Uy>651class NotACopyAssignmentOperator {652  Ty *Ptr1;653  Uy *Ptr2;654 655public:656  NotACopyAssignmentOperator& operator=(const NotACopyAssignmentOperator<Uy, Ty> &RHS) {657    Ptr1 = RHS.getUy();658    Ptr2 = RHS.getTy();659    return *this;660  }661 662  Ty *getTy() const { return Ptr1; }663  Uy *getUy() const { return Ptr2; }664};665 666// Support "extended" copy/move constructors667class AllocatorAwareClass {668  // pointer member to trigger bugprone-unhandled-self-assignment669  void *foo = nullptr;670 671  public:672    using allocator_type = std::pmr::allocator<>;673 674    AllocatorAwareClass(const AllocatorAwareClass& other) {675    }676 677    AllocatorAwareClass(const AllocatorAwareClass& other, const allocator_type& alloc) {678    }679 680    AllocatorAwareClass& operator=(const AllocatorAwareClass& other) {681        AllocatorAwareClass tmp(other, get_allocator());682        swap(tmp);683        return *this;684    }685 686    void swap(AllocatorAwareClass& other) noexcept {687    }688 689    allocator_type get_allocator() const {690        return allocator_type();691    }692};693 694// Support "extended" copy/move constructors + std::swap695class AllocatorAwareClassStdSwap {696  // pointer member to trigger bugprone-unhandled-self-assignment697  void *foo = nullptr;698 699  public:700    using allocator_type = std::pmr::allocator<>;701 702    AllocatorAwareClassStdSwap(const AllocatorAwareClassStdSwap& other) {703    }704 705    AllocatorAwareClassStdSwap(const AllocatorAwareClassStdSwap& other, const allocator_type& alloc) {706    }707 708    AllocatorAwareClassStdSwap& operator=(const AllocatorAwareClassStdSwap& other) {709        using std::swap;710        711        AllocatorAwareClassStdSwap tmp(other, get_allocator());712        swap(*this, tmp);713        return *this;714    }715 716    allocator_type get_allocator() const {717        return allocator_type();718    }719};720 721// Support "extended" copy/move constructors + ADL swap722class AllocatorAwareClassAdlSwap {723  // pointer member to trigger bugprone-unhandled-self-assignment724  void *foo = nullptr;725 726  public:727    using allocator_type = std::pmr::allocator<>;728 729    AllocatorAwareClassAdlSwap(const AllocatorAwareClassAdlSwap& other) {730    }731 732    AllocatorAwareClassAdlSwap(const AllocatorAwareClassAdlSwap& other, const allocator_type& alloc) {733    }734 735    AllocatorAwareClassAdlSwap& operator=(const AllocatorAwareClassAdlSwap& other) {736        AllocatorAwareClassAdlSwap tmp(other, get_allocator());737        swap(*this, tmp);738        return *this;739    }740 741    allocator_type get_allocator() const {742        return allocator_type();743    }744    745    friend void swap(AllocatorAwareClassAdlSwap&, AllocatorAwareClassAdlSwap&) {746    }747};748 749///////////////////////////////////////////////////////////////////750/// Test cases which should be caught by the check.751 752// TODO: handle custom pointers.753template <class T>754class custom_ptr {755};756 757class CustomPtrField {758public:759  CustomPtrField &operator=(const CustomPtrField &object) {760    // ...761    return *this;762  }763 764private:765  custom_ptr<int> p;766};767 768/////////////////////////////////////////////////////////////////////////////////////////////////////769/// False positives: These are self-assignment safe, but they don't use any of the three patterns.770 771class ArrayCopy {772public:773  ArrayCopy &operator=(const ArrayCopy &object) {774    // CHECK-MESSAGES: [[@LINE-1]]:14: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]775    for (int i = 0; i < 256; i++)776      array[i] = object.array[i];777    return *this;778  }779 780private:781  int array[256];782};783 784class GetterSetter {785public:786  GetterSetter &operator=(const GetterSetter &object) {787    // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]788    setValue(object.getValue());789    return *this;790  }791 792  int *getValue() const { return value; }793 794  void setValue(int *newPtr) {795    int *pTmp(newPtr ? new int(*newPtr) : nullptr);796    std::swap(value, pTmp);797    delete pTmp;798  }799 800private:801  int *value;802};803 804class CustomSelfCheck {805public:806  CustomSelfCheck &operator=(const CustomSelfCheck &object) {807    // CHECK-MESSAGES: [[@LINE-1]]:20: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]808    if (index != object.index) {809      // ...810    }811    return *this;812  }813 814private:815  int *value;816  int index;817};818