// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -fno-delayed-template-parsing namespace std { template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template typename remove_reference::type &&move(T &&t); } struct Good { Good& operator=(const Good&); Good& operator=(Good&&); // Assign from other types is fine too. Good& operator=(int); }; struct AlsoGood { // By value is also fine. AlsoGood& operator=(AlsoGood); }; struct BadReturnType { void operator=(const BadReturnType&); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'BadReturnType&' [misc-unconventional-assign-operator] const BadReturnType& operator=(BadReturnType&&); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad void operator=(int); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad }; struct BadReturnType2 { BadReturnType2&& operator=(const BadReturnType2&); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad int operator=(BadReturnType2&&); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad }; struct BadArgument { BadArgument& operator=(BadArgument&); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadArgument const&', 'BadArgument&&' or 'BadArgument' BadArgument& operator=(const BadArgument&&); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadArgument const&', 'BadArgument&&' or 'BadArgument' }; struct BadModifier { BadModifier& operator=(const BadModifier&) const; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const' }; struct Deleted { // We don't check the return value of deleted operators. void operator=(const Deleted&) = delete; void operator=(Deleted&&) = delete; }; class Private { // We don't check the return value of private operators. // Pre-C++11 way of disabling assignment. void operator=(const Private &); }; struct Virtual { virtual Virtual& operator=(const Virtual &); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'virtual' }; class BadReturnStatement { int n; public: BadReturnStatement& operator=(BadReturnStatement&& rhs) { n = std::move(rhs.n); return *&rhs; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this' } // Do not check if return type is different from '&BadReturnStatement' int operator=(int i) { // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad n = i; return n; } }; namespace pr31531 { enum E { e }; // This declaration makes the 'return *this' below have an unresolved operator // in the class template, but not in an instantiation. E operator*(E, E); template struct UnresolvedOperator { UnresolvedOperator &operator=(const UnresolvedOperator &) { return *this; } }; UnresolvedOperator UnresolvedOperatorInt; template struct Template { Template &operator=(const Template &) { return this; } // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: operator=() should always return '*this' }; Template TemplateInt; } struct AssignmentCallAtReturn { AssignmentCallAtReturn &returnThis() { return *this; } AssignmentCallAtReturn &operator=(int rhs) { return *this; } AssignmentCallAtReturn &operator=(char rhs) { // Allow call to assignment from other type. return (*this = static_cast(rhs)); } AssignmentCallAtReturn &operator=(float rhs) { // Do not allow calls to other functions. return returnThis(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this' } }; // Check that no false positives are issued when using type aliases. struct TypeAlias { using Alias = TypeAlias; // This is correct and should not produce any warnings: Alias &operator=(const Alias &) { return *this; } using AliasRef = Alias &; // So is this (assignments from other types are fine): AliasRef operator=(int) { return *this; } }; // Same check as above with typedef instead of using struct TypeAliasTypedef { typedef TypeAliasTypedef Alias; Alias &operator=(const Alias &) { return *this; } typedef Alias &AliasRef; AliasRef operator=(int) { return *this; } }; // Same check as above for a template class template struct TemplateTypeAlias { using Alias1 = TemplateTypeAlias &; using Alias2 = TemplateTypeAlias const &; Alias1 operator=(Alias2) { return *this; } template using Alias3 = TemplateTypeAlias; Alias3 &operator=(int) { return *this; } // Using a different type parameter in the return type should give a warning Alias3 &operator=(double) { return *this; } // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'TemplateTypeAlias&' [misc-unconventional-assign-operator] };