llvm-project/clang-tools-extra/clang-tidy/bugprone/StringviewNullptrCheck.cpp

192 lines
8.6 KiB
C++

//===--- 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