192 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			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
 |