diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidNonConstGlobalVariablesCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidNonConstGlobalVariablesCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidNonConstGlobalVariablesCheck.h @@ -0,0 +1,35 @@ +//===--- AvoidNonConstGlobalVariablesCheck.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_CPPCOREGUIDELINES_AVOIDNONCONSTGLOBALVARIABLESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDNONCONSTGLOBALVARIABLESCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +/// Non-const global variables hide dependencies and make the dependencies +/// subject to unpredictable changes. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-avoid-non-const-global-variables.html +class AvoidNonConstGlobalVariablesCheck : public ClangTidyCheck { +public: + AvoidNonConstGlobalVariablesCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDNONCONSTGLOBALVARIABLESCHECK_H diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidNonConstGlobalVariablesCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidNonConstGlobalVariablesCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidNonConstGlobalVariablesCheck.cpp @@ -0,0 +1,45 @@ +//===--- AvoidNonConstGlobalVariablesCheck.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 "AvoidNonConstGlobalVariablesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +namespace { +AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); } +} // namespace + +void AvoidNonConstGlobalVariablesCheck::registerMatchers(MatchFinder *Finder) { + auto loop = stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt())); + Finder->addMatcher(varDecl(unless(isLocalVarDecl()), + unless(hasAncestor(namespaceDecl(isAnonymous()))), + unless(isConstexpr()), + unless(hasType(isConstQualified()))) + .bind("non-const"), + this); +} + +void AvoidNonConstGlobalVariablesCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("non-const"); + + diag(MatchedDecl->getLocation(), "variable %0 is non-const and global") + << MatchedDecl; + diag(MatchedDecl->getLocation(), "insert 'const '", DiagnosticIDs::Note) + << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "const "); +} + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -2,6 +2,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule AvoidGotoCheck.cpp + AvoidNonConstGlobalVariablesCheck.cpp CppCoreGuidelinesTidyModule.cpp InitVariablesCheck.cpp InterfacesGlobalInitCheck.cpp diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -15,6 +15,7 @@ #include "../modernize/UseOverrideCheck.h" #include "../readability/MagicNumbersCheck.h" #include "AvoidGotoCheck.h" +#include "AvoidNonConstGlobalVariablesCheck.h" #include "InitVariablesCheck.h" #include "InterfacesGlobalInitCheck.h" #include "MacroUsageCheck.h" @@ -48,6 +49,8 @@ "cppcoreguidelines-avoid-goto"); CheckFactories.registerCheck( "cppcoreguidelines-avoid-magic-numbers"); + CheckFactories.registerCheck( + "cppcoreguidelines-avoid-non-const-global-variables"); CheckFactories.registerCheck( "cppcoreguidelines-explicit-virtual-functions"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -94,6 +94,9 @@ Without the null terminator it can result in undefined behaviour when the string is read. +- New :doc:`cppcoreguidelines-avoid-non-const-global-variables + ` check. + - New alias :doc:`cert-pos44-c ` to :doc:`bugprone-bad-signal-to-kill-thread diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-non-const-global-variables.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-non-const-global-variables.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-non-const-global-variables.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - cppcoreguidelines-avoid-non-const-global-variables + +cppcoreguidelines-avoid-non-const-global-variables +================================================== + +FIXME: Describe what patterns does the check detect and why. Give examples. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -194,6 +194,7 @@ cppcoreguidelines-avoid-c-arrays (redirects to modernize-avoid-c-arrays) cppcoreguidelines-avoid-goto cppcoreguidelines-avoid-magic-numbers (redirects to readability-magic-numbers) + cppcoreguidelines-avoid-non-const-global-variables cppcoreguidelines-c-copy-assignment-signature (redirects to misc-unconventional-assign-operator) cppcoreguidelines-explicit-virtual-functions (redirects to modernize-use-override) cppcoreguidelines-init-variables diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-non-const-global-variables.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-non-const-global-variables.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-non-const-global-variables.cpp @@ -0,0 +1,35 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-non-const-global-variables %t + +int nonConstVariable = 0; +// CHECK-MESSAGES: warning: variable 'nonConstVariable' is non-const and global [cppcoreguidelines-avoid-non-const-global-variables] +// CHECK-FIXES: int const nonConstVariable = 0; + +namespace namespace_name { +int nonConstNamespaceVariable = 0; +// CHECK-MESSAGES: warning: variable 'nonConstNamespaceVariable' is non-const and global [cppcoreguidelines-avoid-non-const-global-variables] +// CHECK-FIXES: int const nonConstNamespaceVariable = 0; +} // namespace namespace_name + +const int constVariable = 0; + +constexpr int constexprVariable = 0; + +int function() { + int nonConstReturnValue = 0; + return nonConstReturnValue; +} + +namespace { +int nonConstAnonymousNamespaceVariable = 0; +} + +class Class { + int nonConstMemberVariable = 0; +}; + +int main() { + for (int i = 0; i < 10; ++i) { + int nonConstLoopVariable = 42; + nonConstVariable = nonConstLoopVariable + i; + } +} \ No newline at end of file