- Added FixIts. This is tricky because we have to remove the parens when 
encountering
     Foo(); // Foo is a type.
  -> Foo give_me_a_name;
otherwise it'll parse as a function decl.
- Added another way of reducing false positives: If the expression is the last 
one in
the compoundStmt we don't warn, as it doesn't change behavior.

http://reviews.llvm.org/D4615

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UnusedRAII.cpp
  clang-tidy/misc/UnusedRAII.h
  test/clang-tidy/misc-unused-raii.cpp
Index: clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -6,6 +6,7 @@
   MiscTidyModule.cpp
   RedundantSmartptrGet.cpp
   SwappedArgumentsCheck.cpp
+  UnusedRAII.cpp
   UseOverride.cpp
 
   LINK_LIBS
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -14,6 +14,7 @@
 #include "BoolPointerImplicitConversion.h"
 #include "RedundantSmartptrGet.h"
 #include "SwappedArgumentsCheck.h"
+#include "UnusedRAII.h"
 #include "UseOverride.h"
 
 namespace clang {
@@ -35,6 +36,9 @@
         "misc-swapped-arguments",
         new ClangTidyCheckFactory<SwappedArgumentsCheck>());
     CheckFactories.addCheckFactory(
+        "misc-unused-raii",
+        new ClangTidyCheckFactory<UnusedRAIICheck>());
+    CheckFactories.addCheckFactory(
         "misc-use-override",
         new ClangTidyCheckFactory<UseOverride>());
   }
Index: clang-tidy/misc/UnusedRAII.cpp
===================================================================
--- /dev/null
+++ clang-tidy/misc/UnusedRAII.cpp
@@ -0,0 +1,77 @@
+//===--- UnusedRAII.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 "UnusedRAII.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace ast_matchers {
+AST_MATCHER(CXXRecordDecl, hasUserDeclaredDestructor) {
+  return Node.hasUserDeclaredDestructor();
+}
+} // namespace ast_matchers
+
+namespace tidy {
+
+void UnusedRAIICheck::registerMatchers(MatchFinder *Finder) {
+  // Look for temporaries that are constructed in-place and immediately
+  // destroyed. Look for temporaries created by a functional cast but not for
+  // those returned from a call.
+  auto BindTemp = bindTemporaryExpr(unless(has(callExpr()))).bind("temp");
+  Finder->addMatcher(
+      exprWithCleanups(
+          unless(hasAncestor(decl(
+              anyOf(recordDecl(ast_matchers::isTemplateInstantiation()),
+                    functionDecl(ast_matchers::isTemplateInstantiation()))))),
+          hasParent(compoundStmt().bind("compound")),
+          hasDescendant(typeLoc().bind("typeloc")),
+          hasType(recordDecl(hasUserDeclaredDestructor())),
+          anyOf(has(BindTemp), has(functionalCastExpr(has(BindTemp)))))
+          .bind("expr"),
+      this);
+}
+
+void UnusedRAIICheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *E = Result.Nodes.getStmtAs<Expr>("expr");
+
+  // We ignore code expanded from macros to reduce the number of false
+  // positives.
+  if (E->getLocStart().isMacroID())
+    return;
+
+  // Don't emit a warning for the last statement in the surrounding compund
+  // statement.
+  const auto *CS = Result.Nodes.getStmtAs<CompoundStmt>("compound");
+  if (E == CS->body_back())
+    return;
+
+  // Emit a warning and suggest adding a name.
+  const auto *TL = Result.Nodes.getNodeAs<TypeLoc>("typeloc");
+  auto D =
+      diag(E->getLocStart(), "object destroyed immediately after creation; did "
+                             "you mean to name the object?")
+      << FixItHint::CreateInsertion(
+          Lexer::getLocForEndOfToken(TL->getLocEnd(), 0, *Result.SourceManager,
+                                     Result.Context->getLangOpts()),
+          " give_me_a_name");
+
+  // If this is a default ctor we have to remove the parens or we'll introduce a
+  // most vexing parse.
+  const auto *BTE = Result.Nodes.getStmtAs<CXXBindTemporaryExpr>("temp");
+  if (const auto *TOE = dyn_cast<CXXTemporaryObjectExpr>(BTE->getSubExpr()))
+    if (TOE->getNumArgs() == 0)
+      D << FixItHint::CreateRemoval(
+          CharSourceRange::getTokenRange(TOE->getParenOrBraceRange()));
+}
+
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/misc/UnusedRAII.h
===================================================================
--- /dev/null
+++ clang-tidy/misc/UnusedRAII.h
@@ -0,0 +1,47 @@
+//===--- UnusedRAII.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_UNUSED_RAII_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_RAII_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// \brief Finds temporaries that look like RAII objects.
+///
+/// The canonical example for this is a scoped lock.
+/// \code
+///   {
+///     scoped_lock(&global_mutex);
+///     critical_section();
+///   }
+/// \endcode
+/// The destructor of the scoped_lock is called before the critical_section is
+/// entered, leaving it unprotected.
+///
+/// We apply a number of heuristics to reduce the false positive count of this
+/// check:
+///   - Ignore code expanded from macros. Testing frameworks make heavy use of
+///     this.
+///   - Ignore types with no user-declared constructor. Those are very unlikely
+///     to be RAII objects.
+///   - Ignore objects at the end of a compound statement (doesn't change behavior)
+///   - Ignore objects returned from a call.
+class UnusedRAIICheck : public ClangTidyCheck {
+public:
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_RAII_H
Index: test/clang-tidy/misc-unused-raii.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/misc-unused-raii.cpp
@@ -0,0 +1,45 @@
+// RUN: $(dirname %s)/check_clang_tidy_fix.sh %s misc-unused-raii %t
+// REQUIRES: shell
+
+struct Foo {
+  Foo();
+  Foo(int);
+  ~Foo();
+};
+
+struct Bar {
+  Bar();
+  Foo f;
+};
+
+template <typename T>
+void qux() {
+  T(42);
+}
+
+template <typename T>
+struct TFoo {
+  TFoo(T);
+  ~TFoo();
+};
+
+Foo f();
+
+void test() {
+  Foo(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: Foo give_me_a_name(42);
+  Foo();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: Foo give_me_a_name;
+  TFoo<int>(23);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: TFoo<int> give_me_a_name(23);
+
+  Bar();
+  f();
+  qux<Foo>();
+
+#define M Foo();
+  M
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to