forked from OSchip/llvm-project
333 lines
8.0 KiB
C++
333 lines
8.0 KiB
C++
// RUN: %check_clang_tidy %s readability-make-member-function-const %t
|
|
|
|
struct Str {
|
|
void const_method() const;
|
|
void non_const_method();
|
|
};
|
|
|
|
namespace Diagnose {
|
|
struct A;
|
|
|
|
void free_const_use(const A *);
|
|
void free_const_use(const A &);
|
|
|
|
struct A {
|
|
int M;
|
|
const int ConstM;
|
|
struct {
|
|
int M;
|
|
} Struct;
|
|
Str S;
|
|
Str &Sref;
|
|
|
|
void already_const() const;
|
|
|
|
int read_field() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_field' can be made const
|
|
// CHECK-FIXES: {{^}} int read_field() const {
|
|
return M;
|
|
}
|
|
|
|
int read_struct_field() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_struct_field' can be made const
|
|
// CHECK-FIXES: {{^}} int read_struct_field() const {
|
|
return Struct.M;
|
|
}
|
|
|
|
int read_const_field() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_const_field' can be made const
|
|
// CHECK-FIXES: {{^}} int read_const_field() const {
|
|
return ConstM;
|
|
}
|
|
|
|
void call_const_member() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
|
|
// CHECK-FIXES: {{^}} void call_const_member() const {
|
|
already_const();
|
|
}
|
|
|
|
void call_const_member_on_public_field() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field' can be made const
|
|
// CHECK-FIXES: {{^}} void call_const_member_on_public_field() const {
|
|
S.const_method();
|
|
}
|
|
|
|
void call_const_member_on_public_field_ref() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field_ref' can be made const
|
|
// CHECK-FIXES: {{^}} void call_const_member_on_public_field_ref() const {
|
|
Sref.const_method();
|
|
}
|
|
|
|
const Str &return_public_field_ref() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: method 'return_public_field_ref' can be made const
|
|
// CHECK-FIXES: {{^}} const Str &return_public_field_ref() const {
|
|
return S;
|
|
}
|
|
|
|
const A *return_this_const() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const' can be made const
|
|
// CHECK-FIXES: {{^}} const A *return_this_const() const {
|
|
return this;
|
|
}
|
|
|
|
const A &return_this_const_ref() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const_ref' can be made const
|
|
// CHECK-FIXES: {{^}} const A &return_this_const_ref() const {
|
|
return *this;
|
|
}
|
|
|
|
void const_use() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use' can be made const
|
|
// CHECK-FIXES: {{^}} void const_use() const {
|
|
free_const_use(this);
|
|
}
|
|
|
|
void const_use_ref() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use_ref' can be made const
|
|
// CHECK-FIXES: {{^}} void const_use_ref() const {
|
|
free_const_use(*this);
|
|
}
|
|
|
|
auto trailingReturn() -> int {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'trailingReturn' can be made const
|
|
// CHECK-FIXES: {{^}} auto trailingReturn() const -> int {
|
|
return M;
|
|
}
|
|
|
|
int volatileFunction() volatile {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'volatileFunction' can be made const
|
|
// CHECK-FIXES: {{^}} int volatileFunction() const volatile {
|
|
return M;
|
|
}
|
|
|
|
int restrictFunction() __restrict {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'restrictFunction' can be made const
|
|
// CHECK-FIXES: {{^}} int restrictFunction() const __restrict {
|
|
return M;
|
|
}
|
|
|
|
int refFunction() & {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'refFunction' can be made const
|
|
// CHECK-FIXES: {{^}} int refFunction() const & {
|
|
return M;
|
|
}
|
|
|
|
void out_of_line_call_const();
|
|
// CHECK-FIXES: {{^}} void out_of_line_call_const() const;
|
|
};
|
|
|
|
void A::out_of_line_call_const() {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_const' can be made const
|
|
// CHECK-FIXES: {{^}}void A::out_of_line_call_const() const {
|
|
already_const();
|
|
}
|
|
} // namespace Diagnose
|
|
|
|
namespace Keep {
|
|
struct Keep;
|
|
void free_non_const_use(Keep *);
|
|
void free_non_const_use(Keep &);
|
|
|
|
struct Keep {
|
|
private:
|
|
void private_const_method() const;
|
|
Str PrivateS;
|
|
Str *Sptr;
|
|
Str &Sref;
|
|
|
|
public:
|
|
int M;
|
|
Str S;
|
|
|
|
void keepTrivial() {}
|
|
|
|
// See readability-convert-member-functions-to-static instead.
|
|
void keepStatic() { int I = 0; }
|
|
|
|
const int *keepConstCast() const;
|
|
int *keepConstCast() { // Needs to stay non-const.
|
|
return const_cast<int *>(static_cast<const Keep *>(this)->keepConstCast());
|
|
}
|
|
|
|
void non_const_use() { free_non_const_use(this); }
|
|
void non_const_use_ref() { free_non_const_use(*this); }
|
|
|
|
Keep *return_this() {
|
|
return this;
|
|
}
|
|
|
|
Keep &return_this_ref() {
|
|
return *this;
|
|
}
|
|
|
|
void escape_this() {
|
|
Keep *Escaped = this;
|
|
}
|
|
|
|
void call_private_const_method() {
|
|
private_const_method();
|
|
}
|
|
|
|
int keepConst() const { return M; }
|
|
|
|
virtual int keepVirtual() { return M; }
|
|
|
|
void writeField() {
|
|
M = 1;
|
|
}
|
|
|
|
void callNonConstMember() { writeField(); }
|
|
|
|
void call_non_const_member_on_field() { S.non_const_method(); }
|
|
|
|
void call_const_member_on_private_field() {
|
|
// Technically, this method could be const-qualified,
|
|
// but it might not be logically const.
|
|
PrivateS.const_method();
|
|
}
|
|
|
|
const Str &return_private_field_ref() {
|
|
// Technically, this method could be const-qualified,
|
|
// but it might not be logically const.
|
|
return PrivateS;
|
|
}
|
|
|
|
void call_non_const_member_on_pointee() {
|
|
Sptr->non_const_method();
|
|
}
|
|
|
|
void call_const_member_on_pointee() {
|
|
// Technically, this method could be const-qualified,
|
|
// but it might not be logically const.
|
|
Sptr->const_method();
|
|
}
|
|
|
|
Str *return_pointer() {
|
|
// Technically, this method could be const-qualified,
|
|
// but it might not be logically const.
|
|
return Sptr;
|
|
}
|
|
|
|
const Str *return_const_pointer() {
|
|
// Technically, this method could be const-qualified,
|
|
// but it might not be logically const.
|
|
return Sptr;
|
|
}
|
|
|
|
void call_non_const_member_on_ref() {
|
|
Sref.non_const_method();
|
|
}
|
|
|
|
void escaped_private_field() {
|
|
const auto &Escaped = Sref;
|
|
}
|
|
|
|
Str &return_field_ref() {
|
|
// Technically, this method could be const-qualified,
|
|
// but it might not be logically const.
|
|
return Sref;
|
|
}
|
|
|
|
const Str &return_field_const_ref() {
|
|
// Technically, this method could be const-qualified,
|
|
// but it might not be logically const.
|
|
return Sref;
|
|
}
|
|
};
|
|
|
|
struct KeepVirtualDerived : public Keep {
|
|
int keepVirtual() { return M; }
|
|
};
|
|
|
|
void KeepLambdas() {
|
|
auto F = +[]() { return 0; };
|
|
auto F2 = []() { return 0; };
|
|
}
|
|
|
|
template <class Base>
|
|
struct KeepWithDependentBase : public Base {
|
|
int M;
|
|
// We cannot make this method const because it might need to override
|
|
// a function from Base.
|
|
int const_f() { return M; }
|
|
};
|
|
|
|
template <class T>
|
|
struct KeepClassTemplate {
|
|
int M;
|
|
// We cannot make this method const because a specialization
|
|
// might use *this differently.
|
|
int const_f() { return M; }
|
|
};
|
|
|
|
struct KeepMemberFunctionTemplate {
|
|
int M;
|
|
// We cannot make this method const because a specialization
|
|
// might use *this differently.
|
|
template <class T>
|
|
int const_f() { return M; }
|
|
};
|
|
|
|
void instantiate() {
|
|
struct S {};
|
|
KeepWithDependentBase<S> I1;
|
|
I1.const_f();
|
|
|
|
KeepClassTemplate<int> I2;
|
|
I2.const_f();
|
|
|
|
KeepMemberFunctionTemplate I3;
|
|
I3.const_f<int>();
|
|
}
|
|
|
|
struct NoFixitInMacro {
|
|
int M;
|
|
|
|
#define FUN const_use_macro()
|
|
int FUN {
|
|
return M;
|
|
}
|
|
|
|
#define T(FunctionName, Keyword) \
|
|
int FunctionName() Keyword { return M; }
|
|
#define EMPTY
|
|
T(A, EMPTY)
|
|
T(B, const)
|
|
|
|
#define T2(FunctionName) \
|
|
int FunctionName() { return M; }
|
|
T2(A2)
|
|
};
|
|
|
|
// Real-world code, see clang::ObjCInterfaceDecl.
|
|
class DataPattern {
|
|
int &data() const;
|
|
|
|
public:
|
|
const int &get() const {
|
|
return const_cast<DataPattern *>(this)->get();
|
|
}
|
|
|
|
// This member function must stay non-const, even though
|
|
// it only calls other private const member functions.
|
|
int &get() {
|
|
return data();
|
|
}
|
|
|
|
void set() {
|
|
data() = 42;
|
|
}
|
|
};
|
|
|
|
struct MemberFunctionPointer {
|
|
void call_non_const(void (MemberFunctionPointer::*FP)()) {
|
|
(this->*FP)();
|
|
}
|
|
|
|
void call_const(void (MemberFunctionPointer::*FP)() const) {
|
|
(this->*FP)();
|
|
}
|
|
};
|
|
|
|
} // namespace Keep
|