summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/modernize
diff options
context:
space:
mode:
authorMalcolm Parsons <malcolm.parsons@gmail.com>2016-12-20 21:26:07 +0000
committerMalcolm Parsons <malcolm.parsons@gmail.com>2016-12-20 21:26:07 +0000
commitd5508b4e89f8e3dcbf83d9eadbb77b2420ea5202 (patch)
tree75f689e0508a9a83803942bb3ca1ef7fb3fba693 /clang-tools-extra/clang-tidy/modernize
parente3be61c1393604e9e0efa98c4c2352c05b32f61e (diff)
downloadbcm5719-llvm-d5508b4e89f8e3dcbf83d9eadbb77b2420ea5202.tar.gz
bcm5719-llvm-d5508b4e89f8e3dcbf83d9eadbb77b2420ea5202.zip
[clang-tidy] Add modernize-use-default-member-init check
Summary: Fixes PR18858 Reviewers: alexfh, hokein, aaron.ballman Subscribers: JDevlieghere, Eugene.Zelenko, Prazek, mgorny, cfe-commits, modocache Differential Revision: https://reviews.llvm.org/D26750 llvm-svn: 290202
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize')
-rw-r--r--clang-tools-extra/clang-tidy/modernize/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp241
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.h45
4 files changed, 290 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 6d178e0a845..22c7d8d5b1e 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -16,6 +16,7 @@ add_clang_library(clangTidyModernizeModule
ShrinkToFitCheck.cpp
UseAutoCheck.cpp
UseBoolLiteralsCheck.cpp
+ UseDefaultMemberInitCheck.cpp
UseEmplaceCheck.cpp
UseEqualsDefaultCheck.cpp
UseEqualsDeleteCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 07b450dcf50..3274f5d60b4 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -22,6 +22,7 @@
#include "ShrinkToFitCheck.h"
#include "UseAutoCheck.h"
#include "UseBoolLiteralsCheck.h"
+#include "UseDefaultMemberInitCheck.h"
#include "UseEmplaceCheck.h"
#include "UseEqualsDefaultCheck.h"
#include "UseEqualsDeleteCheck.h"
@@ -56,6 +57,8 @@ public:
CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");
CheckFactories.registerCheck<UseBoolLiteralsCheck>(
"modernize-use-bool-literals");
+ CheckFactories.registerCheck<UseDefaultMemberInitCheck>(
+ "modernize-use-default-member-init");
CheckFactories.registerCheck<UseEmplaceCheck>("modernize-use-emplace");
CheckFactories.registerCheck<UseEqualsDefaultCheck>("modernize-use-equals-default");
CheckFactories.registerCheck<UseEqualsDeleteCheck>(
diff --git a/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp
new file mode 100644
index 00000000000..eb084efcdfa
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp
@@ -0,0 +1,241 @@
+//===--- UseDefaultMemberInitCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseDefaultMemberInitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static StringRef getValueOfValueInit(const QualType InitType) {
+ switch (InitType->getScalarTypeKind()) {
+ case Type::STK_CPointer:
+ case Type::STK_BlockPointer:
+ case Type::STK_ObjCObjectPointer:
+ case Type::STK_MemberPointer:
+ return "nullptr";
+
+ case Type::STK_Bool:
+ return "false";
+
+ case Type::STK_Integral:
+ switch (InitType->getAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return "'\\0'";
+ case BuiltinType::WChar_U:
+ case BuiltinType::WChar_S:
+ return "L'\\0'";
+ case BuiltinType::Char16:
+ return "u'\\0'";
+ case BuiltinType::Char32:
+ return "U'\\0'";
+ default:
+ return "0";
+ }
+
+ case Type::STK_Floating:
+ switch (InitType->getAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ return "0.0f";
+ default:
+ return "0.0";
+ }
+
+ case Type::STK_FloatingComplex:
+ case Type::STK_IntegralComplex:
+ return getValueOfValueInit(
+ InitType->getAs<ComplexType>()->getElementType());
+ }
+ llvm_unreachable("Invalid scalar type kind");
+}
+
+static bool isZero(const Expr *E) {
+ switch (E->getStmtClass()) {
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::ImplicitValueInitExprClass:
+ return true;
+ case Stmt::InitListExprClass:
+ return cast<InitListExpr>(E)->getNumInits() == 0;
+ case Stmt::CharacterLiteralClass:
+ return !cast<CharacterLiteral>(E)->getValue();
+ case Stmt::CXXBoolLiteralExprClass:
+ return !cast<CXXBoolLiteralExpr>(E)->getValue();
+ case Stmt::IntegerLiteralClass:
+ return !cast<IntegerLiteral>(E)->getValue();
+ case Stmt::FloatingLiteralClass: {
+ llvm::APFloat Value = cast<FloatingLiteral>(E)->getValue();
+ return Value.isZero() && !Value.isNegative();
+ }
+ default:
+ return false;
+ }
+}
+
+static const Expr *ignoreUnaryPlus(const Expr *E) {
+ auto *UnaryOp = dyn_cast<UnaryOperator>(E);
+ if (UnaryOp && UnaryOp->getOpcode() == UO_Plus)
+ return UnaryOp->getSubExpr();
+ return E;
+}
+
+static const Expr *getInitializer(const Expr *E) {
+ auto *InitList = dyn_cast<InitListExpr>(E);
+ if (InitList && InitList->getNumInits() == 1)
+ return InitList->getInit(0);
+ return E;
+}
+
+static bool sameValue(const Expr *E1, const Expr *E2) {
+ E1 = ignoreUnaryPlus(getInitializer(E1->IgnoreParenImpCasts()));
+ E2 = ignoreUnaryPlus(getInitializer(E2->IgnoreParenImpCasts()));
+
+ if (isZero(E1) && isZero(E2))
+ return true;
+
+ if (E1->getStmtClass() != E2->getStmtClass())
+ return false;
+
+ switch (E1->getStmtClass()) {
+ case Stmt::UnaryOperatorClass:
+ return sameValue(cast<UnaryOperator>(E1)->getSubExpr(),
+ cast<UnaryOperator>(E2)->getSubExpr());
+ case Stmt::CharacterLiteralClass:
+ return cast<CharacterLiteral>(E1)->getValue() ==
+ cast<CharacterLiteral>(E2)->getValue();
+ case Stmt::CXXBoolLiteralExprClass:
+ return cast<CXXBoolLiteralExpr>(E1)->getValue() ==
+ cast<CXXBoolLiteralExpr>(E2)->getValue();
+ case Stmt::IntegerLiteralClass:
+ return cast<IntegerLiteral>(E1)->getValue() ==
+ cast<IntegerLiteral>(E2)->getValue();
+ case Stmt::FloatingLiteralClass:
+ return cast<FloatingLiteral>(E1)->getValue().bitwiseIsEqual(
+ cast<FloatingLiteral>(E2)->getValue());
+ case Stmt::StringLiteralClass:
+ return cast<StringLiteral>(E1)->getString() ==
+ cast<StringLiteral>(E2)->getString();
+ case Stmt::DeclRefExprClass:
+ return cast<DeclRefExpr>(E1)->getDecl() == cast<DeclRefExpr>(E2)->getDecl();
+ default:
+ return false;
+ }
+}
+
+UseDefaultMemberInitCheck::UseDefaultMemberInitCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ UseAssignment(Options.get("UseAssignment", 0) != 0) {}
+
+void UseDefaultMemberInitCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "UseAssignment", UseAssignment);
+}
+
+AST_MATCHER(FieldDecl, hasInClassInitializer) {
+ return Node.hasInClassInitializer();
+}
+
+void UseDefaultMemberInitCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ auto Init =
+ anyOf(stringLiteral(), characterLiteral(), integerLiteral(),
+ unaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-")),
+ hasUnaryOperand(integerLiteral())),
+ floatLiteral(),
+ unaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-")),
+ hasUnaryOperand(floatLiteral())),
+ cxxBoolLiteral(), cxxNullPtrLiteralExpr(), implicitValueInitExpr(),
+ declRefExpr());
+
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ isDefaultConstructor(), unless(isInstantiated()),
+ forEachConstructorInitializer(allOf(
+ forField(unless(anyOf(isBitField(), hasInClassInitializer()))),
+ cxxCtorInitializer(isWritten(),
+ withInitializer(ignoringImplicit(Init)))
+ .bind("default")))),
+ this);
+
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ unless(ast_matchers::isTemplateInstantiation()),
+ forEachConstructorInitializer(
+ allOf(forField(hasInClassInitializer()),
+ cxxCtorInitializer(isWritten(),
+ withInitializer(ignoringImplicit(Init)))
+ .bind("existing")))),
+ this);
+}
+
+void UseDefaultMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Default =
+ Result.Nodes.getNodeAs<CXXCtorInitializer>("default"))
+ checkDefaultInit(Result, Default);
+ else if (const auto *Existing =
+ Result.Nodes.getNodeAs<CXXCtorInitializer>("existing"))
+ checkExistingInit(Result, Existing);
+ else
+ llvm_unreachable("Bad Callback. No node provided.");
+}
+
+void UseDefaultMemberInitCheck::checkDefaultInit(
+ const MatchFinder::MatchResult &Result, const CXXCtorInitializer *Init) {
+ const FieldDecl *Field = Init->getMember();
+
+ SourceLocation FieldEnd =
+ Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), 0,
+ *Result.SourceManager, getLangOpts());
+ SourceLocation LParenEnd = Lexer::getLocForEndOfToken(
+ Init->getLParenLoc(), 0, *Result.SourceManager, getLangOpts());
+ CharSourceRange InitRange =
+ CharSourceRange::getCharRange(LParenEnd, Init->getRParenLoc());
+
+ auto Diag =
+ diag(Field->getLocation(), "use default member initializer for %0")
+ << Field
+ << FixItHint::CreateInsertion(FieldEnd, UseAssignment ? " = " : "{")
+ << FixItHint::CreateInsertionFromRange(FieldEnd, InitRange);
+
+ if (UseAssignment && isa<ImplicitValueInitExpr>(Init->getInit()))
+ Diag << FixItHint::CreateInsertion(
+ FieldEnd, getValueOfValueInit(Init->getInit()->getType()));
+
+ if (!UseAssignment)
+ Diag << FixItHint::CreateInsertion(FieldEnd, "}");
+
+ Diag << FixItHint::CreateRemoval(Init->getSourceRange());
+}
+
+void UseDefaultMemberInitCheck::checkExistingInit(
+ const MatchFinder::MatchResult &Result, const CXXCtorInitializer *Init) {
+ const FieldDecl *Field = Init->getMember();
+
+ if (!sameValue(Field->getInClassInitializer(), Init->getInit()))
+ return;
+
+ diag(Init->getSourceLocation(), "member initializer for %0 is redundant")
+ << Field
+ << FixItHint::CreateRemoval(Init->getSourceRange());
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.h
new file mode 100644
index 00000000000..6d3b19b6845
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.h
@@ -0,0 +1,45 @@
+//===--- UseDefaultMemberInitCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Convert a default constructor's member initializers into default member
+/// initializers. Remove member initializers that are the same as a default
+/// member initializer.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-default-member-init.html
+class UseDefaultMemberInitCheck : public ClangTidyCheck {
+public:
+ UseDefaultMemberInitCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void checkDefaultInit(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CXXCtorInitializer *Init);
+ void checkExistingInit(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CXXCtorInitializer *Init);
+
+ const bool UseAssignment;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H
OpenPOWER on IntegriCloud