File: unconventional-assign-operator.cpp

package info (click to toggle)
llvm-toolchain-15 1%3A15.0.6-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,554,644 kB
  • sloc: cpp: 5,922,452; ansic: 1,012,136; asm: 674,362; python: 191,568; objc: 73,855; f90: 42,327; lisp: 31,913; pascal: 11,973; javascript: 10,144; sh: 9,421; perl: 7,447; ml: 5,527; awk: 3,523; makefile: 2,520; xml: 885; cs: 573; fortran: 567
file content (165 lines) | stat: -rw-r--r-- 5,044 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -fno-delayed-template-parsing

namespace std {
template <typename T>
struct remove_reference { typedef T type; };
template <typename T>
struct remove_reference<T &> { typedef T type; };
template <typename T>
struct remove_reference<T &&> { typedef T type; };
template <typename T>
typename remove_reference<T>::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 'BadAr
};

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 <typename>
struct UnresolvedOperator {
  UnresolvedOperator &operator=(const UnresolvedOperator &) { return *this; }
};

UnresolvedOperator<int> UnresolvedOperatorInt;

template <typename>
struct Template {
  Template &operator=(const Template &) { return this; }
  // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: operator=() should always return '*this'
};

Template<int> 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<int>(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 <typename T>
struct TemplateTypeAlias {
  using Alias1 = TemplateTypeAlias &;
  using Alias2 = TemplateTypeAlias const &;
  Alias1 operator=(Alias2) { return *this; }

  template <typename U>
  using Alias3 = TemplateTypeAlias<U>;
  Alias3<T> &operator=(int) { return *this; }

  // Using a different type parameter in the return type should give a warning
  Alias3<TypeAlias::Alias> &operator=(double) { return *this; }
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'TemplateTypeAlias&' [misc-unconventional-assign-operator]
};