summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy')
-rw-r--r--clang-tools-extra/clang-tidy/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/Makefile2
-rw-r--r--clang-tools-extra/clang-tidy/modernize/CMakeLists.txt14
-rw-r--r--clang-tools-extra/clang-tidy/modernize/Makefile12
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp46
-rw-r--r--clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp223
-rw-r--r--clang-tools-extra/clang-tidy/modernize/PassByValueCheck.h39
-rw-r--r--clang-tools-extra/clang-tidy/tool/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/tool/Makefile6
10 files changed, 344 insertions, 4 deletions
diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt b/clang-tools-extra/clang-tidy/CMakeLists.txt
index 77cd344b056..80bc565f434 100644
--- a/clang-tools-extra/clang-tidy/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/CMakeLists.txt
@@ -31,5 +31,6 @@ add_subdirectory(tool)
add_subdirectory(llvm)
add_subdirectory(google)
add_subdirectory(misc)
+add_subdirectory(modernize)
add_subdirectory(readability)
add_subdirectory(utils)
diff --git a/clang-tools-extra/clang-tidy/Makefile b/clang-tools-extra/clang-tidy/Makefile
index 74937341d25..7eb589910d3 100644
--- a/clang-tools-extra/clang-tidy/Makefile
+++ b/clang-tools-extra/clang-tidy/Makefile
@@ -11,6 +11,6 @@ CLANG_LEVEL := ../../..
LIBRARYNAME := clangTidy
include $(CLANG_LEVEL)/../../Makefile.config
-DIRS = utils readability llvm google misc tool
+DIRS = utils readability llvm google misc modernize tool
include $(CLANG_LEVEL)/Makefile
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
new file mode 100644
index 00000000000..c53ccb3334a
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyModernizeModule
+ ModernizeTidyModule.cpp
+ PassByValueCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyReadabilityModule
+ )
diff --git a/clang-tools-extra/clang-tidy/modernize/Makefile b/clang-tools-extra/clang-tidy/modernize/Makefile
new file mode 100644
index 00000000000..28cf9ef4538
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/Makefile
@@ -0,0 +1,12 @@
+##===- clang-tidy/modernize/Makefile -----------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+CLANG_LEVEL := ../../../..
+LIBRARYNAME := clangTidyModernizeModule
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
new file mode 100644
index 00000000000..5f25832e8a6
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -0,0 +1,46 @@
+//===--- ModernizeTidyModule.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 "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "PassByValueCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+class ModernizeModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
+ }
+
+ ClangTidyOptions getModuleOptions() override {
+ ClangTidyOptions Options;
+ auto &Opts = Options.CheckOptions;
+ Opts["modernize-pass-by-value.IncludeStyle"] = "llvm"; // Also: "google".
+ return Options;
+ }
+};
+
+// Register the ModernizeTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<ModernizeModule> X("modernize-module",
+ "Add modernize checks.");
+
+} // namespace modernize
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the ModernizeModule.
+volatile int ModernizeModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
new file mode 100644
index 00000000000..d6d750b07d3
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
@@ -0,0 +1,223 @@
+//===--- PassByValueCheck.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 "PassByValueCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+using namespace llvm;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// \brief Matches move-constructible classes.
+///
+/// Given
+/// \code
+/// // POD types are trivially move constructible.
+/// struct Foo { int a; };
+///
+/// struct Bar {
+/// Bar(Bar &&) = deleted;
+/// int a;
+/// };
+/// \endcode
+/// recordDecl(isMoveConstructible())
+/// matches "Foo".
+AST_MATCHER(CXXRecordDecl, isMoveConstructible) {
+ for (const CXXConstructorDecl *Ctor : Node.ctors()) {
+ if (Ctor->isMoveConstructor() && !Ctor->isDeleted())
+ return true;
+ }
+ return false;
+}
+
+/// \brief Matches non-deleted copy constructors.
+///
+/// Given
+/// \code
+/// struct Foo { Foo(const Foo &) = default; };
+/// struct Bar { Bar(const Bar &) = deleted; };
+/// \endcode
+/// constructorDecl(isNonDeletedCopyConstructor())
+/// matches "Foo(const Foo &)".
+AST_MATCHER(CXXConstructorDecl, isNonDeletedCopyConstructor) {
+ return Node.isCopyConstructor() && !Node.isDeleted();
+}
+
+static TypeMatcher constRefType() {
+ return lValueReferenceType(pointee(isConstQualified()));
+}
+
+static TypeMatcher nonConstValueType() {
+ return qualType(unless(anyOf(referenceType(), isConstQualified())));
+}
+
+/// \brief Whether or not \p ParamDecl is used exactly one time in \p Ctor.
+///
+/// Checks both in the init-list and the body of the constructor.
+static bool paramReferredExactlyOnce(const CXXConstructorDecl *Ctor,
+ const ParmVarDecl *ParamDecl) {
+ /// \brief \c clang::RecursiveASTVisitor that checks that the given
+ /// \c ParmVarDecl is used exactly one time.
+ ///
+ /// \see ExactlyOneUsageVisitor::hasExactlyOneUsageIn()
+ class ExactlyOneUsageVisitor
+ : public RecursiveASTVisitor<ExactlyOneUsageVisitor> {
+ friend class RecursiveASTVisitor<ExactlyOneUsageVisitor>;
+
+ public:
+ ExactlyOneUsageVisitor(const ParmVarDecl *ParamDecl)
+ : ParamDecl(ParamDecl) {}
+
+ /// \brief Whether or not the parameter variable is referred only once in
+ /// the
+ /// given constructor.
+ bool hasExactlyOneUsageIn(const CXXConstructorDecl *Ctor) {
+ Count = 0;
+ TraverseDecl(const_cast<CXXConstructorDecl *>(Ctor));
+ return Count == 1;
+ }
+
+ private:
+ /// \brief Counts the number of references to a variable.
+ ///
+ /// Stops the AST traversal if more than one usage is found.
+ bool VisitDeclRefExpr(DeclRefExpr *D) {
+ if (const ParmVarDecl *To = dyn_cast<ParmVarDecl>(D->getDecl())) {
+ if (To == ParamDecl) {
+ ++Count;
+ if (Count > 1) {
+ // No need to look further, used more than once.
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ const ParmVarDecl *ParamDecl;
+ unsigned Count;
+ };
+
+ return ExactlyOneUsageVisitor(ParamDecl).hasExactlyOneUsageIn(Ctor);
+}
+
+/// \brief Find all references to \p ParamDecl across all of the
+/// redeclarations of \p Ctor.
+static SmallVector<const ParmVarDecl *, 2>
+collectParamDecls(const CXXConstructorDecl *Ctor,
+ const ParmVarDecl *ParamDecl) {
+ SmallVector<const ParmVarDecl *, 2> Results;
+ unsigned ParamIdx = ParamDecl->getFunctionScopeIndex();
+
+ for (const FunctionDecl *Redecl : Ctor->redecls())
+ Results.push_back(Redecl->getParamDecl(ParamIdx));
+ return Results;
+}
+
+PassByValueCheck::PassByValueCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeStyle(Options.get("IncludeStyle", "llvm") == "llvm" ?
+ IncludeSorter::IS_LLVM : IncludeSorter::IS_Google) {}
+
+void PassByValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle",
+ IncludeStyle == IncludeSorter::IS_LLVM ? "llvm" : "google");
+}
+
+void PassByValueCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ constructorDecl(
+ forEachConstructorInitializer(
+ ctorInitializer(
+ // Clang builds a CXXConstructExpr only whin it knows which
+ // constructor will be called. In dependent contexts a
+ // ParenListExpr is generated instead of a CXXConstructExpr,
+ // filtering out templates automatically for us.
+ withInitializer(constructExpr(
+ has(declRefExpr(to(
+ parmVarDecl(
+ hasType(qualType(
+ // Match only const-ref or a non-const value
+ // parameters. Rvalues and const-values
+ // shouldn't be modified.
+ anyOf(constRefType(), nonConstValueType()))))
+ .bind("Param")))),
+ hasDeclaration(constructorDecl(
+ isNonDeletedCopyConstructor(),
+ hasDeclContext(recordDecl(isMoveConstructible())))))))
+ .bind("Initializer")))
+ .bind("Ctor"),
+ this);
+}
+
+void PassByValueCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Inserter.reset(new IncludeInserter(Compiler.getSourceManager(),
+ Compiler.getLangOpts(), IncludeStyle));
+ Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+}
+
+void PassByValueCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("Ctor");
+ const auto *ParamDecl = Result.Nodes.getNodeAs<ParmVarDecl>("Param");
+ const auto *Initializer =
+ Result.Nodes.getNodeAs<CXXCtorInitializer>("Initializer");
+ SourceManager &SM = *Result.SourceManager;
+
+ // If the parameter is used or anything other than the copy, do not apply
+ // the changes.
+ if (!paramReferredExactlyOnce(Ctor, ParamDecl))
+ return;
+
+ auto Diag = diag(ParamDecl->getLocStart(), "pass by value and use std::move");
+
+ // Iterate over all declarations of the constructor.
+ for (const ParmVarDecl *ParmDecl : collectParamDecls(Ctor, ParamDecl)) {
+ auto ParamTL = ParmDecl->getTypeSourceInfo()->getTypeLoc();
+ auto RefTL = ParamTL.getAs<ReferenceTypeLoc>();
+
+ // Do not replace if it is already a value, skip.
+ if (RefTL.isNull())
+ continue;
+
+ TypeLoc ValueTL = RefTL.getPointeeLoc();
+ auto TypeRange = CharSourceRange::getTokenRange(ParmDecl->getLocStart(),
+ ParamTL.getLocEnd());
+ std::string ValueStr =
+ Lexer::getSourceText(
+ CharSourceRange::getTokenRange(ValueTL.getSourceRange()), SM,
+ Result.Context->getLangOpts())
+ .str();
+ ValueStr += ' ';
+ Diag << FixItHint::CreateReplacement(TypeRange, ValueStr);
+ }
+
+ // Use std::move in the initialization list.
+ Diag << FixItHint::CreateInsertion(Initializer->getRParenLoc(), ")")
+ << FixItHint::CreateInsertion(
+ Initializer->getLParenLoc().getLocWithOffset(1), "std::move(");
+
+ auto Insertion =
+ Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility",
+ /*IsAngled=*/true);
+ if (Insertion.hasValue())
+ Diag << Insertion.getValue();
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.h b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.h
new file mode 100644
index 00000000000..df9b7cccbcd
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.h
@@ -0,0 +1,39 @@
+//===--- PassByValueCheck.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_PASS_BY_VALUE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_PASS_BY_VALUE_H
+
+#include "../ClangTidy.h"
+#include "../IncludeInserter.h"
+
+#include <memory>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+class PassByValueCheck : public ClangTidyCheck {
+public:
+ PassByValueCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerPPCallbacks(clang::CompilerInstance &Compiler) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::unique_ptr<IncludeInserter> Inserter;
+ const IncludeSorter::IncludeStyle IncludeStyle;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_PASS_BY_VALUE_H
diff --git a/clang-tools-extra/clang-tidy/tool/CMakeLists.txt b/clang-tools-extra/clang-tidy/tool/CMakeLists.txt
index ea65b76d9e9..38b13ea05ee 100644
--- a/clang-tools-extra/clang-tidy/tool/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/tool/CMakeLists.txt
@@ -13,6 +13,7 @@ target_link_libraries(clang-tidy
clangTidyGoogleModule
clangTidyLLVMModule
clangTidyMiscModule
+ clangTidyModernizeModule
clangTidyReadabilityModule
clangTooling
)
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index a6d5e8b7897..0ec59934f97 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -346,6 +346,10 @@ static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination = GoogleModuleAnc
extern volatile int MiscModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED MiscModuleAnchorDestination = MiscModuleAnchorSource;
+// This anchor is used to force the linker to link the ModernizeModule.
+extern volatile int ModernizeModuleAnchorSource;
+static int ModernizeModuleAnchorDestination = ModernizeModuleAnchorSource;
+
// This anchor is used to force the linker to link the ReadabilityModule.
extern volatile int ReadabilityModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination = ReadabilityModuleAnchorSource;
diff --git a/clang-tools-extra/clang-tidy/tool/Makefile b/clang-tools-extra/clang-tidy/tool/Makefile
index f2d83ebf229..6cc9fbc2ec6 100644
--- a/clang-tools-extra/clang-tidy/tool/Makefile
+++ b/clang-tools-extra/clang-tidy/tool/Makefile
@@ -17,9 +17,9 @@ TOOL_NO_EXPORTS = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
- clangTidyMiscModule.a clangTidyReadability.a clangTidyUtils.a \
- clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
- clangStaticAnalyzerCore.a \
+ clangTidyMiscModule.a clangTidyModernizeModule.a clangTidyReadability.a \
+ clangTidyUtils.a clangStaticAnalyzerFrontend.a \
+ clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
clangFormat.a clangASTMatchers.a clangTooling.a clangToolingCore.a \
clangFrontend.a clangSerialization.a clangDriver.a clangParse.a \
clangSema.a clangAnalysis.a clangRewriteFrontend.a clangRewrite.a \
OpenPOWER on IntegriCloud