blob: 3e6f9fde1b9786c8847eeeaed99a25a15eebf6ff [file] [log] [blame]
Inna Palantff3f07a2019-07-11 16:15:26 -07001//===--- MisplacedOperatorInStrlenInAllocCheck.cpp - clang-tidy------------===//
2//
Chih-Hung Hsieh43f06942019-12-19 15:01:08 -08003// 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
Inna Palantff3f07a2019-07-11 16:15:26 -07006//
7//===----------------------------------------------------------------------===//
8
9#include "MisplacedOperatorInStrlenInAllocCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang {
16namespace tidy {
17namespace bugprone {
18
19void 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
72void 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