diff options
author | Alexander Kornienko <alexfh@google.com> | 2016-04-13 11:35:47 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2016-04-13 11:35:47 +0000 |
commit | 855d97e30caedfa0dea3adf8928f71b16dd8a907 (patch) | |
tree | 675cf9ce2fd58594116ad39ec522b37920e95942 /clang-tools-extra/clang-tidy/utils | |
parent | 4191b90c7560c500cb67defbb10c9ab3bc0563c7 (diff) | |
download | bcm5719-llvm-855d97e30caedfa0dea3adf8928f71b16dd8a907.tar.gz bcm5719-llvm-855d97e30caedfa0dea3adf8928f71b16dd8a907.zip |
Complete support for C++ Core Guidelines Type.6: Always initialize a member variable.
Summary: Added the remaining features needed to satisfy C++ Core Guideline Type.6: Always initialize a member variable to cppcoreguidelines-pro-type-member-init. The check now flags all default-constructed uses of record types without user-provided default constructors that would leave their memory in an undefined state. The check suggests value initializing them instead.
Reviewers: flx, alexfh, aaron.ballman
Subscribers: klimek, aaron.ballman, LegalizeAdulthood, cfe-commits
Patch by Michael Miller!
Differential Revision: http://reviews.llvm.org/D18584
llvm-svn: 266191
Diffstat (limited to 'clang-tools-extra/clang-tidy/utils')
-rw-r--r-- | clang-tools-extra/clang-tidy/utils/Matchers.h | 5 | ||||
-rw-r--r-- | clang-tools-extra/clang-tidy/utils/TypeTraits.cpp | 75 | ||||
-rw-r--r-- | clang-tools-extra/clang-tidy/utils/TypeTraits.h | 7 |
3 files changed, 87 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h index 834c06b2861..94ed53a5089 100644 --- a/clang-tools-extra/clang-tidy/utils/Matchers.h +++ b/clang-tools-extra/clang-tidy/utils/Matchers.h @@ -23,6 +23,11 @@ AST_MATCHER(QualType, isExpensiveToCopy) { return IsExpensive && *IsExpensive; } +AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) { + return type_traits::recordIsTriviallyDefaultConstructible( + Node, Finder->getASTContext()); +} + } // namespace matchers } // namespace tidy } // namespace clang diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp index 6c17ee356a0..8e63f0a22d0 100644 --- a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp +++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp @@ -31,6 +31,81 @@ llvm::Optional<bool> isExpensiveToCopy(QualType Type, ASTContext &Context) { !classHasTrivialCopyAndDestroy(Type); } +bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, + const ASTContext &Context) { + const auto *ClassDecl = dyn_cast<CXXRecordDecl>(&RecordDecl); + // Non-C++ records are always trivially constructible. + if (!ClassDecl) + return true; + // A class with a user-provided default constructor is not trivially + // constructible. + if (ClassDecl->hasUserProvidedDefaultConstructor()) + return false; + // A class is trivially constructible if it has a trivial default constructor. + if (ClassDecl->hasTrivialDefaultConstructor()) + return true; + + // If all its fields are trivially constructible. + for (const FieldDecl *Field : ClassDecl->fields()) { + if (!isTriviallyDefaultConstructible(Field->getType(), Context)) + return false; + } + // If all its direct bases are trivially constructible. + for (const CXXBaseSpecifier &Base : ClassDecl->bases()) { + if (!isTriviallyDefaultConstructible(Base.getType(), Context)) + return false; + } + + return true; +} + +// Based on QualType::isTrivial. +bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) { + if (Type.isNull()) + return false; + + if (Type->isArrayType()) + return isTriviallyDefaultConstructible(Context.getBaseElementType(Type), + Context); + + // Return false for incomplete types after skipping any incomplete array + // types which are expressly allowed by the standard and thus our API. + if (Type->isIncompleteType()) + return false; + + if (Context.getLangOpts().ObjCAutoRefCount) { + switch (Type.getObjCLifetime()) { + case Qualifiers::OCL_ExplicitNone: + return true; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Autoreleasing: + return false; + + case Qualifiers::OCL_None: + if (Type->isObjCLifetimeType()) + return false; + break; + } + } + + QualType CanonicalType = Type.getCanonicalType(); + if (CanonicalType->isDependentType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) + return true; + + if (const auto *RT = CanonicalType->getAs<RecordType>()) { + return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context); + } + + // No other types can match. + return false; +} + } // type_traits } // namespace tidy } // namespace clang diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.h b/clang-tools-extra/clang-tidy/utils/TypeTraits.h index 573e61f2f5e..c612e5613d5 100644 --- a/clang-tools-extra/clang-tidy/utils/TypeTraits.h +++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.h @@ -20,6 +20,13 @@ namespace type_traits { // \brief Returns true If \c Type is expensive to copy. llvm::Optional<bool> isExpensiveToCopy(QualType Type, ASTContext &Context); +// \brief Returns true If \c Type is trivially default constructible. +bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context); + +// \brief Returns true If \c RecordDecl is trivially default constructible. +bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, + const ASTContext &Context); + } // type_traits } // namespace tidy } // namespace clang |