jpakkane created this revision.
jpakkane added a reviewer: alexfh.
Herald added subscribers: cfe-commits, mgorny.
Herald added a project: clang.

This checks finds all primitive type local variables (integers, doubles, 
pointers) that are declared without an initial value. Includes fixit 
functionality to initialize said variables with a default value. This is zero 
for most types and NaN for floating point types. The use of NaNs is copied from 
the D programming language.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D64671

Files:
  clang-tools-extra/clang-tidy/misc/CMakeLists.txt
  clang-tools-extra/clang-tidy/misc/InitLocalVariablesCheck.cpp
  clang-tools-extra/clang-tidy/misc/InitLocalVariablesCheck.h
  clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/misc-init-local-variables.rst
  clang-tools-extra/test/clang-tidy/misc-init-local-variables.cpp

Index: clang-tools-extra/test/clang-tidy/misc-init-local-variables.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/misc-init-local-variables.cpp
@@ -0,0 +1,68 @@
+// RUN: %check_clang_tidy %s misc-init-local-variables %t
+
+#define DO_NOTHING(x) ((void)x)
+
+// Ensure that function declarations are not changed.
+void some_func(int x, double d, bool b, const char *p);
+
+int do_not_modify_me;
+
+typedef struct {
+  int unaltered1;
+  int unaltered2;
+} UnusedStruct;
+
+
+void init_unit_tests() {
+  int x;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'x' is not initialized [misc-init-local-variables]
+// CHECK-FIXES: {{^}}  int x=0;{{$}}
+  int x0=1, x1, x2=2;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: variable 'x1' is not initialized [misc-init-local-variables]
+// CHECK-FIXES: {{^}}  int x0=1, x1=0, x2=2;{{$}}
+  int y0, y1=1, y2;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'y0' is not initialized [misc-init-local-variables]
+// CHECK-MESSAGES: :[[@LINE-2]]:17: warning: variable 'y2' is not initialized [misc-init-local-variables]
+// CHECK-FIXES: {{^}}  int y0=0, y1=1, y2=0;{{$}}
+  int hasval = 42;
+
+  float f;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: variable 'f' is not initialized [misc-init-local-variables]
+// CHECK-FIXES: {{^}}  float f=(0.0/0.0);{{$}}
+  float fval = 85.0;
+  double d;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: variable 'd' is not initialized [misc-init-local-variables]
+// CHECK-FIXES: {{^}}  double d=(0.0/0.0);{{$}}
+  double dval = 99.0;
+
+  bool b;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: variable 'b' is not initialized [misc-init-local-variables]
+// CHECK-FIXES: {{^}}  bool b=0;{{$}}
+  bool bval = true;
+
+  const char *ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: variable 'ptr' is not initialized [misc-init-local-variables]
+// CHECK-FIXES: {{^}}  const char *ptr=nullptr;{{$}}
+  const char *ptrval = "a string";
+
+  UnusedStruct u;
+
+  DO_NOTHING(x);
+  DO_NOTHING(x0);
+  DO_NOTHING(x1);
+  DO_NOTHING(x2);
+  DO_NOTHING(y0);
+  DO_NOTHING(y1);
+  DO_NOTHING(y2);
+  DO_NOTHING(hasval);
+  DO_NOTHING(f);
+  DO_NOTHING(fval);
+  DO_NOTHING(d);
+  DO_NOTHING(dval);
+  DO_NOTHING(b);
+  DO_NOTHING(bval);
+  DO_NOTHING(ptr);
+  DO_NOTHING(ptrval);
+  DO_NOTHING(u);
+}
+
Index: clang-tools-extra/docs/clang-tidy/checks/misc-init-local-variables.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/misc-init-local-variables.rst
@@ -0,0 +1,36 @@
+.. title:: clang-tidy - misc-init-local-variables
+
+misc-init-local-variables
+=========================
+
+Finds local variables that are declared without an initial
+value. These may lead to unexpected behaviour if there is a code path
+that reads the variable before assigning to it.
+
+Only integers, booleans, floats, doubles and pointers are checked. The
+fix option initializes all detected values with the value of zero. An
+exception is float and double types, which are initialized to NaN.
+
+As an example a function that looks like this:
+
+.. code-block:: c++
+
+   void function() {
+     int x;
+     char *txt;
+     double d;
+
+     // Rest of the function.
+   }
+
+Would be rewritten to look like this:
+
+.. code-block:: c++
+
+   void function() {
+     int x=0;
+     char *txt=nullptr;
+     double d=(0.0/0.0);
+
+     // Rest of the function.
+   }
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -189,6 +189,7 @@
    llvm-prefer-isa-or-dyn-cast-in-conditionals
    llvm-twine-local
    misc-definitions-in-headers
+   misc-init-local-variables
    misc-misplaced-const
    misc-new-delete-overloads
    misc-non-copyable-objects
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -158,6 +158,12 @@
   Checks for calls to ``+new`` or overrides of it, which are prohibited by the
   Google Objective-C style guide.
 
+- New :doc:`misc-init-local-variables
+  <clang-tidy/checks/misc-init-local-variables>` check.
+
+  Checks whether there are local variables that are declared without
+  an initial value.
+
 - New :doc:`objc-super-self <clang-tidy/checks/objc-super-self>` check.
 
   Finds invocations of ``-self`` on super instances in initializers of
Index: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -10,6 +10,7 @@
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
 #include "DefinitionsInHeadersCheck.h"
+#include "InitLocalVariablesCheck.h"
 #include "MisplacedConstCheck.h"
 #include "NewDeleteOverloadsCheck.h"
 #include "NonCopyableObjects.h"
@@ -32,6 +33,8 @@
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
     CheckFactories.registerCheck<DefinitionsInHeadersCheck>(
         "misc-definitions-in-headers");
+    CheckFactories.registerCheck<InitLocalVariablesCheck>(
+        "misc-init-local-variables");
     CheckFactories.registerCheck<MisplacedConstCheck>("misc-misplaced-const");
     CheckFactories.registerCheck<NewDeleteOverloadsCheck>(
         "misc-new-delete-overloads");
Index: clang-tools-extra/clang-tidy/misc/InitLocalVariablesCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/misc/InitLocalVariablesCheck.h
@@ -0,0 +1,35 @@
+//===--- InitLocalVariablesCheck.h - clang-tidy -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_INITLOCALVARIABLESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_INITLOCALVARIABLESCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Find uninitialized local variables.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-init-local-variables.html
+class InitLocalVariablesCheck : public ClangTidyCheck {
+public:
+  InitLocalVariablesCheck(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_INITLOCALVARIABLESCHECK_H
Index: clang-tools-extra/clang-tidy/misc/InitLocalVariablesCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/misc/InitLocalVariablesCheck.cpp
@@ -0,0 +1,62 @@
+//===--- InitLocalVariablesCheck.cpp - clang-tidy -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "InitLocalVariablesCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void InitLocalVariablesCheck::registerMatchers(MatchFinder *Finder) {
+    Finder->addMatcher(varDecl().bind("vardecl"), this);
+}
+
+void InitLocalVariablesCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("vardecl");
+  const char *replacement = nullptr;
+
+  if(!MatchedDecl->isLocalVarDecl())
+    return;
+  if(MatchedDecl->hasInit())
+    return;
+
+  auto varName = MatchedDecl->getName();
+  if(varName.empty() || varName.front() == '_') {
+    // Some standard library methods such as "be64toh" are implemented
+    // as macros that internally use variable names
+    // like __v. Do not touch those.
+    return;
+  }
+  auto typePtr = MatchedDecl->getType();
+
+  if(typePtr->isIntegerType()) {
+    replacement = "=0";
+  } else if(typePtr->isFloatingType()) {
+    replacement = "=(0.0/0.0)"; // NaN without needing #includes
+  } else if(typePtr->isPointerType()) {
+    if(getLangOpts().CPlusPlus) {
+      replacement = "=nullptr";
+    } else {
+      replacement = "=NULL";
+    }
+  }
+
+  if(replacement) {
+    diag(MatchedDecl->getLocation(), "variable %0 is not initialized")
+      << MatchedDecl;
+    diag(MatchedDecl->getLocation(), "insert initial value", DiagnosticIDs::Note)
+      << FixItHint::CreateInsertion(MatchedDecl->getLocation().getLocWithOffset(varName.size()), replacement);
+  }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -2,6 +2,7 @@
 
 add_clang_library(clangTidyMiscModule
   DefinitionsInHeadersCheck.cpp
+  InitLocalVariablesCheck.cpp
   MiscTidyModule.cpp
   MisplacedConstCheck.cpp
   NewDeleteOverloadsCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to