CJ-Johnson updated this revision to Diff 388972. CJ-Johnson marked 6 inline comments as done. CJ-Johnson added a comment.
Address reviewer comments Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D113148/new/ https://reviews.llvm.org/D113148 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/StringviewNullptrCheck.cpp clang-tools-extra/clang-tidy/bugprone/StringviewNullptrCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-stringview-nullptr.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-stringview-nullptr.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-stringview-nullptr.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-stringview-nullptr.cpp @@ -0,0 +1,1417 @@ +// RUN: %check_clang_tidy %s bugprone-stringview-nullptr -std=c++17 %t + +namespace std { + +using nullptr_t = decltype(nullptr); + +template <typename T> +T &&declval(); + +template <typename T> +struct type_identity { using type = T; }; +template <typename T> +using type_identity_t = typename type_identity<T>::type; + +template <typename C> +class basic_string_view { +public: + basic_string_view(); + basic_string_view(const C *); + basic_string_view(const basic_string_view &); + basic_string_view &operator=(const basic_string_view &); +}; + +template <typename C> +bool operator<(basic_string_view<C>, basic_string_view<C>); +template <typename C> +bool operator<(type_identity_t<basic_string_view<C>>, basic_string_view<C>); +template <typename C> +bool operator<(basic_string_view<C>, type_identity_t<basic_string_view<C>>); + +template <typename C> +bool operator<=(basic_string_view<C>, basic_string_view<C>); +template <typename C> +bool operator<=(type_identity_t<basic_string_view<C>>, basic_string_view<C>); +template <typename C> +bool operator<=(basic_string_view<C>, type_identity_t<basic_string_view<C>>); + +template <typename C> +bool operator>(basic_string_view<C>, basic_string_view<C>); +template <typename C> +bool operator>(type_identity_t<basic_string_view<C>>, basic_string_view<C>); +template <typename C> +bool operator>(basic_string_view<C>, type_identity_t<basic_string_view<C>>); + +template <typename C> +bool operator>=(basic_string_view<C>, basic_string_view<C>); +template <typename C> +bool operator>=(type_identity_t<basic_string_view<C>>, basic_string_view<C>); +template <typename C> +bool operator>=(basic_string_view<C>, type_identity_t<basic_string_view<C>>); + +template <typename C> +bool operator==(basic_string_view<C>, basic_string_view<C>); +template <typename C> +bool operator==(type_identity_t<basic_string_view<C>>, basic_string_view<C>); +template <typename C> +bool operator==(basic_string_view<C>, type_identity_t<basic_string_view<C>>); + +template <typename C> +bool operator!=(basic_string_view<C>, basic_string_view<C>); +template <typename C> +bool operator!=(type_identity_t<basic_string_view<C>>, basic_string_view<C>); +template <typename C> +bool operator!=(basic_string_view<C>, type_identity_t<basic_string_view<C>>); + +using string_view = basic_string_view<char>; + +} // namespace std + +void function(std::string_view); +void function(std::string_view, std::string_view); + +void temporary_construction() /* a */ { + // Functional Cast + { + (void)(std::string_view(nullptr)) /* a1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing basic_string_view from null is undefined; replace with the default constructor + // CHECK-FIXES: {{^}} (void)(std::string_view()) /* a1 */; + + (void)(std::string_view((nullptr))) /* a2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view()) /* a2 */; + + (void)(std::string_view({nullptr})) /* a3 */; + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view()) /* a3 */; + + (void)(std::string_view({(nullptr)})) /* a4 */; + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view()) /* a4 */; + + (void)(std::string_view({})) /* a5 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view()) /* a5 */; + + // (void)(const std::string_view(nullptr)) /* a6 */; + // CV qualifiers do not compile in this context + + // (void)(const std::string_view((nullptr))) /* a7 */; + // CV qualifiers do not compile in this context + + // (void)(const std::string_view({nullptr})) /* a8 */; + // CV qualifiers do not compile in this context + + // (void)(const std::string_view({(nullptr)})) /* a9 */; + // CV qualifiers do not compile in this context + + // (void)(const std::string_view({})) /* a10 */; // Default `const CharT*` + // CV qualifiers do not compile in this context + } + + // Temporary Object + { + (void)(std::string_view{nullptr}) /* a11 */; + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view{}) /* a11 */; + + (void)(std::string_view{(nullptr)}) /* a12 */; + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view{}) /* a12 */; + + (void)(std::string_view{{nullptr}}) /* a13 */; + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view{}) /* a13 */; + + (void)(std::string_view{{(nullptr)}}) /* a14 */; + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view{}) /* a14 */; + + (void)(std::string_view{{}}) /* a15 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(std::string_view{}) /* a15 */; + + // (void)(const std::string_view{nullptr}) /* a16 */; + // CV qualifiers do not compile in this context + + // (void)(const std::string_view{(nullptr)}) /* a17 */; + // CV qualifiers do not compile in this context + + // (void)(const std::string_view{{nullptr}}) /* a18 */; + // CV qualifiers do not compile in this context + + // (void)(const std::string_view{{(nullptr)}}) /* a19 */; + // CV qualifiers do not compile in this context + + // (void)(const std::string_view{{}}) /* a20 */; // Default `const CharT*` + // CV qualifiers do not compile in this context + } + + // C-Style Cast && Compound Literal + { + (void)((std::string_view) nullptr) /* a21 */; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((std::string_view) {}) /* a21 */; + + (void)((std::string_view)(nullptr)) /* a22 */; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((std::string_view){}) /* a22 */; + + (void)((std::string_view){nullptr}) /* a23 */; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((std::string_view){}) /* a23 */; + + (void)((std::string_view){(nullptr)}) /* a24 */; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((std::string_view){}) /* a24 */; + + (void)((std::string_view){{nullptr}}) /* a25 */; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((std::string_view){}) /* a25 */; + + (void)((std::string_view){{(nullptr)}}) /* a26 */; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((std::string_view){}) /* a26 */; + + (void)((std::string_view){{}}) /* a27 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((std::string_view){}) /* a27 */; + + (void)((const std::string_view) nullptr) /* a28 */; + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((const std::string_view) {}) /* a28 */; + + (void)((const std::string_view)(nullptr)) /* a29 */; + // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((const std::string_view){}) /* a29 */; + + (void)((const std::string_view){nullptr}) /* a30 */; + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((const std::string_view){}) /* a30 */; + + (void)((const std::string_view){(nullptr)}) /* a31 */; + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((const std::string_view){}) /* a31 */; + + (void)((const std::string_view){{nullptr}}) /* a32 */; + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((const std::string_view){}) /* a32 */; + + (void)((const std::string_view){{(nullptr)}}) /* a33 */; + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((const std::string_view){}) /* a33 */; + + (void)((const std::string_view){{}}) /* a34 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)((const std::string_view){}) /* a34 */; + } + + // Static Cast + { + (void)(static_cast<std::string_view>(nullptr)) /* a35 */; + // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(static_cast<std::string_view>("")) /* a35 */; + + (void)(static_cast<std::string_view>((nullptr))) /* a36 */; + // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(static_cast<std::string_view>("")) /* a36 */; + + // (void)(static_cast<std::string_view>({nullptr})) /* a37 */; + // Braced initializer list does not compile in this context + + // (void)(static_cast<std::string_view>({(nullptr)})) /* a38 */; + // Braced initializer list does not compile in this context + + // (void)(static_cast<std::string_view>({})) /* a39 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(static_cast<const std::string_view>(nullptr)) /* a40 */; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(static_cast<const std::string_view>("")) /* a40 */; + + (void)(static_cast<const std::string_view>((nullptr))) /* a41 */; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(static_cast<const std::string_view>("")) /* a41 */; + + // (void)(static_cast<const std::string_view>({nullptr})) /* a42 */; + // Braced initializer list does not compile in this context + + // (void)(static_cast<const std::string_view>({(nullptr)})) /* a43 */; + // Braced initializer list does not compile in this context + + // (void)(static_cast<const std::string_view>({})) /* a44 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } +} + +void stack_construction() /* b */ { + // Copy Initialization + { + std::string_view b1 = nullptr; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b1 = {}; + + std::string_view b2 = (nullptr); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b2 = {}; + + const std::string_view b3 = nullptr; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b3 = {}; + + const std::string_view b4 = (nullptr); + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b4 = {}; + } + + // Copy List Initialization + { + std::string_view b5 = {nullptr}; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b5 = {}; + + std::string_view b6 = {(nullptr)}; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b6 = {}; + + std::string_view b7 = {{nullptr}}; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b7 = {}; + + std::string_view b8 = {{(nullptr)}}; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b8 = {}; + + std::string_view b9 = {{}}; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b9 = {}; + + const std::string_view b10 = {nullptr}; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b10 = {}; + + const std::string_view b11 = {(nullptr)}; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b11 = {}; + + const std::string_view b12 = {{nullptr}}; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b12 = {}; + + const std::string_view b13 = {{(nullptr)}}; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b13 = {}; + + const std::string_view b14 = {{}}; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b14 = {}; + } + + // Direct Initialization + { + std::string_view b15(nullptr); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b15; + + std::string_view b16((nullptr)); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b16; + + std::string_view b17({nullptr}); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b17; + + std::string_view b18({(nullptr)}); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b18; + + std::string_view b19({}); // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b19; + + const std::string_view b20(nullptr); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b20; + + const std::string_view b21((nullptr)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b21; + + const std::string_view b22({nullptr}); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b22; + + const std::string_view b23({(nullptr)}); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b23; + + const std::string_view b24({}); // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b24; + } + + // Direct List Initialization + { + std::string_view b25{nullptr}; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b25{}; + + std::string_view b26{(nullptr)}; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b26{}; + + std::string_view b27{{nullptr}}; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b27{}; + + std::string_view b28{{(nullptr)}}; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b28{}; + + std::string_view b29{{}}; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view b29{}; + + const std::string_view b30{nullptr}; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b30{}; + + const std::string_view b31{(nullptr)}; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b31{}; + + const std::string_view b32{{nullptr}}; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b32{}; + + const std::string_view b33{{(nullptr)}}; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b33{}; + + const std::string_view b34{{}}; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view b34{}; + } +} + +void field_construction() /* c */ { + struct DefaultMemberInitializers { + void CopyInitialization(); + + std::string_view c1 = nullptr; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c1 = {}; + + std::string_view c2 = (nullptr); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c2 = {}; + + const std::string_view c3 = nullptr; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c3 = {}; + + const std::string_view c4 = (nullptr); + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c4 = {}; + + void CopyListInitialization(); + + std::string_view c5 = {nullptr}; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c5 = {}; + + std::string_view c6 = {(nullptr)}; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c6 = {}; + + std::string_view c7 = {{nullptr}}; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c7 = {}; + + std::string_view c8 = {{(nullptr)}}; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c8 = {}; + + std::string_view c9 = {{}}; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c9 = {}; + + const std::string_view c10 = {nullptr}; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c10 = {}; + + const std::string_view c11 = {(nullptr)}; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c11 = {}; + + const std::string_view c12 = {{nullptr}}; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c12 = {}; + + const std::string_view c13 = {{(nullptr)}}; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c13 = {}; + + const std::string_view c14 = {{}}; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c14 = {}; + + void DirectListInitialization(); + + std::string_view c15{nullptr}; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c15{}; + + std::string_view c16{(nullptr)}; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c16{}; + + std::string_view c17{{nullptr}}; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c17{}; + + std::string_view c18{{(nullptr)}}; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c18{}; + + std::string_view c19{{}}; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} std::string_view c19{}; + + const std::string_view c20{nullptr}; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c20{}; + + const std::string_view c21{(nullptr)}; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c21{}; + + const std::string_view c22{{nullptr}}; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c22{}; + + const std::string_view c23{{(nullptr)}}; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c23{}; + + const std::string_view c24{{}}; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} const std::string_view c24{}; + }; + + class ConstructorInitializers { + ConstructorInitializers() + : direct_initialization(), + + c25(nullptr), + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c25(), + + c26((nullptr)), + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c26(), + + c27({nullptr}), + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c27(), + + c28({(nullptr)}), + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c28(), + + c29({}), // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c29(), + + direct_list_initialization(), + + c30{nullptr}, + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c30{}, + + c31{(nullptr)}, + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c31{}, + + c32{{nullptr}}, + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c32{}, + + c33{{(nullptr)}}, + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c33{}, + + c34{{}}, // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} c34{}, + + end_of_list() {} + + std::nullptr_t direct_initialization; + std::string_view c25; + std::string_view c26; + std::string_view c27; + std::string_view c28; + std::string_view c29; + std::nullptr_t direct_list_initialization; + std::string_view c30; + std::string_view c31; + std::string_view c32; + std::string_view c33; + std::string_view c34; + std::nullptr_t end_of_list; + }; +} + +void default_argument_construction() /* d */ { + // Copy Initialization + { + void d1(std::string_view sv = nullptr); + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d1(std::string_view sv = {}); + + void d2(std::string_view sv = (nullptr)); + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d2(std::string_view sv = {}); + + void d3(const std::string_view sv = nullptr); + // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d3(const std::string_view sv = {}); + + void d4(const std::string_view sv = (nullptr)); + // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d4(const std::string_view sv = {}); + } + + // Copy List Initialization + { + void d5(std::string_view sv = {nullptr}); + // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d5(std::string_view sv = {}); + + void d6(std::string_view sv = {(nullptr)}); + // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d6(std::string_view sv = {}); + + void d7(std::string_view sv = {{nullptr}}); + // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d7(std::string_view sv = {}); + + void d8(std::string_view sv = {{(nullptr)}}); + // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d8(std::string_view sv = {}); + + void d9(std::string_view sv = {{}}); // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d9(std::string_view sv = {}); + + void d10(const std::string_view sv = {nullptr}); + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d10(const std::string_view sv = {}); + + void d11(const std::string_view sv = {(nullptr)}); + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d11(const std::string_view sv = {}); + + void d12(const std::string_view sv = {{nullptr}}); + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d12(const std::string_view sv = {}); + + void d13(const std::string_view sv = {{(nullptr)}}); + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d13(const std::string_view sv = {}); + + void d14(const std::string_view sv = {{}}); // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} void d14(const std::string_view sv = {}); + } +} + +void heap_construction() /* e */ { + // Direct Initialization + { + (void)(new std::string_view(nullptr)) /* e1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view()) /* e1 */; + + (void)(new std::string_view((nullptr))) /* e2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view()) /* e2 */; + + (void)(new std::string_view({nullptr})) /* e3 */; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view()) /* e3 */; + + (void)(new std::string_view({(nullptr)})) /* e4 */; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view()) /* e4 */; + + (void)(new std::string_view({})) /* e5 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view()) /* e5 */; + + (void)(new const std::string_view(nullptr)) /* e6 */; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view()) /* e6 */; + + (void)(new const std::string_view((nullptr))) /* e7 */; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view()) /* e7 */; + + (void)(new const std::string_view({nullptr})) /* e8 */; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view()) /* e8 */; + + (void)(new const std::string_view({(nullptr)})) /* e9 */; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view()) /* e9 */; + + (void)(new const std::string_view({})) /* e10 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view()) /* e10 */; + } + + // Direct List Initialization + { + (void)(new std::string_view{nullptr}) /* e11 */; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view{}) /* e11 */; + + (void)(new std::string_view{(nullptr)}) /* e12 */; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view{}) /* e12 */; + + (void)(new std::string_view{{nullptr}}) /* e13 */; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view{}) /* e13 */; + + (void)(new std::string_view{{(nullptr)}}) /* e14 */; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view{}) /* e14 */; + + (void)(new std::string_view{{}}) /* e15 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new std::string_view{}) /* e15 */; + + (void)(new const std::string_view{nullptr}) /* e16 */; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view{}) /* e16 */; + + (void)(new const std::string_view{(nullptr)}) /* e17 */; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view{}) /* e17 */; + + (void)(new const std::string_view{{nullptr}}) /* e18 */; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view{}) /* e18 */; + + (void)(new const std::string_view{{(nullptr)}}) /* e19 */; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view{}) /* e19 */; + + (void)(new const std::string_view{{}}) /* e20 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} (void)(new const std::string_view{}) /* e20 */; + } +} + +void function_invocation() /* f */ { + // Single Argument + { + function(nullptr) /* f1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}) /* f1 */; + + function((nullptr)) /* f2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}) /* f2 */; + + function({nullptr}) /* f3 */; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}) /* f3 */; + + function({(nullptr)}) /* f4 */; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}) /* f4 */; + + function({{}}) /* f5 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}) /* f5 */; + } + + // Multiple Argument + { + function(nullptr, nullptr) /* f6 */; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: constructing{{.*}}default + // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}, {}) /* f6 */; + + function((nullptr), (nullptr)) /* f7 */; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: constructing{{.*}}default + // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}, {}) /* f7 */; + + function({nullptr}, {nullptr}) /* f8 */; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}, {}) /* f8 */; + + function({(nullptr)}, {(nullptr)}) /* f9 */; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}, {}) /* f9 */; + + function({{}}, {{}}) /* f10 */; // Default `const CharT*`s + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: constructing{{.*}}default + // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: constructing{{.*}}default + // CHECK-FIXES: {{^}} function({}, {}) /* f10 */; + } +} + +void assignment(std::string_view sv) /* g */ { + sv = nullptr /* g1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: assignment to basic_string_view from null is undefined; replace with the default constructor + // CHECK-FIXES: {{^}} sv = {} /* g1 */; + + sv = (nullptr) /* g2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} sv = {} /* g2 */; + + sv = {nullptr} /* g3 */; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} sv = {} /* g3 */; + + sv = {(nullptr)} /* g4 */; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} sv = {} /* g4 */; + + sv = {{}} /* g5 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} sv = {} /* g5 */; +} + +void pointer_assignment(std::string_view *sv_ptr) /* h */ { + *sv_ptr = nullptr /* h1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} *sv_ptr = {} /* h1 */; + + *sv_ptr = (nullptr) /* h2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} *sv_ptr = {} /* h2 */; + + *sv_ptr = {nullptr} /* h3 */; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} *sv_ptr = {} /* h3 */; + + *sv_ptr = {(nullptr)} /* h4 */; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} *sv_ptr = {} /* h4 */; + + *sv_ptr = {{}} /* h5 */; // Default `const CharT*` + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: assignment{{.*}}default + // CHECK-FIXES: {{^}} *sv_ptr = {} /* h5 */; +} + +void lesser_comparison(std::string_view sv) /* i */ { + // Without Equality + { + (void)(sv < nullptr) /* i1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: comparing basic_string_view to null is undefined; replace with the empty string + // CHECK-FIXES: {{^}} (void)(sv < "") /* i1 */; + + (void)(sv < (nullptr)) /* i2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(sv < "") /* i2 */; + + // (void)(sv < {nullptr}) /* i3 */; + // Braced initializer list does not compile in this context + + // (void)(sv < {(nullptr)}) /* i4 */; + // Braced initializer list does not compile in this context + + // (void)(sv < {{}}) /* i5 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr < sv) /* i6 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" < sv) /* i6 */; + + (void)((nullptr) < sv) /* i7 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" < sv) /* i7 */; + + // (void)({nullptr} < sv) /* i8 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} < sv) /* i9 */; + // Braced initializer list does not compile in this context + + // (void)({{}} < sv) /* i10 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // With Equality + { + (void)(sv <= nullptr) /* i11 */; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(sv <= "") /* i11 */; + + (void)(sv <= (nullptr)) /* i12 */; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(sv <= "") /* i12 */; + + // (void)(sv <= {nullptr}) /* i13 */; + // Braced initializer list does not compile in this context + + // (void)(sv <= {(nullptr)}) /* i14 */; + // Braced initializer list does not compile in this context + + // (void)(sv <= {{}}) /* i15 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr <= sv) /* i16 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" <= sv) /* i16 */; + + (void)((nullptr) <= sv) /* i17 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" <= sv) /* i17 */; + + // (void)({nullptr} <= sv) /* i18 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} <= sv) /* i19 */; + // Braced initializer list does not compile in this context + + // (void)({{}} <= sv) /* i20 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } +} + +void pointer_lesser_comparison(std::string_view *sv_ptr) /* j */ { + // Without Equality + { + (void)(*sv_ptr < nullptr) /* j1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(*sv_ptr < "") /* j1 */; + + (void)(*sv_ptr < (nullptr)) /* j2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(*sv_ptr < "") /* j2 */; + + // (void)(*sv_ptr < {nullptr}) /* j3 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr < {(nullptr)}) /* j4 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr < {{}}) /* j5 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr < *sv_ptr) /* j6 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" < *sv_ptr) /* j6 */; + + (void)((nullptr) < *sv_ptr) /* j7 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" < *sv_ptr) /* j7 */; + + // (void)({nullptr} < *sv_ptr) /* j8 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} < *sv_ptr) /* j9 */; + // Braced initializer list does not compile in this context + + // (void)({{}} < *sv_ptr) /* j10 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // With Equality + { + (void)(*sv_ptr <= nullptr) /* j11 */; + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(*sv_ptr <= "") /* j11 */; + + (void)(*sv_ptr <= (nullptr)) /* j12 */; + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(*sv_ptr <= "") /* j12 */; + + // (void)(*sv_ptr <= {nullptr}) /* j13 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr <= {(nullptr)}) /* j14 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr <= {{}}) /* j15 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr <= *sv_ptr) /* j16 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" <= *sv_ptr) /* j16 */; + + (void)((nullptr) <= *sv_ptr) /* j17 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" <= *sv_ptr) /* j17 */; + + // (void)({nullptr} <= *sv_ptr) /* j18 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} <= *sv_ptr) /* j19 */; + // Braced initializer list does not compile in this context + + // (void)({{}} <= *sv_ptr) /* j20 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } +} + +void greater_comparison(std::string_view sv) /* k */ { + // Without Equality + { + (void)(sv > nullptr) /* k1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(sv > "") /* k1 */; + + (void)(sv > (nullptr)) /* k2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(sv > "") /* k2 */; + + // (void)(sv > {nullptr}) /* k3 */; + // Braced initializer list does not compile in this context + + // (void)(sv > {(nullptr)}) /* k4 */; + // Braced initializer list does not compile in this context + + // (void)(sv > {{}}) /* k5 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr > sv) /* k6 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" > sv) /* k6 */; + + (void)((nullptr) > sv) /* k7 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" > sv) /* k7 */; + + // (void)({nullptr} > sv) /* k8 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} > sv) /* k9 */; + // Braced initializer list does not compile in this context + + // (void)({{}} > sv) /* k10 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // With Equality + { + (void)(sv >= nullptr) /* k11 */; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(sv >= "") /* k11 */; + + (void)(sv >= (nullptr)) /* k12 */; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(sv >= "") /* k12 */; + + // (void)(sv >= {nullptr}) /* k13 */; + // Braced initializer list does not compile in this context + + // (void)(sv >= {(nullptr)}) /* k14 */; + // Braced initializer list does not compile in this context + + // (void)(sv >= {{}}) /* k15 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr >= sv) /* k16 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" >= sv) /* k16 */; + + (void)((nullptr) >= sv) /* k17 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" >= sv) /* k17 */; + + // (void)({nullptr} >= sv) /* k18 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} >= sv) /* k19 */; + // Braced initializer list does not compile in this context + + // (void)({{}} >= sv) /* k20 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } +} + +void pointer_greater_comparison(std::string_view *sv_ptr) /* l */ { + // Without Equality + { + (void)(*sv_ptr > nullptr) /* l1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(*sv_ptr > "") /* l1 */; + + (void)(*sv_ptr > (nullptr)) /* l2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(*sv_ptr > "") /* l2 */; + + // (void)(*sv_ptr > {nullptr}) /* l3 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr > {(nullptr)}) /* l4 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr > {{}}) /* l5 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr > *sv_ptr) /* l6 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" > *sv_ptr) /* l6 */; + + (void)((nullptr) > *sv_ptr) /* l7 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" > *sv_ptr) /* l7 */; + + // (void)({nullptr} > *sv_ptr) /* l8 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} > *sv_ptr) /* l9 */; + // Braced initializer list does not compile in this context + + // (void)({{}} > *sv_ptr) /* l10 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // With Equality + { + (void)(*sv_ptr >= nullptr) /* l11 */; + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(*sv_ptr >= "") /* l11 */; + + (void)(*sv_ptr >= (nullptr)) /* l12 */; + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)(*sv_ptr >= "") /* l12 */; + + // (void)(*sv_ptr >= {nullptr}) /* l13 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr >= {(nullptr)}) /* l14 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr >= {{}}) /* l15 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr >= *sv_ptr) /* l16 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" >= *sv_ptr) /* l16 */; + + (void)((nullptr) >= *sv_ptr) /* l17 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}empty string + // CHECK-FIXES: {{^}} (void)("" >= *sv_ptr) /* l17 */; + + // (void)({nullptr} >= *sv_ptr) /* l18 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} >= *sv_ptr) /* l19 */; + // Braced initializer list does not compile in this context + + // (void)({{}} >= *sv_ptr) /* l20 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } +} + +void equality_comparison(std::string_view sv) /* m */ { + // Empty Without Parens + { + (void)(sv == nullptr) /* m1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing basic_string_view to null is undefined; replace with the emptiness query + // CHECK-FIXES: {{^}} (void)(sv.empty()) /* m1 */; + + (void)(sv == (nullptr)) /* m2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv.empty()) /* m2 */; + + // (void)(sv == {nullptr}) /* m3 */; + // Braced initializer list does not compile in this context + + // (void)(sv == {(nullptr)}) /* m4 */; + // Braced initializer list does not compile in this context + + // (void)(sv == {{}}) /* m5 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr == sv) /* m6 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv.empty()) /* m6 */; + + (void)((nullptr) == sv) /* m7 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv.empty()) /* m7 */; + + // (void)({nullptr} == sv) /* m8 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} == sv) /* m9 */; + // Braced initializer list does not compile in this context + + // (void)({{}} == sv) /* m10 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // Empty With Parens + { + (void)((sv) == nullptr) /* m11 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing basic_string_view to null is undefined; replace with the emptiness query + // CHECK-FIXES: {{^}} (void)(sv.empty()) /* m11 */; + + (void)((sv) == (nullptr)) /* m12 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv.empty()) /* m12 */; + + // (void)((sv) == {nullptr}) /* m13 */; + // Braced initializer list does not compile in this context + + // (void)((sv) == {(nullptr)}) /* m14 */; + // Braced initializer list does not compile in this context + + // (void)((sv) == {{}}) /* m15 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr == (sv)) /* m16 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv.empty()) /* m16 */; + + (void)((nullptr) == (sv)) /* m17 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv.empty()) /* m17 */; + + // (void)({nullptr} == (sv)) /* m18 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} == (sv)) /* m19 */; + // Braced initializer list does not compile in this context + + // (void)({{}} == (sv)) /* m20 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // Non-Empty Without Parens + { + (void)((sv) != nullptr) /* m21 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv.empty()) /* m21 */; + + (void)((sv) != (nullptr)) /* m22 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv.empty()) /* m22 */; + + // (void)((sv) != {nullptr}) /* m23 */; + // Braced initializer list does not compile in this context + + // (void)((sv) != {(nullptr)}) /* m24 */; + // Braced initializer list does not compile in this context + + // (void)((sv) != {{}}) /* m25 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr != (sv)) /* m26 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv.empty()) /* m26 */; + + (void)((nullptr) != (sv)) /* m27 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv.empty()) /* m27 */; + + // (void)({nullptr} != (sv)) /* m28 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} != (sv)) /* m29 */; + // Braced initializer list does not compile in this context + + // (void)({{}} != (sv)) /* m30 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // Non-Empty With Parens + { + (void)((sv) != nullptr) /* m31 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv.empty()) /* m31 */; + + (void)((sv) != (nullptr)) /* m32 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv.empty()) /* m32 */; + + // (void)((sv) != {nullptr}) /* m33 */; + // Braced initializer list does not compile in this context + + // (void)((sv) != {(nullptr)}) /* m34 */; + // Braced initializer list does not compile in this context + + // (void)((sv) != {{}}) /* m35 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr != (sv)) /* m36 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv.empty()) /* m36 */; + + (void)((nullptr) != (sv)) /* m37 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv.empty()) /* m37 */; + + // (void)({nullptr} != (sv)) /* m38 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} != (sv)) /* m39 */; + // Braced initializer list does not compile in this context + + // (void)({{}} != (sv)) /* m40 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } +} + +void pointer_equality_comparison(std::string_view *sv_ptr) /* n */ { + // Empty Without Parens + { + (void)(*sv_ptr == nullptr) /* n1 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv_ptr->empty()) /* n1 */; + + (void)(*sv_ptr == (nullptr)) /* n2 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv_ptr->empty()) /* n2 */; + + // (void)(*sv_ptr == {nullptr}) /* n3 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr == {(nullptr)}) /* n4 */; + // Braced initializer list does not compile in this context + + // (void)(*sv_ptr == {{}}) /* n5 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr == *sv_ptr) /* n6 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv_ptr->empty()) /* n6 */; + + (void)((nullptr) == *sv_ptr) /* n7 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv_ptr->empty()) /* n7 */; + + // (void)({nullptr} == *sv_ptr) /* n8 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} == *sv_ptr) /* n9 */; + // Braced initializer list does not compile in this context + + // (void)({{}} == *sv_ptr) /* n10 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // Empty With Parens + { + (void)((*sv_ptr) == nullptr) /* n11 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv_ptr->empty()) /* n11 */; + + (void)((*sv_ptr) == (nullptr)) /* n12 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv_ptr->empty()) /* n12 */; + + // (void)((*sv_ptr) == {nullptr}) /* n13 */; + // Braced initializer list does not compile in this context + + // (void)((*sv_ptr) == {(nullptr)}) /* n14 */; + // Braced initializer list does not compile in this context + + // (void)((*sv_ptr) == {{}}) /* n15 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr == (*sv_ptr)) /* n16 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv_ptr->empty()) /* n16 */; + + (void)((nullptr) == (*sv_ptr)) /* n17 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(sv_ptr->empty()) /* n17 */; + + // (void)({nullptr} == (*sv_ptr)) /* n18 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} == (*sv_ptr)) /* n19 */; + // Braced initializer list does not compile in this context + + // (void)({{}} == (*sv_ptr)) /* n20 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // Non-Empty With Parens + { + (void)((*sv_ptr) != nullptr) /* n21 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv_ptr->empty()) /* n21 */; + + (void)((*sv_ptr) != (nullptr)) /* n22 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv_ptr->empty()) /* n22 */; + + // (void)((*sv_ptr) != {nullptr}) /* n23 */; + // Braced initializer list does not compile in this context + + // (void)((*sv_ptr) != {(nullptr)}) /* n24 */; + // Braced initializer list does not compile in this context + + // (void)((*sv_ptr) != {{}}) /* n25 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr != (*sv_ptr)) /* n26 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv_ptr->empty()) /* n26 */; + + (void)((nullptr) != (*sv_ptr)) /* n27 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv_ptr->empty()) /* n27 */; + + // (void)({nullptr} != (*sv_ptr)) /* n28 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} != (*sv_ptr)) /* n29 */; + // Braced initializer list does not compile in this context + + // (void)({{}} != (*sv_ptr)) /* n30 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } + + // Non-Empty Without Parens + { + (void)((*sv_ptr) != nullptr) /* n31 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv_ptr->empty()) /* n31 */; + + (void)((*sv_ptr) != (nullptr)) /* n32 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv_ptr->empty()) /* n32 */; + + // (void)((*sv_ptr) != {nullptr}) /* n33 */; + // Braced initializer list does not compile in this context + + // (void)((*sv_ptr) != {(nullptr)}) /* n34 */; + // Braced initializer list does not compile in this context + + // (void)((*sv_ptr) != {{}}) /* n35 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + + (void)(nullptr != (*sv_ptr)) /* n36 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv_ptr->empty()) /* n36 */; + + (void)((nullptr) != (*sv_ptr)) /* n37 */; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: comparing{{.*}}emptiness query + // CHECK-FIXES: {{^}} (void)(!sv_ptr->empty()) /* n37 */; + + // (void)({nullptr} != (*sv_ptr)) /* n38 */; + // Braced initializer list does not compile in this context + + // (void)({(nullptr)} != (*sv_ptr)) /* n39 */; + // Braced initializer list does not compile in this context + + // (void)({{}} != (*sv_ptr)) /* n40 */; // Default `const CharT*` + // Braced initializer list does not compile in this context + } +} Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -92,6 +92,7 @@ `bugprone-string-constructor <bugprone-string-constructor.html>`_, "Yes" `bugprone-string-integer-assignment <bugprone-string-integer-assignment.html>`_, "Yes" `bugprone-string-literal-with-embedded-nul <bugprone-string-literal-with-embedded-nul.html>`_, + `bugprone-stringview-nullptr <bugprone-stringview-nullptr.html>`_, "Yes" `bugprone-suspicious-enum-usage <bugprone-suspicious-enum-usage.html>`_, `bugprone-suspicious-include <bugprone-suspicious-include.html>`_, `bugprone-suspicious-memory-comparison <bugprone-suspicious-memory-comparison.html>`_, Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-stringview-nullptr.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-stringview-nullptr.rst @@ -0,0 +1,63 @@ +.. title:: clang-tidy - bugprone-stringview-nullptr + +bugprone-stringview-nullptr +=========================== +Checks for various ways that the ``const CharT*`` constructor of +``std::basic_string_view`` can be passed a null argument and replaces them +with the default constructor in most cases. For the comparison operators, +braced initializer list does not compile so instead a call to ``.empty()`` +or the empty string literal are used, where appropriate. + +This prevents code from invoking behavior which is unconditionally undefined. +The single-argument ``const CharT*`` constructor does not check for the null +case before dereferencing its input. The standard is slated to add an +explicitly-deleted overload to catch some of these cases: wg21.link/p2166 + +.. code-block:: c++ + + std::string_view sv = nullptr; + + sv = nullptr; + + bool is_empty = sv == nullptr; + bool isnt_empty = sv != nullptr; + + accepts_sv(nullptr); + + accepts_sv({{}}); // A + + accepts_sv({nullptr, 0}); // B + +is translated into... + +.. code-block:: c++ + + std::string_view sv = {}; + + sv = {}; + + bool is_empty = sv.empty(); + bool isnt_empty = !sv.empty(); + + accepts_sv({}); + + accepts_sv({}); // A + + accepts_sv({nullptr, 0}); // B + +.. note:: + + The source pattern with trailing comment "A" selects the ``(const CharT*)`` + constructor overload and then value-initializes the pointer, causing a null + dereference. It happens to not include the ``nullptr`` literal, but it is + still within the scope of this ClangTidy check. + + To catch the additional cases of ``NULL`` (which expands to ``__null``) and + ``0``, first run the ``modernize-use-nullptr`` check to convert the callers + to ``nullptr``. + +.. note:: + + The source pattern with trailing comment "B" selects the + ``(const CharT*, size_type)`` constructor which is perfectly valid, since the + length argument is ``0``. It is not changed by this ClangTidy check. \ No newline at end of file Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -76,6 +76,12 @@ New checks ^^^^^^^^^^ +- New :doc:`bugprone-stringview-nullptr + <clang-tidy/checks/bugprone-stringview-nullptr>` check. + + Checks for various ways that the ``const CharT*`` constructor of + ``std::basic_string_view`` can be passed a null argument. + - New :doc:`abseil-cleanup-ctad <clang-tidy/checks/abseil-cleanup-ctad>` check. Index: clang-tools-extra/clang-tidy/bugprone/StringviewNullptrCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/StringviewNullptrCheck.h @@ -0,0 +1,44 @@ +//===--- StringviewNullptrCheck.h - clang-tidy ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGVIEWNULLPTRCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGVIEWNULLPTRCHECK_H + +#include "../utils/TransformerClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Checks for various ways that the `nullptr` literal can be passed into the +/// `const CharT*` constructor of `std::basic_string_view` and replaces them +/// with the default constructor in most cases. For the comparison operators, +/// braced initializer list does not compile so instead the empty string is +/// used. Also, `==` and `!=` are replaced with calls to `.empty()`. +/// +/// This prevents code from invoking behavior which is unconditionally +/// undefined. The single-argument `const char*` constructor of +/// `std::string_view` does not check for the null case before dereferencing +/// its input. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-stringview-nullptr.html +class StringviewNullptrCheck : public utils::TransformerClangTidyCheck { +public: + StringviewNullptrCheck(StringRef Name, ClangTidyContext *Context); + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus17; + } +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGVIEWNULLPTRCHECK_H Index: clang-tools-extra/clang-tidy/bugprone/StringviewNullptrCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/StringviewNullptrCheck.cpp @@ -0,0 +1,191 @@ +//===--- StringviewNullptrCheck.cpp - clang-tidy --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "StringviewNullptrCheck.h" +#include "../utils/TransformerClangTidyCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/Transformer/RangeSelector.h" +#include "clang/Tooling/Transformer/RewriteRule.h" +#include "clang/Tooling/Transformer/Stencil.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +using namespace ::clang::ast_matchers; +using namespace ::clang::transformer; + +namespace { +AST_MATCHER_P(InitListExpr, initCountIs, unsigned, N) { + return Node.getNumInits() == N; +} +} // namespace + +RewriteRule StringviewNullptrCheckImpl() { + auto construction_warning = + cat("constructing basic_string_view from null is undefined; replace with " + "the default constructor"); + auto assignment_warning = + cat("assignment to basic_string_view from null is undefined; replace " + "with the default constructor"); + auto relative_comparison_warning = + cat("comparing basic_string_view to null is undefined; replace with the " + "empty string"); + auto equality_comparison_warning = + cat("comparing basic_string_view to null is undefined; replace with the " + "emptiness query"); + auto StringViewConstructingFromNullExpr = + cxxConstructExpr( + hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( + cxxRecordDecl(hasName("std::basic_string_view")))))), + argumentCountIs(1), + hasArgument( + 0, anyOf(ignoringParenImpCasts(cxxNullPtrLiteralExpr()), + initListExpr(initCountIs(1), + hasInit(0, ignoringParenImpCasts( + cxxNullPtrLiteralExpr()))), + initListExpr(initCountIs(0)))), + has(expr().bind("null_argument_expr"))) + .bind("construct_expr"); + + auto HandleTemporaryCXXFunctionalCastExpr = + makeRule(cxxFunctionalCastExpr( + hasSourceExpression(StringViewConstructingFromNullExpr)), + remove(node("null_argument_expr")), construction_warning); + + auto HandleTemporaryCXXTemporaryObjectExprAndCompoundLiteralExpr = + makeRule(cxxTemporaryObjectExpr(StringViewConstructingFromNullExpr), + remove(node("null_argument_expr")), construction_warning); + + auto HandleTemporaryCStyleCastExpr = makeRule( + cStyleCastExpr(hasSourceExpression(StringViewConstructingFromNullExpr)), + changeTo(node("null_argument_expr"), cat("{}")), construction_warning); + + auto HandleTemporaryCXXStaticCastExpr = makeRule( + cxxStaticCastExpr( + hasSourceExpression(StringViewConstructingFromNullExpr)), + changeTo(node("null_argument_expr"), cat("\"\"")), construction_warning); + + auto HandleStackCopyInitialization = makeRule( + varDecl(hasInitializer(implicitCastExpr( + ignoringImpCasts(StringViewConstructingFromNullExpr)))), + changeTo(node("null_argument_expr"), cat("{}")), construction_warning); + + auto HandleStackDirectInitialization = + makeRule(varDecl(hasInitializer( + cxxConstructExpr(StringViewConstructingFromNullExpr, + unless(isListInitialization())))) + .bind("var_decl"), + changeTo(node("construct_expr"), cat(name("var_decl"))), + construction_warning); + + auto HandleStackDirectListAndCopyListInitialization = makeRule( + varDecl(hasInitializer(cxxConstructExpr( + StringViewConstructingFromNullExpr, isListInitialization()))), + remove(node("null_argument_expr")), construction_warning); + + auto HandleFieldCopyInitialization = makeRule( + fieldDecl(hasInClassInitializer(implicitCastExpr( + ignoringImpCasts(StringViewConstructingFromNullExpr)))), + changeTo(node("null_argument_expr"), cat("{}")), construction_warning); + + auto HandleFieldOtherInitialization = makeRule( + fieldDecl(hasInClassInitializer(StringViewConstructingFromNullExpr)), + remove(node("null_argument_expr")), construction_warning); + + auto HandleConstructorInitialization = makeRule( + cxxCtorInitializer(withInitializer(StringViewConstructingFromNullExpr)), + remove(node("null_argument_expr")), construction_warning); + + auto HandleDefaultArgumentInitialization = makeRule( + parmVarDecl(hasInitializer(implicitCastExpr( + hasSourceExpression(StringViewConstructingFromNullExpr)))), + changeTo(node("null_argument_expr"), cat("{}")), construction_warning); + + auto HandleDefaultArgumentListInitialization = + makeRule(parmVarDecl(hasInitializer(StringViewConstructingFromNullExpr)), + remove(node("null_argument_expr")), construction_warning); + + auto HandleHeapInitialization = makeRule( + cxxNewExpr(unless(isArray()), has(StringViewConstructingFromNullExpr)), + remove(node("null_argument_expr")), construction_warning); + + auto HandleFunctionArgumentInitialization = makeRule( + implicitCastExpr(hasSourceExpression(StringViewConstructingFromNullExpr), + hasParent(callExpr(unless(cxxOperatorCallExpr())))), + changeTo(node("null_argument_expr"), cat("{}")), construction_warning); + + auto HandleFunctionArgumentListInitialization = makeRule( + cxxConstructExpr(StringViewConstructingFromNullExpr, + hasParent(callExpr(unless(cxxOperatorCallExpr())))), + remove(node("null_argument_expr")), construction_warning); + + auto HandleAssignment = makeRule( + materializeTemporaryExpr( + has(StringViewConstructingFromNullExpr), + hasParent(cxxOperatorCallExpr(hasOverloadedOperatorName("=")))), + changeTo(node("construct_expr"), cat("{}")), assignment_warning); + + auto HandleRelativeComparison = + makeRule(implicitCastExpr( + hasSourceExpression(StringViewConstructingFromNullExpr), + hasParent(cxxOperatorCallExpr( + hasAnyOverloadedOperatorName("<", "<=", ">", ">=")))), + changeTo(node("null_argument_expr"), cat("\"\"")), + relative_comparison_warning); + + auto HandleEmptyEqualityComparison = makeRule( + cxxOperatorCallExpr( + hasOverloadedOperatorName("=="), + hasOperands(traverse(clang::TK_IgnoreUnlessSpelledInSource, + expr().bind("string_view_instance")), + implicitCastExpr(hasSourceExpression( + StringViewConstructingFromNullExpr)))) + .bind("root"), + changeTo(node("root"), + cat(access("string_view_instance", cat("empty")), "()")), + equality_comparison_warning); + + auto HandleNonEmptyEqualityComparison = makeRule( + cxxOperatorCallExpr( + hasOverloadedOperatorName("!="), + hasOperands(traverse(clang::TK_IgnoreUnlessSpelledInSource, + expr().bind("string_view_instance")), + implicitCastExpr(hasSourceExpression( + StringViewConstructingFromNullExpr)))) + .bind("root"), + changeTo(node("root"), + cat("!", access("string_view_instance", cat("empty")), "()")), + equality_comparison_warning); + + return applyFirst( + {HandleTemporaryCXXFunctionalCastExpr, + HandleTemporaryCXXTemporaryObjectExprAndCompoundLiteralExpr, + HandleTemporaryCStyleCastExpr, HandleTemporaryCXXStaticCastExpr, + HandleStackCopyInitialization, HandleStackDirectInitialization, + HandleStackDirectListAndCopyListInitialization, + HandleFieldCopyInitialization, HandleFieldOtherInitialization, + HandleConstructorInitialization, HandleDefaultArgumentInitialization, + HandleDefaultArgumentListInitialization, HandleHeapInitialization, + HandleFunctionArgumentInitialization, + HandleFunctionArgumentListInitialization, HandleAssignment, + HandleRelativeComparison, HandleEmptyEqualityComparison, + HandleNonEmptyEqualityComparison}); +} + +StringviewNullptrCheck::StringviewNullptrCheck(StringRef Name, + ClangTidyContext *Context) + : utils::TransformerClangTidyCheck(StringviewNullptrCheckImpl(), Name, + Context) {} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -45,6 +45,7 @@ StringConstructorCheck.cpp StringIntegerAssignmentCheck.cpp StringLiteralWithEmbeddedNulCheck.cpp + StringviewNullptrCheck.cpp SuspiciousEnumUsageCheck.cpp SuspiciousIncludeCheck.cpp SuspiciousMemoryComparisonCheck.cpp Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -50,6 +50,7 @@ #include "StringConstructorCheck.h" #include "StringIntegerAssignmentCheck.h" #include "StringLiteralWithEmbeddedNulCheck.h" +#include "StringviewNullptrCheck.h" #include "SuspiciousEnumUsageCheck.h" #include "SuspiciousIncludeCheck.h" #include "SuspiciousMemoryComparisonCheck.h" @@ -157,6 +158,8 @@ "bugprone-string-integer-assignment"); CheckFactories.registerCheck<StringLiteralWithEmbeddedNulCheck>( "bugprone-string-literal-with-embedded-nul"); + CheckFactories.registerCheck<StringviewNullptrCheck>( + "bugprone-stringview-nullptr"); CheckFactories.registerCheck<SuspiciousEnumUsageCheck>( "bugprone-suspicious-enum-usage"); CheckFactories.registerCheck<SuspiciousIncludeCheck>(
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits