// 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 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 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 std::add_const::type n15(T v) { return v; } template 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 p5() const; // CHECK-FIXES: const Klazz* 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& n11(const Klazz) 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 Clazz::p5() const {} // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz * // CHECK-FIXES: const Klazz* 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 p12() {} // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz' // CHECK-FIXES: Klazz p12() {} const Klazz* const p13() {} // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz * // CHECK-FIXES: const Klazz* 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::type p28() { return 3; } // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'std::add_const::typ // p29, p30 are based on // llvm/projects/test-suite/SingleSource/Benchmarks/Misc-C++-EH/spirit.cpp: template Klazz const p29(T const &t) { return {}; } // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz' is // CHECK-FIXES: Klazz p29(T const &t) { return {}; } Klazz const p30(char const *s) { return s; } // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz 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 n9(); const Klazz* n10(); const Klazz& Clazz::n11(const Klazz) const {} // Declaration only. const int n14(); int **const * n_multiple_ptr(); int *const & n_pointer_ref();