clang-tools  10.0.0
MisplacedOperatorInStrlenInAllocCheck.cpp
Go to the documentation of this file.
1 //===--- MisplacedOperatorInStrlenInAllocCheck.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 
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 
13 using namespace clang::ast_matchers;
14 
15 namespace clang {
16 namespace tidy {
17 namespace bugprone {
18 
19 void MisplacedOperatorInStrlenInAllocCheck::registerMatchers(
20  MatchFinder *Finder) {
21  const auto StrLenFunc = functionDecl(anyOf(
22  hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"),
23  hasName("::std::strnlen"), hasName("::strnlen_s"),
24  hasName("::std::strnlen_s"), hasName("::wcslen"),
25  hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"),
26  hasName("::wcsnlen_s"), hasName("std::wcsnlen_s")));
27 
28  const auto BadUse =
29  callExpr(callee(StrLenFunc),
30  hasAnyArgument(ignoringImpCasts(
31  binaryOperator(
32  hasOperatorName("+"),
33  hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))
34  .bind("BinOp"))))
35  .bind("StrLen");
36 
37  const auto BadArg = anyOf(
38  allOf(unless(binaryOperator(
39  hasOperatorName("+"), hasLHS(BadUse),
40  hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))),
41  hasDescendant(BadUse)),
42  BadUse);
43 
44  const auto Alloc0Func =
45  functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"),
46  hasName("::alloca"), hasName("std::alloca")));
47  const auto Alloc1Func =
48  functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"),
49  hasName("::realloc"), hasName("std::realloc")));
50 
51  const auto Alloc0FuncPtr =
52  varDecl(hasType(isConstQualified()),
53  hasInitializer(ignoringParenImpCasts(
54  declRefExpr(hasDeclaration(Alloc0Func)))));
55  const auto Alloc1FuncPtr =
56  varDecl(hasType(isConstQualified()),
57  hasInitializer(ignoringParenImpCasts(
58  declRefExpr(hasDeclaration(Alloc1Func)))));
59 
60  Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))),
61  hasArgument(0, BadArg))
62  .bind("Alloc"),
63  this);
64  Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))),
65  hasArgument(1, BadArg))
66  .bind("Alloc"),
67  this);
68  Finder->addMatcher(
69  cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this);
70 }
71 
72 void MisplacedOperatorInStrlenInAllocCheck::check(
73  const MatchFinder::MatchResult &Result) {
74  const Expr *Alloc = Result.Nodes.getNodeAs<CallExpr>("Alloc");
75  if (!Alloc)
76  Alloc = Result.Nodes.getNodeAs<CXXNewExpr>("Alloc");
77  assert(Alloc && "Matched node bound by 'Alloc' shoud be either 'CallExpr'"
78  " or 'CXXNewExpr'");
79 
80  const auto *StrLen = Result.Nodes.getNodeAs<CallExpr>("StrLen");
81  const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("BinOp");
82 
83  const StringRef StrLenText = Lexer::getSourceText(
84  CharSourceRange::getTokenRange(StrLen->getSourceRange()),
85  *Result.SourceManager, getLangOpts());
86  const StringRef Arg0Text = Lexer::getSourceText(
87  CharSourceRange::getTokenRange(StrLen->getArg(0)->getSourceRange()),
88  *Result.SourceManager, getLangOpts());
89  const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find(Arg0Text));
90  const StringRef StrLenEnd = StrLenText.substr(
91  StrLenText.find(Arg0Text) + Arg0Text.size(), StrLenText.size());
92 
93  const StringRef LHSText = Lexer::getSourceText(
94  CharSourceRange::getTokenRange(BinOp->getLHS()->getSourceRange()),
95  *Result.SourceManager, getLangOpts());
96  const StringRef RHSText = Lexer::getSourceText(
97  CharSourceRange::getTokenRange(BinOp->getRHS()->getSourceRange()),
98  *Result.SourceManager, getLangOpts());
99 
100  auto Hint = FixItHint::CreateReplacement(
101  StrLen->getSourceRange(),
102  (StrLenBegin + LHSText + StrLenEnd + " + " + RHSText).str());
103 
104  diag(Alloc->getBeginLoc(),
105  "addition operator is applied to the argument of %0 instead of its "
106  "result")
107  << StrLen->getDirectCallee()->getName() << Hint;
108 }
109 
110 } // namespace bugprone
111 } // namespace tidy
112 } // namespace clang
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
Definition: SourceCode.cpp:227
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//