1 //===--- StringviewNullptrCheck.cpp - clang-tidy --------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "StringviewNullptrCheck.h" 10 #include "../utils/TransformerClangTidyCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/ASTMatchers/ASTMatchers.h" 14 #include "clang/Tooling/Transformer/RangeSelector.h" 15 #include "clang/Tooling/Transformer/RewriteRule.h" 16 #include "clang/Tooling/Transformer/Stencil.h" 17 #include "llvm/ADT/StringRef.h" 18 19 namespace clang { 20 namespace tidy { 21 namespace bugprone { 22 23 using namespace ::clang::ast_matchers; 24 using namespace ::clang::transformer; 25 26 namespace { 27 AST_MATCHER_P(InitListExpr, initCountIs, unsigned, N) { 28 return Node.getNumInits() == N; 29 } 30 } // namespace 31 32 RewriteRule StringviewNullptrCheckImpl() { 33 auto construction_warning = 34 cat("constructing basic_string_view from null is undefined; replace with " 35 "the default constructor"); 36 auto assignment_warning = 37 cat("assignment to basic_string_view from null is undefined; replace " 38 "with the default constructor"); 39 auto relative_comparison_warning = 40 cat("comparing basic_string_view to null is undefined; replace with the " 41 "empty string"); 42 auto equality_comparison_warning = 43 cat("comparing basic_string_view to null is undefined; replace with the " 44 "emptiness query"); 45 auto StringViewConstructingFromNullExpr = 46 cxxConstructExpr( 47 hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( 48 cxxRecordDecl(hasName("::std::basic_string_view")))))), 49 argumentCountIs(1), 50 hasArgument( 51 0, anyOf(ignoringParenImpCasts(cxxNullPtrLiteralExpr()), 52 initListExpr(initCountIs(1), 53 hasInit(0, ignoringParenImpCasts( 54 cxxNullPtrLiteralExpr()))), 55 initListExpr(initCountIs(0)))), 56 has(expr().bind("null_argument_expr"))) 57 .bind("construct_expr"); 58 59 auto HandleTemporaryCXXFunctionalCastExpr = 60 makeRule(cxxFunctionalCastExpr( 61 hasSourceExpression(StringViewConstructingFromNullExpr)), 62 remove(node("null_argument_expr")), construction_warning); 63 64 auto HandleTemporaryCXXTemporaryObjectExprAndCompoundLiteralExpr = 65 makeRule(cxxTemporaryObjectExpr(StringViewConstructingFromNullExpr), 66 remove(node("null_argument_expr")), construction_warning); 67 68 auto HandleTemporaryCStyleCastExpr = makeRule( 69 cStyleCastExpr(hasSourceExpression(StringViewConstructingFromNullExpr)), 70 changeTo(node("null_argument_expr"), cat("{}")), construction_warning); 71 72 auto HandleTemporaryCXXStaticCastExpr = makeRule( 73 cxxStaticCastExpr( 74 hasSourceExpression(StringViewConstructingFromNullExpr)), 75 changeTo(node("null_argument_expr"), cat("\"\"")), construction_warning); 76 77 auto HandleStackCopyInitialization = makeRule( 78 varDecl(hasInitializer(implicitCastExpr( 79 ignoringImpCasts(StringViewConstructingFromNullExpr)))), 80 changeTo(node("null_argument_expr"), cat("{}")), construction_warning); 81 82 auto HandleStackDirectInitialization = 83 makeRule(varDecl(hasInitializer( 84 cxxConstructExpr(StringViewConstructingFromNullExpr, 85 unless(isListInitialization())))) 86 .bind("var_decl"), 87 changeTo(node("construct_expr"), cat(name("var_decl"))), 88 construction_warning); 89 90 auto HandleStackDirectListAndCopyListInitialization = makeRule( 91 varDecl(hasInitializer(cxxConstructExpr( 92 StringViewConstructingFromNullExpr, isListInitialization()))), 93 remove(node("null_argument_expr")), construction_warning); 94 95 auto HandleFieldCopyInitialization = makeRule( 96 fieldDecl(hasInClassInitializer(implicitCastExpr( 97 ignoringImpCasts(StringViewConstructingFromNullExpr)))), 98 changeTo(node("null_argument_expr"), cat("{}")), construction_warning); 99 100 auto HandleFieldOtherInitialization = makeRule( 101 fieldDecl(hasInClassInitializer(StringViewConstructingFromNullExpr)), 102 remove(node("null_argument_expr")), construction_warning); 103 104 auto HandleConstructorInitialization = makeRule( 105 cxxCtorInitializer(withInitializer(StringViewConstructingFromNullExpr)), 106 remove(node("null_argument_expr")), construction_warning); 107 108 auto HandleDefaultArgumentInitialization = makeRule( 109 parmVarDecl(hasInitializer(implicitCastExpr( 110 hasSourceExpression(StringViewConstructingFromNullExpr)))), 111 changeTo(node("null_argument_expr"), cat("{}")), construction_warning); 112 113 auto HandleDefaultArgumentListInitialization = 114 makeRule(parmVarDecl(hasInitializer(StringViewConstructingFromNullExpr)), 115 remove(node("null_argument_expr")), construction_warning); 116 117 auto HandleHeapInitialization = makeRule( 118 cxxNewExpr(unless(isArray()), has(StringViewConstructingFromNullExpr)), 119 remove(node("null_argument_expr")), construction_warning); 120 121 auto HandleFunctionArgumentInitialization = makeRule( 122 implicitCastExpr(hasSourceExpression(StringViewConstructingFromNullExpr), 123 hasParent(callExpr(unless(cxxOperatorCallExpr())))), 124 changeTo(node("null_argument_expr"), cat("{}")), construction_warning); 125 126 auto HandleFunctionArgumentListInitialization = makeRule( 127 cxxConstructExpr(StringViewConstructingFromNullExpr, 128 hasParent(callExpr(unless(cxxOperatorCallExpr())))), 129 remove(node("null_argument_expr")), construction_warning); 130 131 auto HandleAssignment = makeRule( 132 materializeTemporaryExpr( 133 has(StringViewConstructingFromNullExpr), 134 hasParent(cxxOperatorCallExpr(hasOverloadedOperatorName("=")))), 135 changeTo(node("construct_expr"), cat("{}")), assignment_warning); 136 137 auto HandleRelativeComparison = 138 makeRule(implicitCastExpr( 139 hasSourceExpression(StringViewConstructingFromNullExpr), 140 hasParent(cxxOperatorCallExpr( 141 hasAnyOverloadedOperatorName("<", "<=", ">", ">=")))), 142 changeTo(node("null_argument_expr"), cat("\"\"")), 143 relative_comparison_warning); 144 145 auto HandleEmptyEqualityComparison = makeRule( 146 cxxOperatorCallExpr( 147 hasOverloadedOperatorName("=="), 148 hasOperands(traverse(clang::TK_IgnoreUnlessSpelledInSource, 149 expr().bind("string_view_instance")), 150 implicitCastExpr(hasSourceExpression( 151 StringViewConstructingFromNullExpr)))) 152 .bind("root"), 153 changeTo(node("root"), 154 cat(access("string_view_instance", cat("empty")), "()")), 155 equality_comparison_warning); 156 157 auto HandleNonEmptyEqualityComparison = makeRule( 158 cxxOperatorCallExpr( 159 hasOverloadedOperatorName("!="), 160 hasOperands(traverse(clang::TK_IgnoreUnlessSpelledInSource, 161 expr().bind("string_view_instance")), 162 implicitCastExpr(hasSourceExpression( 163 StringViewConstructingFromNullExpr)))) 164 .bind("root"), 165 changeTo(node("root"), 166 cat("!", access("string_view_instance", cat("empty")), "()")), 167 equality_comparison_warning); 168 169 return applyFirst( 170 {HandleTemporaryCXXFunctionalCastExpr, 171 HandleTemporaryCXXTemporaryObjectExprAndCompoundLiteralExpr, 172 HandleTemporaryCStyleCastExpr, HandleTemporaryCXXStaticCastExpr, 173 HandleStackCopyInitialization, HandleStackDirectInitialization, 174 HandleStackDirectListAndCopyListInitialization, 175 HandleFieldCopyInitialization, HandleFieldOtherInitialization, 176 HandleConstructorInitialization, HandleDefaultArgumentInitialization, 177 HandleDefaultArgumentListInitialization, HandleHeapInitialization, 178 HandleFunctionArgumentInitialization, 179 HandleFunctionArgumentListInitialization, HandleAssignment, 180 HandleRelativeComparison, HandleEmptyEqualityComparison, 181 HandleNonEmptyEqualityComparison}); 182 } 183 184 StringviewNullptrCheck::StringviewNullptrCheck(StringRef Name, 185 ClangTidyContext *Context) 186 : utils::TransformerClangTidyCheck(StringviewNullptrCheckImpl(), Name, 187 Context) {} 188 189 } // namespace bugprone 190 } // namespace tidy 191 } // namespace clang 192