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