10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/RecordLayout.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/ASTMatchers/ASTMatchers.h" 19 namespace cppcoreguidelines {
21 void SlicingCheck::registerMatchers(MatchFinder *Finder) {
38 const auto OfBaseClass = ofClass(cxxRecordDecl().bind(
"BaseDecl"));
39 const auto IsDerivedFromBaseDecl =
40 cxxRecordDecl(isDerivedFrom(equalsBoundNode(
"BaseDecl")))
42 const auto HasTypeDerivedFromBaseDecl =
43 anyOf(hasType(IsDerivedFromBaseDecl),
44 hasType(references(IsDerivedFromBaseDecl)));
45 const auto IsWithinDerivedCtor =
46 hasParent(cxxConstructorDecl(ofClass(equalsBoundNode(
"DerivedDecl"))));
49 const auto SlicesObjectInAssignment =
50 callExpr(callee(cxxMethodDecl(anyOf(isCopyAssignmentOperator(),
51 isMoveAssignmentOperator()),
53 hasArgument(1, HasTypeDerivedFromBaseDecl));
57 const auto SlicesObjectInCtor = cxxConstructExpr(
58 hasDeclaration(cxxConstructorDecl(
59 anyOf(isCopyConstructor(), isMoveConstructor()), OfBaseClass)),
60 hasArgument(0, HasTypeDerivedFromBaseDecl),
63 unless(IsWithinDerivedCtor));
66 expr(anyOf(SlicesObjectInAssignment, SlicesObjectInCtor)).bind(
"Call"),
73 void SlicingCheck::DiagnoseSlicedOverriddenMethods(
74 const Expr &Call,
const CXXRecordDecl &DerivedDecl,
75 const CXXRecordDecl &BaseDecl) {
76 if (DerivedDecl.getCanonicalDecl() == BaseDecl.getCanonicalDecl())
78 for (
const auto *Method : DerivedDecl.methods()) {
81 if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
83 if (Method->size_overridden_methods() > 0) {
84 diag(Call.getExprLoc(),
85 "slicing object from type %0 to %1 discards override %2")
86 << &DerivedDecl << &BaseDecl << Method;
90 for (
const auto &
Base : DerivedDecl.bases()) {
91 if (
const auto *BaseRecordType =
Base.getType()->getAs<RecordType>()) {
92 if (
const auto *BaseRecord = cast_or_null<CXXRecordDecl>(
93 BaseRecordType->getDecl()->getDefinition()))
94 DiagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl);
99 void SlicingCheck::check(
const MatchFinder::MatchResult &Result) {
100 const auto *BaseDecl = Result.Nodes.getNodeAs<CXXRecordDecl>(
"BaseDecl");
101 const auto *DerivedDecl =
102 Result.Nodes.getNodeAs<CXXRecordDecl>(
"DerivedDecl");
103 const auto *Call = Result.Nodes.getNodeAs<Expr>(
"Call");
104 assert(BaseDecl !=
nullptr);
105 assert(DerivedDecl !=
nullptr);
106 assert(Call !=
nullptr);
117 DiagnoseSlicedOverriddenMethods(*Call, *DerivedDecl, *BaseDecl);
120 const auto &BaseLayout =
121 BaseDecl->getASTContext().getASTRecordLayout(BaseDecl);
122 const auto &DerivedLayout =
123 DerivedDecl->getASTContext().getASTRecordLayout(DerivedDecl);
124 const CharUnits StateSize =
125 DerivedLayout.getDataSize() - BaseLayout.getDataSize();
126 if (StateSize.isPositive()) {
127 diag(Call->getExprLoc(),
"slicing object from type %0 to %1 discards " 129 << DerivedDecl << BaseDecl << static_cast<int>(StateSize.getQuantity());
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::unique_ptr< GlobalCompilationDatabase > Base