Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -2,6 +2,7 @@ add_clang_library(clangTidyMiscModule MisplacedConstCheck.cpp + OwnerlessResourceCheck.cpp UnconventionalAssignOperatorCheck.cpp DefinitionsInHeadersCheck.cpp MacroParenthesesCheck.cpp Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -15,6 +15,7 @@ #include "MisplacedConstCheck.h" #include "NewDeleteOverloadsCheck.h" #include "NonCopyableObjects.h" +#include "OwnerlessResourceCheck.h" #include "RedundantExpressionCheck.h" #include "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" @@ -35,6 +36,8 @@ public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck("misc-misplaced-const"); + CheckFactories.registerCheck( + "misc-ownerless-resource"); CheckFactories.registerCheck( "misc-unconventional-assign-operator"); CheckFactories.registerCheck( Index: clang-tidy/misc/OwnerlessResourceCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/OwnerlessResourceCheck.h @@ -0,0 +1,35 @@ +//===--- OwnerlessResourceCheck.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_MISC_OWNERLESSRESOURCECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OWNERLESSRESOURCECHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Diagnoses when a non-trivial type is not assigned to a variable. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-ownerless-resource.html +class OwnerlessResourceCheck : public ClangTidyCheck { +public: + OwnerlessResourceCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OWNERLESSRESOURCECHECK_H Index: clang-tidy/misc/OwnerlessResourceCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/OwnerlessResourceCheck.cpp @@ -0,0 +1,37 @@ +//===--- OwnerlessResourceCheck.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 "OwnerlessResourceCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void OwnerlessResourceCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + exprWithCleanups(unless(hasType(voidType())), + has(cxxBindTemporaryExpr(has(cxxTemporaryObjectExpr())))) + .bind("ownerless-resource"), + this); +} + +void OwnerlessResourceCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *E = Result.Nodes.getNodeAs("ownerless-resource")) { + diag(E->getLocStart(), "Resource has no owner; Did you mean to declare it " + "with a variable name?"); + } +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,12 @@ Improvements to clang-tidy -------------------------- +- New `misc-ownerless-resource + `_ check + + Diagnoses when a non-trivial type is not assigned to a variable. This is + useful to check for problems like unamed lock guards. + - New `bugprone-throw-keyword-missing `_ check Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -143,6 +143,7 @@ misc-misplaced-const misc-new-delete-overloads misc-non-copyable-objects + misc-ownerless-resource misc-redundant-expression misc-sizeof-container misc-sizeof-expression Index: docs/clang-tidy/checks/misc-ownerless-resource.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-ownerless-resource.rst @@ -0,0 +1,34 @@ +.. title:: clang-tidy - misc-ownerless-resource + +misc-ownerless-resource +======================= + +Diagnoses when a non-trivial type is not assigned to a variable. This is useful to check for problems like unamed lock guards. + +For example, if you had code written like this: + +.. code-block:: c++ + + int g_i = 0; + std::mutex g_i_mutex; // protects g_i + + void safe_increment() + { + std::lock_guard{g_i_mutex}; + // The lock is locked and then unlocked before reaching here + ++g_i; + } + +This will warn that a variable should be created instead: + +.. code-block:: c++ + + int g_i = 0; + std::mutex g_i_mutex; // protects g_i + + void safe_increment() + { + std::lock_guard lock{g_i_mutex}; + // The lock is locked and then will be unlocked when exiting scope + ++g_i; + } Index: test/clang-tidy/misc-ownerless-resource.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-ownerless-resource.cpp @@ -0,0 +1,36 @@ +// RUN: %check_clang_tidy %s misc-ownerless-resource %t + +struct Trivial {}; + +struct NonTrivial { + int *mem; + NonTrivial() + : mem(new int()) {} + NonTrivial(int) + : mem(new int()) {} + ~NonTrivial() { + delete mem; + } +}; + +NonTrivial f() { return {}; } +void g(NonTrivial) {} + +void fail() { + NonTrivial{}; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Resource has no owner; Did you mean to declare it with a variable name? [misc-ownerless-resource] + NonTrivial{1}; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Resource has no owner; Did you mean to declare it with a variable name? [misc-ownerless-resource] +} + +void valid() { + NonTrivial a{}; + auto b = NonTrivial{}; + + g(f()); + f(); + + auto c = f(); + Trivial{}; + Trivial x{}; +}