1 | //===--- AvoidConstOrRefDataMembersCheck.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 | |
9 | #include "AvoidConstOrRefDataMembersCheck.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
12 | |
13 | using namespace clang::ast_matchers; |
14 | |
15 | namespace clang::tidy::cppcoreguidelines { |
16 | namespace { |
17 | |
18 | AST_MATCHER(FieldDecl, isMemberOfLambda) { |
19 | return Node.getParent()->isLambda(); |
20 | } |
21 | |
22 | struct MemberFunctionInfo { |
23 | bool Declared{}; |
24 | bool Deleted{}; |
25 | }; |
26 | |
27 | struct MemberFunctionPairInfo { |
28 | MemberFunctionInfo Copy{}; |
29 | MemberFunctionInfo Move{}; |
30 | }; |
31 | |
32 | MemberFunctionPairInfo getConstructorsInfo(CXXRecordDecl const &Node) { |
33 | MemberFunctionPairInfo Constructors{}; |
34 | |
35 | for (CXXConstructorDecl const *Ctor : Node.ctors()) { |
36 | if (Ctor->isCopyConstructor()) { |
37 | Constructors.Copy.Declared = true; |
38 | if (Ctor->isDeleted()) |
39 | Constructors.Copy.Deleted = true; |
40 | } |
41 | if (Ctor->isMoveConstructor()) { |
42 | Constructors.Move.Declared = true; |
43 | if (Ctor->isDeleted()) |
44 | Constructors.Move.Deleted = true; |
45 | } |
46 | } |
47 | |
48 | return Constructors; |
49 | } |
50 | |
51 | MemberFunctionPairInfo getAssignmentsInfo(CXXRecordDecl const &Node) { |
52 | MemberFunctionPairInfo Assignments{}; |
53 | |
54 | for (CXXMethodDecl const *Method : Node.methods()) { |
55 | if (Method->isCopyAssignmentOperator()) { |
56 | Assignments.Copy.Declared = true; |
57 | if (Method->isDeleted()) |
58 | Assignments.Copy.Deleted = true; |
59 | } |
60 | |
61 | if (Method->isMoveAssignmentOperator()) { |
62 | Assignments.Move.Declared = true; |
63 | if (Method->isDeleted()) |
64 | Assignments.Move.Deleted = true; |
65 | } |
66 | } |
67 | |
68 | return Assignments; |
69 | } |
70 | |
71 | AST_MATCHER(CXXRecordDecl, isCopyableOrMovable) { |
72 | MemberFunctionPairInfo Constructors = getConstructorsInfo(Node); |
73 | MemberFunctionPairInfo Assignments = getAssignmentsInfo(Node); |
74 | |
75 | if (Node.hasSimpleCopyConstructor() || |
76 | (Constructors.Copy.Declared && !Constructors.Copy.Deleted)) |
77 | return true; |
78 | if (Node.hasSimpleMoveConstructor() || |
79 | (Constructors.Move.Declared && !Constructors.Move.Deleted)) |
80 | return true; |
81 | if (Node.hasSimpleCopyAssignment() || |
82 | (Assignments.Copy.Declared && !Assignments.Copy.Deleted)) |
83 | return true; |
84 | if (Node.hasSimpleMoveAssignment() || |
85 | (Assignments.Move.Declared && !Assignments.Move.Deleted)) |
86 | return true; |
87 | |
88 | return false; |
89 | } |
90 | |
91 | } // namespace |
92 | |
93 | void AvoidConstOrRefDataMembersCheck::registerMatchers(MatchFinder *Finder) { |
94 | Finder->addMatcher( |
95 | NodeMatch: fieldDecl( |
96 | unless(isMemberOfLambda()), |
97 | anyOf( |
98 | fieldDecl(hasType(InnerMatcher: hasCanonicalType(InnerMatcher: referenceType()))).bind(ID: "ref"), |
99 | fieldDecl(hasType(InnerMatcher: qualType(isConstQualified()))).bind(ID: "const")), |
100 | hasDeclContext(InnerMatcher: cxxRecordDecl(isCopyableOrMovable()))), |
101 | Action: this); |
102 | } |
103 | |
104 | void AvoidConstOrRefDataMembersCheck::check( |
105 | const MatchFinder::MatchResult &Result) { |
106 | if (const auto *MatchedDecl = Result.Nodes.getNodeAs<FieldDecl>(ID: "ref")) |
107 | diag(MatchedDecl->getLocation(), "member %0 of type %1 is a reference") |
108 | << MatchedDecl << MatchedDecl->getType(); |
109 | if (const auto *MatchedDecl = Result.Nodes.getNodeAs<FieldDecl>(ID: "const")) |
110 | diag(MatchedDecl->getLocation(), "member %0 of type %1 is const qualified") |
111 | << MatchedDecl << MatchedDecl->getType(); |
112 | } |
113 | |
114 | } // namespace clang::tidy::cppcoreguidelines |
115 |