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/modernize/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp145
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.h50
4 files changed, 199 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index cfacc952faa..bb5c0aebb66 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -26,6 +26,7 @@ add_clang_library(clangTidyModernizeModule
UseEmplaceCheck.cpp
UseEqualsDefaultCheck.cpp
UseEqualsDeleteCheck.cpp
+ UseNodiscardCheck.cpp
UseNoexceptCheck.cpp
UseNullptrCheck.cpp
UseOverrideCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 6bad6cbefa9..fcf535b76ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -32,6 +32,7 @@
#include "UseEmplaceCheck.h"
#include "UseEqualsDefaultCheck.h"
#include "UseEqualsDeleteCheck.h"
+#include "UseNodiscardCheck.h"
#include "UseNoexceptCheck.h"
#include "UseNullptrCheck.h"
#include "UseOverrideCheck.h"
@@ -82,6 +83,8 @@ public:
CheckFactories.registerCheck<UseEqualsDefaultCheck>("modernize-use-equals-default");
CheckFactories.registerCheck<UseEqualsDeleteCheck>(
"modernize-use-equals-delete");
+ CheckFactories.registerCheck<UseNodiscardCheck>(
+ "modernize-use-nodiscard");
CheckFactories.registerCheck<UseNoexceptCheck>("modernize-use-noexcept");
CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp
new file mode 100644
index 00000000000..69e1734075c
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp
@@ -0,0 +1,145 @@
+//===--- UseNodiscardCheck.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 "UseNodiscardCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static bool doesNoDiscardMacroExist(ASTContext &Context,
+ const llvm::StringRef &MacroId) {
+ // Don't check for the Macro existence if we are using an attribute
+ // either a C++17 standard attribute or pre C++17 syntax
+ if (MacroId.startswith("[[") || MacroId.startswith("__attribute__"))
+ return true;
+
+ // Otherwise look up the macro name in the context to see if its defined.
+ return Context.Idents.get(MacroId).hasMacroDefinition();
+}
+
+namespace {
+AST_MATCHER(CXXMethodDecl, isOverloadedOperator) {
+ // Don't put ``[[nodiscard]]`` in front of operators.
+ return Node.isOverloadedOperator();
+}
+AST_MATCHER(CXXMethodDecl, isConversionOperator) {
+ // Don't put ``[[nodiscard]]`` in front of a conversion decl
+ // like operator bool().
+ return isa<CXXConversionDecl>(Node);
+}
+AST_MATCHER(CXXMethodDecl, hasClassMutableFields) {
+ // Don't put ``[[nodiscard]]`` on functions on classes with
+ // mutable member variables.
+ return Node.getParent()->hasMutableFields();
+}
+AST_MATCHER(ParmVarDecl, hasParameterPack) {
+ // Don't put ``[[nodiscard]]`` on functions with parameter pack arguments.
+ return Node.isParameterPack();
+}
+AST_MATCHER(CXXMethodDecl, hasTemplateReturnType) {
+ // Don't put ``[[nodiscard]]`` in front of functions returning a template
+ // type.
+ return Node.getReturnType()->isTemplateTypeParmType() ||
+ Node.getReturnType()->isInstantiationDependentType();
+}
+AST_MATCHER(CXXMethodDecl, isDefinitionOrInline) {
+ // A function definition, with optional inline but not the declaration.
+ return !(Node.isThisDeclarationADefinition() && Node.isOutOfLine());
+}
+AST_MATCHER(QualType, isInstantiationDependentType) {
+ return Node->isInstantiationDependentType();
+}
+AST_MATCHER(QualType, isNonConstReferenceOrPointer) {
+ // If the function has any non-const-reference arguments
+ // bool foo(A &a)
+ // or pointer arguments
+ // bool foo(A*)
+ // then they may not care about the return value because of passing data
+ // via the arguments.
+ return (Node->isTemplateTypeParmType() || Node->isPointerType() ||
+ (Node->isReferenceType() &&
+ !Node.getNonReferenceType().isConstQualified()) ||
+ Node->isInstantiationDependentType());
+}
+} // namespace
+
+UseNodiscardCheck::UseNodiscardCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ NoDiscardMacro(Options.get("ReplacementString", "[[nodiscard]]")) {}
+
+void UseNodiscardCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ReplacementString", NoDiscardMacro);
+}
+
+void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) {
+ // If we use ``[[nodiscard]]`` attribute, we require at least C++17. Use a
+ // macro or ``__attribute__`` with pre c++17 compilers by using
+ // ReplacementString option.
+ if ((NoDiscardMacro == "[[nodiscard]]" && !getLangOpts().CPlusPlus17) ||
+ !getLangOpts().CPlusPlus)
+ return;
+
+ auto functionObj =
+ cxxRecordDecl(hasAnyName("::std::function", "::boost::function"));
+
+ // Find all non-void const methods which have not already been marked to
+ // warn on unused result.
+ Finder->addMatcher(
+ cxxMethodDecl(
+ allOf(isConst(), isDefinitionOrInline(),
+ unless(anyOf(
+ returns(voidType()), isNoReturn(), isOverloadedOperator(),
+ isVariadic(), hasTemplateReturnType(),
+ hasClassMutableFields(), isConversionOperator(),
+ hasAttr(clang::attr::WarnUnusedResult),
+ hasType(isInstantiationDependentType()),
+ hasAnyParameter(anyOf(
+ parmVarDecl(anyOf(hasType(functionObj),
+ hasType(references(functionObj)))),
+ hasType(isNonConstReferenceOrPointer()),
+ hasParameterPack()))))))
+ .bind("no_discard"),
+ this);
+}
+
+void UseNodiscardCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("no_discard");
+ // Don't make replacements if the location is invalid or in a macro.
+ SourceLocation Loc = MatchedDecl->getLocation();
+ if (Loc.isInvalid() || Loc.isMacroID())
+ return;
+
+ SourceLocation retLoc = MatchedDecl->getInnerLocStart();
+
+ ASTContext &Context = *Result.Context;
+
+ auto Diag = diag(retLoc, "function %0 should be marked " + NoDiscardMacro)
+ << MatchedDecl;
+
+ // Check for the existence of the keyword being used as the ``[[nodiscard]]``.
+ if (!doesNoDiscardMacroExist(Context, NoDiscardMacro))
+ return;
+
+ // Possible false positives include:
+ // 1. A const member function which returns a variable which is ignored
+ // but performs some external I/O operation and the return value could be
+ // ignored.
+ Diag << FixItHint::CreateInsertion(retLoc, NoDiscardMacro + " ");
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.h b/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.h
new file mode 100644
index 00000000000..00563e7f0bd
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.h
@@ -0,0 +1,50 @@
+//===--- UseNodiscardCheck.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_USENODISCARDCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USENODISCARDCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// \brief Add ``[[nodiscard]]`` to non-void const-member functions with no
+/// arguments or pass-by-value or pass by const-reference arguments.
+/// \code
+/// bool empty() const;
+/// bool empty(const Bar &) const;
+/// bool empty(int bar) const;
+/// \endcode
+/// Is converted to:
+/// \code
+/// [[nodiscard]] bool empty() const;
+/// [[nodiscard]] bool empty(const Bar &) const;
+/// [[nodiscard]] bool empty(int bar) const;
+/// \endcode
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-nodiscard.html
+class UseNodiscardCheck : public ClangTidyCheck {
+public:
+ UseNodiscardCheck(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:
+ const std::string NoDiscardMacro;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USENODISCARDCHECK_H
OpenPOWER on IntegriCloud