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 Index: clang-tools-extra/clang-tidy/misc/InitLocalVariablesCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/InitLocalVariablesCheck.h @@ -0,0 +1,34 @@ +//===--- 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,65 @@ +//===--- 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(unless(hasInitializer(anything()))).bind("vardecl"), this); +} + +void InitLocalVariablesCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("vardecl"); + const char *InitializationString = nullptr; + + if (!MatchedDecl->isLocalVarDecl()) + return; + + StringRef 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; + } + QualType TypePtr = MatchedDecl->getType(); + + if (TypePtr->isIntegerType()) { + InitializationString = " = 0"; + } else if (TypePtr->isFloatingType()) { + InitializationString = " = (0.0/0.0)"; // NaN without needing #includes + } else if (TypePtr->isPointerType()) { + if (getLangOpts().CPlusPlus) { + InitializationString = " = nullptr"; + } else { + InitializationString = " = NULL"; + } + } + + if (InitializationString) { + diag(MatchedDecl->getLocation(), "variable %0 is not initialized") + << MatchedDecl; + diag(MatchedDecl->getLocation(), "insert initial value", + DiagnosticIDs::Note) + << FixItHint::CreateInsertion( + MatchedDecl->getLocation().getLocWithOffset(VarName.size()), + InitializationString); + } +} + +} // namespace misc +} // namespace tidy +} // namespace clang 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( "misc-definitions-in-headers"); + CheckFactories.registerCheck( + "misc-init-local-variables"); CheckFactories.registerCheck("misc-misplaced-const"); CheckFactories.registerCheck( "misc-new-delete-overloads"); 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 + ` check. + + Checks whether there are local variables that are declared without + an initial value. + - New :doc:`objc-super-self ` check. Finds invocations of ``-self`` on super instances in initializers of 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/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 +========================= + +Checks whether there are 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/test/clang-tidy/misc-init-local-variables.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/misc-init-local-variables.cpp @@ -0,0 +1,83 @@ +// RUN: %check_clang_tidy %s misc-init-local-variables %t + +#include + +#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; + +typedef int my_int_type; +#define MACRO_INT int + +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;{{$}} + int32_t sized_var; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: variable 'sized_var' is not initialized [misc-init-local-variables] + // CHECK-FIXES: {{^}} int32_t sized_var = 0;{{$}} + my_int_type myint; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: variable 'myint' is not initialized [misc-init-local-variables] + // CHECK-FIXES: {{^}} my_int_type myint = 0;{{$}} + MACRO_INT macroint; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: variable 'macroint' is not initialized [misc-init-local-variables] + // CHECK-FIXES: {{^}} MACRO_INT macroint = 0;{{$}} + int x0 = 1, x1, x2 = 2; + // CHECK-MESSAGES: :[[@LINE-1]]:15: 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]]:19: 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(sized_var); + DO_NOTHING(myint); + DO_NOTHING(macroint); + 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); +}