1 //===--- PointerArithmeticOnPolymorphicObjectCheck.cpp - clang-tidy--------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "PointerArithmeticOnPolymorphicObjectCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::bugprone
{
18 AST_MATCHER(CXXRecordDecl
, isAbstract
) { return Node
.isAbstract(); }
19 AST_MATCHER(CXXRecordDecl
, isPolymorphic
) { return Node
.isPolymorphic(); }
22 PointerArithmeticOnPolymorphicObjectCheck::
23 PointerArithmeticOnPolymorphicObjectCheck(StringRef Name
,
24 ClangTidyContext
*Context
)
25 : ClangTidyCheck(Name
, Context
),
26 IgnoreInheritedVirtualFunctions(
27 Options
.get("IgnoreInheritedVirtualFunctions", false)) {}
29 void PointerArithmeticOnPolymorphicObjectCheck::storeOptions(
30 ClangTidyOptions::OptionMap
&Opts
) {
31 Options
.store(Opts
, "IgnoreInheritedVirtualFunctions",
32 IgnoreInheritedVirtualFunctions
);
35 void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
36 MatchFinder
*Finder
) {
37 const auto PolymorphicPointerExpr
=
38 expr(hasType(hasCanonicalType(pointerType(pointee(hasCanonicalType(
39 hasDeclaration(cxxRecordDecl(unless(isFinal()), isPolymorphic())
40 .bind("pointee"))))))))
43 const auto PointerExprWithVirtualMethod
=
44 expr(hasType(hasCanonicalType(
45 pointerType(pointee(hasCanonicalType(hasDeclaration(
48 anyOf(hasMethod(isVirtualAsWritten()), isAbstract()))
49 .bind("pointee"))))))))
52 const auto SelectedPointerExpr
= IgnoreInheritedVirtualFunctions
53 ? PointerExprWithVirtualMethod
54 : PolymorphicPointerExpr
;
56 const auto ArraySubscript
= arraySubscriptExpr(hasBase(SelectedPointerExpr
));
58 const auto BinaryOperators
=
59 binaryOperator(hasAnyOperatorName("+", "-", "+=", "-="),
60 hasEitherOperand(SelectedPointerExpr
));
62 const auto UnaryOperators
= unaryOperator(
63 hasAnyOperatorName("++", "--"), hasUnaryOperand(SelectedPointerExpr
));
65 Finder
->addMatcher(ArraySubscript
, this);
66 Finder
->addMatcher(BinaryOperators
, this);
67 Finder
->addMatcher(UnaryOperators
, this);
70 void PointerArithmeticOnPolymorphicObjectCheck::check(
71 const MatchFinder::MatchResult
&Result
) {
72 const auto *PointerExpr
= Result
.Nodes
.getNodeAs
<Expr
>("pointer");
73 const auto *PointeeDecl
= Result
.Nodes
.getNodeAs
<CXXRecordDecl
>("pointee");
75 diag(PointerExpr
->getBeginLoc(),
76 "pointer arithmetic on polymorphic object of type %0 can result in "
77 "undefined behavior if the dynamic type differs from the pointer type")
78 << PointeeDecl
<< PointerExpr
->getSourceRange();
81 } // namespace clang::tidy::bugprone