blob: 78557c5e652e3e0d639aef01e250d057c8182761 [file] [log] [blame]
// RUN: %check_clang_tidy %s readability-const-return-type %t
// p# = positive test
// n# = negative test
namespace std {
template< class T >
struct add_cv { typedef const volatile T type; };
template< class T> struct add_const { typedef const T type; };
template< class T> struct add_volatile { typedef volatile T type; };
}
const int p1() {
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qualified at the top level, which may reduce code readability without improving const correctness
// CHECK-FIXES: int p1() {
return 1;
}
const int p15();
// CHECK-FIXES: int p15();
template <typename T>
const int p31(T v) { return 2; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
// CHECK-FIXES: int p31(T v) { return 2; }
// We detect const-ness even without instantiating T.
template <typename T>
const T p32(T t) { return t; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const T' is 'const'-qual
// CHECK-FIXES: T p32(T t) { return t; }
// However, if the return type is itself a template instantiation, Clang does
// not consider it const-qualified without knowing `T`.
template <typename T>
typename std::add_const<T>::type n15(T v) { return v; }
template <typename A>
class Klazz {
public:
Klazz(A) {}
};
class Clazz {
public:
Clazz *const p2() {
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'Clazz *const' is 'co
// CHECK-FIXES: Clazz *p2() {
return this;
}
Clazz *const p3();
// CHECK-FIXES: Clazz *p3();
const int p4() const {
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 'const
// CHECK-FIXES: int p4() const {
return 4;
}
const Klazz<const int>* const p5() const;
// CHECK-FIXES: const Klazz<const int>* p5() const;
const Clazz operator++(int x) { // p12
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz' is 'const
// CHECK-FIXES: Clazz operator++(int x) {
}
struct Strukt {
int i;
};
const Strukt p6() {}
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz::Strukt' i
// CHECK-FIXES: Strukt p6() {}
// No warning is emitted here, because this is only the declaration. The
// warning will be associated with the definition, below.
const Strukt* const p7();
// CHECK-FIXES: const Strukt* p7();
// const-qualifier is the first `const` token, but not the first token.
static const int p8() {}
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 'const'-
// CHECK-FIXES: static int p8() {}
static const Strukt p9() {}
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const Clazz::Strukt' i
// CHECK-FIXES: static Strukt p9() {}
int n0() const { return 0; }
const Klazz<const int>& n11(const Klazz<const int>) const;
};
Clazz *const Clazz::p3() {
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'Clazz *const' is 'cons
// CHECK-FIXES: Clazz *Clazz::p3() {
return this;
}
const Klazz<const int>* const Clazz::p5() const {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
// CHECK-FIXES: const Klazz<const int>* Clazz::p5() const {}
const Clazz::Strukt* const Clazz::p7() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Clazz::Strukt *con
// CHECK-FIXES: const Clazz::Strukt* Clazz::p7() {}
Clazz *const p10();
// CHECK-FIXES: Clazz *p10();
Clazz *const p10() {
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'Clazz *const' is 'cons
// CHECK-FIXES: Clazz *p10() {
return new Clazz();
}
const Clazz bar;
const Clazz *const p11() {
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Clazz *const' is
// CHECK-FIXES: const Clazz *p11() {
return &bar;
}
const Klazz<const int> p12() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int>'
// CHECK-FIXES: Klazz<const int> p12() {}
const Klazz<const int>* const p13() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
// CHECK-FIXES: const Klazz<const int>* p13() {}
// re-declaration of p15.
const int p15();
// CHECK-FIXES: int p15();
const int p15() {
// CHECK-MESSAGES: [[@LINE-1]]:1: warning:
// CHECK-FIXES: int p15() {
return 0;
}
// Exercise the lexer.
const /* comment */ /* another comment*/ int p16() { return 0; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning:
// CHECK-FIXES: /* comment */ /* another comment*/ int p16() { return 0; }
/* comment */ const
// CHECK-MESSAGES: [[@LINE-1]]:15: warning:
// CHECK-FIXES: /* comment */
// more
/* another comment*/ int p17() { return 0; }
// Test cases where the `const` token lexically is hidden behind some form of
// indirection.
#define CONSTINT const int
CONSTINT p18() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
#define CONST const
CONST int p19() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
using ty = const int;
ty p21() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty' (aka 'const int') is
typedef const int ty2;
ty2 p22() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty2' (aka 'const int') i
// Declaration uses a macro, while definition doesn't. In this case, we won't
// fix the declaration, and will instead issue a warning.
CONST int p23();
// CHECK-NOTE: [[@LINE-1]]:1: note: could not transform this declaration
const int p23();
// CHECK-FIXES: int p23();
const int p23() { return 3; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
// CHECK-FIXES: int p23() { return 3; }
int const p24() { return 3; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
// CHECK-FIXES: int p24() { return 3; }
int const * const p25(const int* p) { return p; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int *const' is 'co
// CHECK-FIXES: int const * p25(const int* p) { return p; }
// We cannot (yet) fix instances that use trailing return types, but we can
// warn.
auto p26() -> const int { return 3; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
auto p27() -> int const { return 3; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu
std::add_const<int>::type p28() { return 3; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'std::add_const<int>::typ
// p29, p30 are based on
// llvm/projects/test-suite/SingleSource/Benchmarks/Misc-C++-EH/spirit.cpp:
template <class T>
Klazz<T const> const p29(T const &t) { return {}; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const T>' is
// CHECK-FIXES: Klazz<T const> p29(T const &t) { return {}; }
Klazz<char const *> const p30(char const *s) { return s; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const char *
// CHECK-FIXES: Klazz<char const *> p30(char const *s) { return s; }
const int n1 = 1;
const Clazz n2 = Clazz();
const Clazz* n3 = new Clazz();
Clazz *const n4 = new Clazz();
const Clazz *const n5 = new Clazz();
constexpr int n6 = 6;
constexpr int n7() { return 8; }
const int eight = 8;
constexpr const int* n8() { return &eight; }
Klazz<const int> n9();
const Klazz<const int>* n10();
const Klazz<const int>& Clazz::n11(const Klazz<const int>) const {}
// Declaration only.
const int n14();
int **const * n_multiple_ptr();
int *const & n_pointer_ref();