brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.9 KiB · 49ba3b8 Raw
528 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "SizeofExpressionCheck.h"10#include "../utils/Matchers.h"11#include "clang/AST/ASTContext.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::bugprone {17 18namespace {19 20AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N) {21  return Node.getValue().ugt(N);22}23 24AST_MATCHER_P2(Expr, hasSizeOfDescendant, int, Depth,25               ast_matchers::internal::Matcher<Expr>, InnerMatcher) {26  if (Depth < 0)27    return false;28 29  const Expr *E = Node.IgnoreParenImpCasts();30  if (InnerMatcher.matches(*E, Finder, Builder))31    return true;32 33  if (const auto *CE = dyn_cast<CastExpr>(E)) {34    const auto M = hasSizeOfDescendant(Depth - 1, InnerMatcher);35    return M.matches(*CE->getSubExpr(), Finder, Builder);36  }37  if (const auto *UE = dyn_cast<UnaryOperator>(E)) {38    const auto M = hasSizeOfDescendant(Depth - 1, InnerMatcher);39    return M.matches(*UE->getSubExpr(), Finder, Builder);40  }41  if (const auto *BE = dyn_cast<BinaryOperator>(E)) {42    const auto LHS = hasSizeOfDescendant(Depth - 1, InnerMatcher);43    const auto RHS = hasSizeOfDescendant(Depth - 1, InnerMatcher);44    return LHS.matches(*BE->getLHS(), Finder, Builder) ||45           RHS.matches(*BE->getRHS(), Finder, Builder);46  }47 48  return false;49}50 51AST_MATCHER(Expr, offsetOfExpr) { return isa<OffsetOfExpr>(Node); }52 53} // namespace54 55static CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {56  if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||57      isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())58    return CharUnits::Zero();59  return Ctx.getTypeSizeInChars(Ty);60}61 62SizeofExpressionCheck::SizeofExpressionCheck(StringRef Name,63                                             ClangTidyContext *Context)64    : ClangTidyCheck(Name, Context),65      WarnOnSizeOfConstant(Options.get("WarnOnSizeOfConstant", true)),66      WarnOnSizeOfIntegerExpression(67          Options.get("WarnOnSizeOfIntegerExpression", false)),68      WarnOnSizeOfThis(Options.get("WarnOnSizeOfThis", true)),69      WarnOnSizeOfCompareToConstant(70          Options.get("WarnOnSizeOfCompareToConstant", true)),71      WarnOnSizeOfPointerToAggregate(72          Options.get("WarnOnSizeOfPointerToAggregate", true)),73      WarnOnSizeOfPointer(Options.get("WarnOnSizeOfPointer", false)),74      WarnOnOffsetDividedBySizeOf(75          Options.get("WarnOnOffsetDividedBySizeOf", true)),76      WarnOnSizeOfInLoopTermination(77          Options.get("WarnOnSizeOfInLoopTermination", true)) {}78 79void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {80  Options.store(Opts, "WarnOnSizeOfConstant", WarnOnSizeOfConstant);81  Options.store(Opts, "WarnOnSizeOfIntegerExpression",82                WarnOnSizeOfIntegerExpression);83  Options.store(Opts, "WarnOnSizeOfThis", WarnOnSizeOfThis);84  Options.store(Opts, "WarnOnSizeOfCompareToConstant",85                WarnOnSizeOfCompareToConstant);86  Options.store(Opts, "WarnOnSizeOfPointerToAggregate",87                WarnOnSizeOfPointerToAggregate);88  Options.store(Opts, "WarnOnSizeOfPointer", WarnOnSizeOfPointer);89  Options.store(Opts, "WarnOnOffsetDividedBySizeOf",90                WarnOnOffsetDividedBySizeOf);91  Options.store(Opts, "WarnOnSizeOfInLoopTermination",92                WarnOnSizeOfInLoopTermination);93}94 95void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {96  // FIXME:97  // Some of the checks should not match in template code to avoid false98  // positives if sizeof is applied on template argument.99 100  auto LoopCondExpr =101      [](const ast_matchers::internal::Matcher<Stmt> &InnerMatcher) {102        return stmt(anyOf(forStmt(hasCondition(InnerMatcher)),103                          whileStmt(hasCondition(InnerMatcher)),104                          doStmt(hasCondition(InnerMatcher))));105      };106 107  const auto IntegerExpr = ignoringParenImpCasts(integerLiteral());108  const auto ConstantExpr = ignoringParenImpCasts(109      anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(IntegerExpr)),110            binaryOperator(hasLHS(IntegerExpr), hasRHS(IntegerExpr))));111  const auto IntegerCallExpr = ignoringParenImpCasts(callExpr(112      anyOf(hasType(isInteger()), hasType(hasCanonicalType(enumType()))),113      unless(isInTemplateInstantiation())));114  const auto SizeOfExpr = sizeOfExpr(hasArgumentOfType(115      hasUnqualifiedDesugaredType(type().bind("sizeof-arg-type"))));116  const auto SizeOfZero =117      sizeOfExpr(has(ignoringParenImpCasts(integerLiteral(equals(0)))));118 119  // Detect expression like: sizeof(ARRAYLEN);120  // Note: The expression 'sizeof(sizeof(0))' is a portable trick used to know121  //       the sizeof size_t.122  if (WarnOnSizeOfConstant) {123    Finder->addMatcher(124        expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr))),125             unless(SizeOfZero))126            .bind("sizeof-constant"),127        this);128  }129 130  // Detect sizeof(f())131  if (WarnOnSizeOfIntegerExpression) {132    Finder->addMatcher(sizeOfExpr(ignoringParenImpCasts(has(IntegerCallExpr)))133                           .bind("sizeof-integer-call"),134                       this);135  }136 137  // Detect expression like: sizeof(this);138  if (WarnOnSizeOfThis) {139    Finder->addMatcher(sizeOfExpr(has(ignoringParenImpCasts(cxxThisExpr())))140                           .bind("sizeof-this"),141                       this);142  }143 144  if (WarnOnSizeOfInLoopTermination) {145    auto CondExpr = binaryOperator(146        allOf(has(SizeOfExpr.bind("sizeof-expr")), isComparisonOperator()));147    Finder->addMatcher(LoopCondExpr(anyOf(CondExpr, hasDescendant(CondExpr)))148                           .bind("loop-expr"),149                       this);150  }151 152  // Detect sizeof(kPtr) where kPtr is 'const char* kPtr = "abc"';153  const auto CharPtrType = pointerType(pointee(isAnyCharacter()));154  const auto ConstStrLiteralDecl =155      varDecl(isDefinition(), hasType(hasCanonicalType(CharPtrType)),156              hasInitializer(ignoringParenImpCasts(stringLiteral())));157  const auto VarWithConstStrLiteralDecl = expr(158      hasType(hasCanonicalType(CharPtrType)),159      ignoringParenImpCasts(declRefExpr(hasDeclaration(ConstStrLiteralDecl))));160  Finder->addMatcher(161      sizeOfExpr(has(ignoringParenImpCasts(VarWithConstStrLiteralDecl)))162          .bind("sizeof-charp"),163      this);164 165  // Detect sizeof(ptr) where ptr is a pointer (CWE-467).166  //167  // In WarnOnSizeOfPointerToAggregate mode only report cases when ptr points168  // to an aggregate type or ptr is an expression that (implicitly or169  // explicitly) casts an array to a pointer type. (These are more suspicious170  // than other sizeof(ptr) expressions because they can appear as distorted171  // forms of the common sizeof(aggregate) expressions.)172  //173  // To avoid false positives, the check doesn't report expressions like174  // 'sizeof(pp[0])' and 'sizeof(*pp)' where `pp` is a pointer-to-pointer or175  // array of pointers. (This filters out both `sizeof(arr) / sizeof(arr[0])`176  // expressions and other cases like `p = realloc(p, newsize * sizeof(*p));`.)177  //178  // Moreover this generic message is suppressed in cases that are also matched179  // by the more concrete matchers 'sizeof-this' and 'sizeof-charp'.180  if (WarnOnSizeOfPointerToAggregate || WarnOnSizeOfPointer) {181    const auto ArrayExpr =182        ignoringParenImpCasts(hasType(hasCanonicalType(arrayType())));183    const auto ArrayCastExpr = expr(anyOf(184        unaryOperator(hasUnaryOperand(ArrayExpr), unless(hasOperatorName("*"))),185        binaryOperator(hasEitherOperand(ArrayExpr)),186        castExpr(hasSourceExpression(ArrayExpr))));187    const auto PointerToArrayExpr =188        hasType(hasCanonicalType(pointerType(pointee(arrayType()))));189 190    const auto PointerToStructType =191        hasUnqualifiedDesugaredType(pointerType(pointee(recordType())));192    const auto PointerToStructExpr =193        expr(hasType(hasCanonicalType(PointerToStructType)));194 195    const auto PointerToDetectedExpr =196        WarnOnSizeOfPointer197            ? expr(hasType(hasUnqualifiedDesugaredType(pointerType())))198            : expr(anyOf(ArrayCastExpr, PointerToArrayExpr,199                         PointerToStructExpr));200 201    const auto ZeroLiteral = ignoringParenImpCasts(integerLiteral(equals(0)));202    const auto SubscriptExprWithZeroIndex =203        arraySubscriptExpr(hasIndex(ZeroLiteral));204    const auto DerefExpr =205        ignoringParenImpCasts(unaryOperator(hasOperatorName("*")));206 207    Finder->addMatcher(208        expr(sizeOfExpr(has(ignoringParenImpCasts(expr(209                 PointerToDetectedExpr, unless(DerefExpr),210                 unless(SubscriptExprWithZeroIndex),211                 unless(VarWithConstStrLiteralDecl), unless(cxxThisExpr()))))))212            .bind("sizeof-pointer"),213        this);214  }215 216  // Detect expression like: sizeof(expr) <= k for a suspicious constant 'k'.217  if (WarnOnSizeOfCompareToConstant) {218    Finder->addMatcher(219        binaryOperator(matchers::isRelationalOperator(),220                       hasOperands(ignoringParenImpCasts(SizeOfExpr),221                                   ignoringParenImpCasts(integerLiteral(anyOf(222                                       equals(0), isBiggerThan(0x80000))))))223            .bind("sizeof-compare-constant"),224        this);225  }226 227  // Detect expression like: sizeof(expr, expr); most likely an error.228  Finder->addMatcher(229      sizeOfExpr(230          has(ignoringParenImpCasts(231              binaryOperator(hasOperatorName(",")).bind("sizeof-comma-binop"))))232          .bind("sizeof-comma-expr"),233      this);234 235  // Detect sizeof(...) /sizeof(...));236  // FIXME:237  // Re-evaluate what cases to handle by the checker.238  // Probably any sizeof(A)/sizeof(B) should be error if239  // 'A' is not an array (type) and 'B' the (type of the) first element of it.240  // Except if 'A' and 'B' are non-pointers, then use the existing size division241  // rule.242  const auto ElemType =243      arrayType(hasElementType(recordType().bind("elem-type")));244  const auto ElemPtrType = pointerType(pointee(type().bind("elem-ptr-type")));245  const auto SizeofDivideExpr = binaryOperator(246      hasOperatorName("/"),247      hasLHS(248          ignoringParenImpCasts(sizeOfExpr(hasArgumentOfType(hasCanonicalType(249              type(anyOf(ElemType, ElemPtrType, type())).bind("num-type")))))),250      hasRHS(ignoringParenImpCasts(sizeOfExpr(251          hasArgumentOfType(hasCanonicalType(type().bind("denom-type")))))));252 253  Finder->addMatcher(SizeofDivideExpr.bind("sizeof-divide-expr"), this);254 255  // Detect expression like: sizeof(...) * sizeof(...)); most likely an error.256  Finder->addMatcher(binaryOperator(hasOperatorName("*"),257                                    hasLHS(ignoringParenImpCasts(SizeOfExpr)),258                                    hasRHS(ignoringParenImpCasts(SizeOfExpr)))259                         .bind("sizeof-multiply-sizeof"),260                     this);261 262  Finder->addMatcher(263      binaryOperator(hasOperatorName("*"),264                     hasOperands(ignoringParenImpCasts(SizeOfExpr),265                                 ignoringParenImpCasts(binaryOperator(266                                     hasOperatorName("*"),267                                     hasEitherOperand(268                                         ignoringParenImpCasts(SizeOfExpr))))))269          .bind("sizeof-multiply-sizeof"),270      this);271 272  // Detect strange double-sizeof expression like: sizeof(sizeof(...));273  // Note: The expression 'sizeof(sizeof(0))' is accepted.274  Finder->addMatcher(sizeOfExpr(has(ignoringParenImpCasts(hasSizeOfDescendant(275                                    8, allOf(SizeOfExpr, unless(SizeOfZero))))))276                         .bind("sizeof-sizeof-expr"),277                     this);278 279  // Detect sizeof usage in comparisons involving pointer arithmetics, such as280  // N * sizeof(T) == P1 - P2 or (P1 - P2) / sizeof(T), where P1 and P2 are281  // pointers to a type T.282  const auto PtrDiffExpr = binaryOperator(283      hasOperatorName("-"),284      hasLHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(285          hasUnqualifiedDesugaredType(type().bind("left-ptr-type"))))))),286      hasRHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(287          hasUnqualifiedDesugaredType(type().bind("right-ptr-type"))))))));288 289  Finder->addMatcher(290      binaryOperator(291          hasAnyOperatorName("==", "!=", "<", "<=", ">", ">=", "+", "-"),292          hasOperands(anyOf(ignoringParenImpCasts(293                                SizeOfExpr.bind("sizeof-ptr-mul-expr")),294                            ignoringParenImpCasts(binaryOperator(295                                hasOperatorName("*"),296                                hasEitherOperand(ignoringParenImpCasts(297                                    SizeOfExpr.bind("sizeof-ptr-mul-expr")))))),298                      ignoringParenImpCasts(PtrDiffExpr)))299          .bind("sizeof-in-ptr-arithmetic-mul"),300      this);301 302  Finder->addMatcher(303      binaryOperator(304          hasOperatorName("/"), hasLHS(ignoringParenImpCasts(PtrDiffExpr)),305          hasRHS(ignoringParenImpCasts(SizeOfExpr.bind("sizeof-ptr-div-expr"))))306          .bind("sizeof-in-ptr-arithmetic-div"),307      this);308 309  // SEI CERT ARR39-C. Do not add or subtract a scaled integer to a pointer.310  // Detect sizeof, alignof and offsetof usage in pointer arithmetics where311  // they are used to scale the numeric distance, which is scaled again by312  // the pointer arithmetic operator. This can result in forming invalid313  // offsets.314  //315  // Examples, where P is a pointer, N is some integer (both compile-time and316  // run-time): P + sizeof(T), P + sizeof(*P), P + N * sizeof(*P).317  //318  // This check does not warn on cases where the pointee type is "1 byte",319  // as those cases can often come from generics and also do not constitute a320  // problem because the size does not affect the scale used.321  const auto InterestingPtrTyForPtrArithmetic =322      pointerType(pointee(qualType().bind("pointee-type")));323  const auto SizeofLikeScaleExpr =324      expr(anyOf(unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)),325                 unaryExprOrTypeTraitExpr(ofKind(UETT_AlignOf)),326                 offsetOfExpr()))327          .bind("sizeof-in-ptr-arithmetic-scale-expr");328  const auto PtrArithmeticIntegerScaleExpr = binaryOperator(329      WarnOnOffsetDividedBySizeOf ? binaryOperator(hasAnyOperatorName("*", "/"))330                                  : binaryOperator(hasOperatorName("*")),331      // sizeof(...) * sizeof(...) and sizeof(...) / sizeof(...) is handled332      // by this check on another path.333      hasOperands(expr(hasType(isInteger()), unless(SizeofLikeScaleExpr)),334                  SizeofLikeScaleExpr));335  const auto PtrArithmeticScaledIntegerExpr =336      expr(anyOf(SizeofLikeScaleExpr, PtrArithmeticIntegerScaleExpr),337           unless(SizeofDivideExpr));338 339  Finder->addMatcher(340      expr(anyOf(341          binaryOperator(hasAnyOperatorName("+", "-"),342                         hasOperands(hasType(InterestingPtrTyForPtrArithmetic),343                                     PtrArithmeticScaledIntegerExpr))344              .bind("sizeof-in-ptr-arithmetic-plusminus"),345          binaryOperator(hasAnyOperatorName("+=", "-="),346                         hasLHS(hasType(InterestingPtrTyForPtrArithmetic)),347                         hasRHS(PtrArithmeticScaledIntegerExpr))348              .bind("sizeof-in-ptr-arithmetic-plusminus"))),349      this);350}351 352void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {353  const ASTContext &Ctx = *Result.Context;354 355  if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-constant")) {356    diag(E->getBeginLoc(), "suspicious usage of 'sizeof(K)'; did you mean 'K'?")357        << E->getSourceRange();358  } else if (const auto *E =359                 Result.Nodes.getNodeAs<Expr>("sizeof-integer-call")) {360    diag(E->getBeginLoc(), "suspicious usage of 'sizeof()' on an expression "361                           "of integer type")362        << E->getSourceRange();363  } else if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-this")) {364    diag(E->getBeginLoc(),365         "suspicious usage of 'sizeof(this)'; did you mean 'sizeof(*this)'")366        << E->getSourceRange();367  } else if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-charp")) {368    diag(E->getBeginLoc(),369         "suspicious usage of 'sizeof(char*)'; do you mean 'strlen'?")370        << E->getSourceRange();371  } else if (Result.Nodes.getNodeAs<Stmt>("loop-expr")) {372    auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>("sizeof-arg-type");373    if (const auto *Member = dyn_cast<MemberPointerType>(SizeofArgTy))374      SizeofArgTy = Member->getPointeeType().getTypePtr();375 376    const auto *SzOfExpr = Result.Nodes.getNodeAs<Expr>("sizeof-expr");377 378    if (const auto *Type = dyn_cast<ArrayType>(SizeofArgTy)) {379      // check if the array element size is larger than one. If true,380      // the size of the array is higher than the number of elements381      if (!getSizeOfType(Ctx, Type->getElementType().getTypePtr()).isOne()) {382        diag(SzOfExpr->getBeginLoc(),383             "suspicious usage of 'sizeof' in the loop")384            << SzOfExpr->getSourceRange();385      }386    }387  } else if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-pointer")) {388    diag(E->getBeginLoc(), "suspicious usage of 'sizeof()' on an expression "389                           "of pointer type")390        << E->getSourceRange();391  } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(392                 "sizeof-compare-constant")) {393    diag(E->getOperatorLoc(),394         "suspicious comparison of 'sizeof(expr)' to a constant")395        << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();396  } else if (const auto *E =397                 Result.Nodes.getNodeAs<Expr>("sizeof-comma-expr")) {398    const auto *BO =399        Result.Nodes.getNodeAs<BinaryOperator>("sizeof-comma-binop");400    assert(BO);401    diag(BO->getOperatorLoc(), "suspicious usage of 'sizeof(..., ...)'")402        << E->getSourceRange();403  } else if (const auto *E =404                 Result.Nodes.getNodeAs<BinaryOperator>("sizeof-divide-expr")) {405    const auto *NumTy = Result.Nodes.getNodeAs<Type>("num-type");406    const auto *DenomTy = Result.Nodes.getNodeAs<Type>("denom-type");407    const auto *ElementTy = Result.Nodes.getNodeAs<Type>("elem-type");408    const auto *PointedTy = Result.Nodes.getNodeAs<Type>("elem-ptr-type");409 410    const CharUnits NumeratorSize = getSizeOfType(Ctx, NumTy);411    const CharUnits DenominatorSize = getSizeOfType(Ctx, DenomTy);412    const CharUnits ElementSize = getSizeOfType(Ctx, ElementTy);413 414    if (DenominatorSize > CharUnits::Zero() &&415        !NumeratorSize.isMultipleOf(DenominatorSize)) {416      diag(E->getOperatorLoc(), "suspicious usage of 'sizeof(...)/sizeof(...)';"417                                " numerator is not a multiple of denominator")418          << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();419    } else if (ElementSize > CharUnits::Zero() &&420               DenominatorSize > CharUnits::Zero() &&421               ElementSize != DenominatorSize) {422      // FIXME: Apparently there are no testcases that cover this branch!423      diag(E->getOperatorLoc(),424           "suspicious usage of 'sizeof(array)/sizeof(...)';"425           " denominator differs from the size of array elements")426          << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();427    } else if (NumTy && DenomTy && ASTContext::hasSameType(NumTy, DenomTy) &&428               !NumTy->isDependentType()) {429      // Dependent type should not be compared.430      diag(E->getOperatorLoc(),431           "suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions "432           "have the same type")433          << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();434    } else if (!WarnOnSizeOfPointer) {435      // When 'WarnOnSizeOfPointer' is enabled, these messages become redundant:436      if (PointedTy && DenomTy && ASTContext::hasSameType(PointedTy, DenomTy)) {437        diag(E->getOperatorLoc(),438             "suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer "439             "is divided by size of pointed type")440            << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();441      } else if (NumTy && DenomTy && NumTy->isPointerType() &&442                 DenomTy->isPointerType()) {443        diag(E->getOperatorLoc(),444             "suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions "445             "have pointer types")446            << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();447      }448    }449  } else if (const auto *E =450                 Result.Nodes.getNodeAs<Expr>("sizeof-sizeof-expr")) {451    diag(E->getBeginLoc(), "suspicious usage of 'sizeof(sizeof(...))'")452        << E->getSourceRange();453  } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(454                 "sizeof-multiply-sizeof")) {455    diag(E->getOperatorLoc(), "suspicious 'sizeof' by 'sizeof' multiplication")456        << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();457  } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(458                 "sizeof-in-ptr-arithmetic-mul")) {459    const auto *LPtrTy = Result.Nodes.getNodeAs<Type>("left-ptr-type");460    const auto *RPtrTy = Result.Nodes.getNodeAs<Type>("right-ptr-type");461    const auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>("sizeof-arg-type");462    const auto *SizeOfExpr =463        Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-mul-expr");464 465    if (ASTContext::hasSameType(LPtrTy, RPtrTy) &&466        ASTContext::hasSameType(LPtrTy, SizeofArgTy)) {467      diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "468                                      "pointer arithmetic")469          << SizeOfExpr->getSourceRange() << E->getOperatorLoc()470          << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();471    }472  } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(473                 "sizeof-in-ptr-arithmetic-div")) {474    const auto *LPtrTy = Result.Nodes.getNodeAs<Type>("left-ptr-type");475    const auto *RPtrTy = Result.Nodes.getNodeAs<Type>("right-ptr-type");476    const auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>("sizeof-arg-type");477    const auto *SizeOfExpr =478        Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-div-expr");479 480    if (ASTContext::hasSameType(LPtrTy, RPtrTy) &&481        ASTContext::hasSameType(LPtrTy, SizeofArgTy)) {482      diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "483                                      "pointer arithmetic")484          << SizeOfExpr->getSourceRange() << E->getOperatorLoc()485          << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();486    }487  } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(488                 "sizeof-in-ptr-arithmetic-plusminus")) {489    const auto *PointeeTy = Result.Nodes.getNodeAs<QualType>("pointee-type");490    const auto *ScaleExpr =491        Result.Nodes.getNodeAs<Expr>("sizeof-in-ptr-arithmetic-scale-expr");492    const CharUnits PointeeSize = getSizeOfType(Ctx, PointeeTy->getTypePtr());493    const int ScaleKind = [ScaleExpr]() {494      if (const auto *UTTE = dyn_cast<UnaryExprOrTypeTraitExpr>(ScaleExpr))495        switch (UTTE->getKind()) {496        case UETT_SizeOf:497          return 0;498        case UETT_AlignOf:499          return 1;500        default:501          return -1;502        }503 504      if (isa<OffsetOfExpr>(ScaleExpr))505        return 2;506 507      return -1;508    }();509 510    if (ScaleKind != -1 && PointeeSize > CharUnits::One()) {511      diag(E->getExprLoc(),512           "suspicious usage of '%select{sizeof|alignof|offsetof}0(...)' in "513           "pointer arithmetic; this scaled value will be scaled again by the "514           "'%1' operator")515          << ScaleKind << E->getOpcodeStr() << ScaleExpr->getSourceRange();516      diag(E->getExprLoc(),517           "'%0' in pointer arithmetic internally scales with 'sizeof(%1)' == "518           "%2",519           DiagnosticIDs::Note)520          << E->getOpcodeStr()521          << PointeeTy->getAsString(Ctx.getPrintingPolicy())522          << PointeeSize.getQuantity();523    }524  }525}526 527} // namespace clang::tidy::bugprone528