Author: Congcong Cai Date: 2024-11-25T06:47:22+08:00 New Revision: 605b8dad5cb173ac86adb3541e9f70a824aff364
URL: https://github.com/llvm/llvm-project/commit/605b8dad5cb173ac86adb3541e9f70a824aff364 DIFF: https://github.com/llvm/llvm-project/commit/605b8dad5cb173ac86adb3541e9f70a824aff364.diff LOG: [clang-tidy] Fix false positive in cppcoreguidelines-avoid-const-or-ref-data-members when detecting templated classes with inheritance (#115180) `hasSimpleCopyConstructor` series of functions are not reliable when these functions are not resolved. We need to manually resolve the status of these functions from its base classes. Fixes: #111985. Added: Modified: clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-const-or-ref-data-members.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp index 6a6e620a4387b0..f615976c7edb62 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp @@ -13,79 +13,88 @@ using namespace clang::ast_matchers; namespace clang::tidy::cppcoreguidelines { -namespace { -AST_MATCHER(FieldDecl, isMemberOfLambda) { - return Node.getParent()->isLambda(); +static bool isCopyConstructible(CXXRecordDecl const &Node) { + if (Node.needsOverloadResolutionForCopyConstructor() && + Node.needsImplicitCopyConstructor()) { + // unresolved + for (CXXBaseSpecifier const &BS : Node.bases()) { + CXXRecordDecl const *BRD = BS.getType()->getAsCXXRecordDecl(); + if (BRD != nullptr && !isCopyConstructible(*BRD)) + return false; + } + } + if (Node.hasSimpleCopyConstructor()) + return true; + for (CXXConstructorDecl const *Ctor : Node.ctors()) + if (Ctor->isCopyConstructor()) + return !Ctor->isDeleted(); + return false; } -struct MemberFunctionInfo { - bool Declared{}; - bool Deleted{}; -}; - -struct MemberFunctionPairInfo { - MemberFunctionInfo Copy{}; - MemberFunctionInfo Move{}; -}; - -MemberFunctionPairInfo getConstructorsInfo(CXXRecordDecl const &Node) { - MemberFunctionPairInfo Constructors{}; - - for (CXXConstructorDecl const *Ctor : Node.ctors()) { - if (Ctor->isCopyConstructor()) { - Constructors.Copy.Declared = true; - if (Ctor->isDeleted()) - Constructors.Copy.Deleted = true; - } - if (Ctor->isMoveConstructor()) { - Constructors.Move.Declared = true; - if (Ctor->isDeleted()) - Constructors.Move.Deleted = true; +static bool isMoveConstructible(CXXRecordDecl const &Node) { + if (Node.needsOverloadResolutionForMoveConstructor() && + Node.needsImplicitMoveConstructor()) { + // unresolved + for (CXXBaseSpecifier const &BS : Node.bases()) { + CXXRecordDecl const *BRD = BS.getType()->getAsCXXRecordDecl(); + if (BRD != nullptr && !isMoveConstructible(*BRD)) + return false; } } - - return Constructors; + if (Node.hasSimpleMoveConstructor()) + return true; + for (CXXConstructorDecl const *Ctor : Node.ctors()) + if (Ctor->isMoveConstructor()) + return !Ctor->isDeleted(); + return false; } -MemberFunctionPairInfo getAssignmentsInfo(CXXRecordDecl const &Node) { - MemberFunctionPairInfo Assignments{}; - - for (CXXMethodDecl const *Method : Node.methods()) { - if (Method->isCopyAssignmentOperator()) { - Assignments.Copy.Declared = true; - if (Method->isDeleted()) - Assignments.Copy.Deleted = true; +static bool isCopyAssignable(CXXRecordDecl const &Node) { + if (Node.needsOverloadResolutionForCopyAssignment() && + Node.needsImplicitCopyAssignment()) { + // unresolved + for (CXXBaseSpecifier const &BS : Node.bases()) { + CXXRecordDecl const *BRD = BS.getType()->getAsCXXRecordDecl(); + if (BRD != nullptr && !isCopyAssignable(*BRD)) + return false; } + } + if (Node.hasSimpleCopyAssignment()) + return true; + for (CXXMethodDecl const *Method : Node.methods()) + if (Method->isCopyAssignmentOperator()) + return !Method->isDeleted(); + return false; +} - if (Method->isMoveAssignmentOperator()) { - Assignments.Move.Declared = true; - if (Method->isDeleted()) - Assignments.Move.Deleted = true; +static bool isMoveAssignable(CXXRecordDecl const &Node) { + if (Node.needsOverloadResolutionForMoveAssignment() && + Node.needsImplicitMoveAssignment()) { + // unresolved + for (CXXBaseSpecifier const &BS : Node.bases()) { + CXXRecordDecl const *BRD = BS.getType()->getAsCXXRecordDecl(); + if (BRD != nullptr && !isMoveAssignable(*BRD)) + return false; } } - - return Assignments; + if (Node.hasSimpleMoveAssignment()) + return true; + for (CXXMethodDecl const *Method : Node.methods()) + if (Method->isMoveAssignmentOperator()) + return !Method->isDeleted(); + return false; } -AST_MATCHER(CXXRecordDecl, isCopyableOrMovable) { - MemberFunctionPairInfo Constructors = getConstructorsInfo(Node); - MemberFunctionPairInfo Assignments = getAssignmentsInfo(Node); +namespace { - if (Node.hasSimpleCopyConstructor() || - (Constructors.Copy.Declared && !Constructors.Copy.Deleted)) - return true; - if (Node.hasSimpleMoveConstructor() || - (Constructors.Move.Declared && !Constructors.Move.Deleted)) - return true; - if (Node.hasSimpleCopyAssignment() || - (Assignments.Copy.Declared && !Assignments.Copy.Deleted)) - return true; - if (Node.hasSimpleMoveAssignment() || - (Assignments.Move.Declared && !Assignments.Move.Deleted)) - return true; +AST_MATCHER(FieldDecl, isMemberOfLambda) { + return Node.getParent()->isLambda(); +} - return false; +AST_MATCHER(CXXRecordDecl, isCopyableOrMovable) { + return isCopyConstructible(Node) || isMoveConstructible(Node) || + isCopyAssignable(Node) || isMoveAssignable(Node); } } // namespace diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 1f338f23f4e6ea..fec2c20206bc4d 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -207,6 +207,10 @@ Changes in existing checks fix false positive that floating point variable is only used in increment expression. +- Improved :doc:`cppcoreguidelines-avoid-const-or-ref-data-members + <clang-tidy/checks/cppcoreguidelines/avoid-const-or-ref-data-members>` check to + avoid false positives when detecting a templated class with inheritance. + - Improved :doc:`cppcoreguidelines-init-variables <clang-tidy/checks/cppcoreguidelines/init-variables>` check by fixing the insertion location for function pointers. diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-const-or-ref-data-members.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-const-or-ref-data-members.cpp index e3864be134da3c..19da88300aec46 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-const-or-ref-data-members.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-const-or-ref-data-members.cpp @@ -285,6 +285,28 @@ struct InheritBothFromNonCopyableAndNonMovable : NonCopyable, NonMovable int& x; // OK, non copyable nor movable }; +template<class T> struct TemplateInheritFromNonCopyable : NonCopyable +{ + int& x; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference +}; + +template<class T> struct TemplateInheritFromNonMovable : NonMovable +{ + int& x; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference +}; + +template<class T> struct TemplateInheritFromNonCopyableNonMovable : NonCopyableNonMovable +{ + int& x; // OK, non copyable nor movable +}; + +template<class T> struct TemplateInheritBothFromNonCopyableAndNonMovable : NonCopyable, NonMovable +{ + int& x; // OK, non copyable nor movable +}; + // Test composition struct ContainsNonCopyable { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits