mgartmann updated this revision to Diff 344030.
mgartmann added a comment.
Change encoding of patch to UTF-8 in order to fix build.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D99646/new/
https://reviews.llvm.org/D99646
Files:
clang-tools-extra/clang-tidy/misc/AvoidStdIoOutsideMainCheck.cpp
clang-tools-extra/clang-tidy/misc/AvoidStdIoOutsideMainCheck.h
clang-tools-extra/clang-tidy/misc/CMakeLists.txt
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-avoid-std-io-outside-main.rst
clang-tools-extra/test/clang-tidy/checkers/misc-avoid-std-io-outside-main.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/misc-avoid-std-io-outside-main.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/misc-avoid-std-io-outside-main.cpp
@@ -0,0 +1,138 @@
+// RUN: %check_clang_tidy %s misc-avoid-std-io-outside-main %t
+
+namespace std {
+struct string {
+ string(const char *);
+ ~string();
+};
+
+struct Ostream {
+ Ostream &operator<<(string Message);
+};
+
+struct Istream {
+ Istream &operator>>(string Message);
+};
+
+Ostream cout{}, wcout{}, cerr{}, wcerr{};
+Istream cin{}, wcin{};
+
+int printf(const char *Format, ...);
+int vprintf(const char *const, ...);
+int puts(const char *Str);
+int putchar(int Character);
+int scanf(const char *Format, ...);
+int getchar(void);
+char *gets(char *Str);
+} // namespace std
+
+int printf(const char *Format, ...);
+int vprintf(const char *const, ...);
+int puts(const char *Str);
+int putchar(int Character);
+int scanf(const char *Format, ...);
+int getchar(void);
+char *gets(char *Str);
+
+namespace arbitrary_namespace {
+std::Ostream cout{};
+std::Istream cin{};
+} // namespace arbitrary_namespace
+
+void anyNonMainFunction() {
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: predefined standard stream objects should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::cout << "This should trigger the check";
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: predefined standard stream objects should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::wcout << "This should trigger the check";
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: predefined standard stream objects should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::cerr << "This should trigger the check";
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: predefined standard stream objects should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::wcerr << "This should trigger the check";
+
+ arbitrary_namespace::cout << "This should not trigger the check"; // OK
+
+ std::string Foo{"bar"};
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: predefined standard stream objects should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::cin >> Foo;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: predefined standard stream objects should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::wcin >> Foo;
+
+ arbitrary_namespace::cin >> Foo; // OK
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::printf("This should trigger the check");
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ printf("This should trigger the check");
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::puts("This should trigger the check");
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ puts("This should trigger the check");
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::putchar('m');
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ putchar('m');
+
+ char Input[5];
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::scanf("%s", Input);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ scanf("%s", Input);
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::getchar();
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ getchar();
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::gets(Input);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ gets(Input);
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ std::vprintf("This should trigger the check %d", 1);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ vprintf("This should trigger the check %d", 1);
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:17: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ auto Print = &puts;
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: cstdio functions should not be used outside the main function [misc-avoid-std-io-outside-main]
+ Print("This should trigger the check");
+}
+
+int main() {
+ std::cout << "This should not trigger the check"; // OK
+ std::wcout << "This should not trigger the check"; // OK
+ std::cerr << "This should not trigger the check"; // OK
+ std::wcerr << "This should not trigger the check"; // OK
+ arbitrary_namespace::cout << "This should not trigger the check"; // OK
+
+ std::string Foo{"bar"};
+ std::cin >> Foo; // OK
+ std::wcin >> Foo; // OK
+ arbitrary_namespace::cin >> Foo; // OK
+
+ char Input[5];
+ std::printf("This should not trigger the check"); // OK
+ std::puts("This should not trigger the check"); // OK
+ std::putchar('m'); // OK
+ std::scanf("%s", Input); // OK
+ std::getchar(); // OK
+ std::gets(Input); // OK
+ std::vprintf("This should not trigger the check %d", 1); // OK
+ printf("This should not trigger the check"); // OK
+ puts("This should not trigger the check"); // OK
+ putchar('m'); // OK
+ scanf("%s", Input); // OK
+ getchar(); // OK
+ gets(Input); // OK
+ vprintf("This should not trigger the check %d", 1); // OK
+ auto Print = &puts; // OK
+ Print("This should not trigger the check"); // OK
+}
Index: clang-tools-extra/docs/clang-tidy/checks/misc-avoid-std-io-outside-main.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/misc-avoid-std-io-outside-main.rst
@@ -0,0 +1,53 @@
+.. title:: clang-tidy - misc-avoid-std-io-outside-main
+
+misc-avoid-std-io-outside-main
+=============
+
+Diagnoses if a predefined standard stream object (``cin``, ``wcin``,
+``cout``, ``wcout``, ``cerr`` or ``wcerr``) or a ``cstdio``/``stdio.h``
+function is used outside the ``main`` function.
+
+For instance, in the following code, the use of ``std::cout`` and ``printf()``
+outside of ``main()`` would get flagged whereas the use of them inside
+``main()`` is not flagged:
+
+.. code-block:: c++
+
+ #include <iostream>
+ #include <cstdio>
+
+ void some_function() {
+ std::cout << "This triggers the check.";
+ ~~~~
+ std::printf("This triggers the check.");
+ ~~~~~
+ }
+
+ int main() {
+ std::cout << "This does not trigger the check.";
+ std::printf("This does not trigger the check.");
+ }
+
+Since the predefined standard stream objects are global objects, their use
+outside of ``main()`` worsens a program's testability and is thus discouraged.
+Instead, those objects should only be used inside ``main()``. They can then be
+passed as arguments to other functions like so:
+
+.. code-block:: c++
+
+ #include <iostream>
+
+ void some_function(std::istream & in, std::ostream & out) {
+ out << "This does not trigger the check.";
+
+ int i{0};
+ in >> i;
+ }
+
+ int main() {
+ some_function(std::cin, std::cout);
+ }
+
+In contrast to using ``std::cin`` and ``std::cout`` directly, in the above
+example, it is possible to inject mocked stream objects into
+``some_function()`` during testing.
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
@@ -202,6 +202,7 @@
`llvmlibc-callee-namespace <llvmlibc-callee-namespace.html>`_,
`llvmlibc-implementation-in-namespace <llvmlibc-implementation-in-namespace.html>`_,
`llvmlibc-restrict-system-libc-headers <llvmlibc-restrict-system-libc-headers.html>`_, "Yes"
+ `misc-misc-avoid-std-io-outside-main <misc-avoid-std-io-outside-main.html>`_, "Yes"
`misc-definitions-in-headers <misc-definitions-in-headers.html>`_, "Yes"
`misc-misplaced-const <misc-misplaced-const.html>`_,
`misc-new-delete-overloads <misc-new-delete-overloads.html>`_,
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -95,6 +95,14 @@
Finds member initializations in the constructor body which can be placed into
the initialization list instead.
+- New :doc:`misc-avoid-std-io-outside-main
+ <clang-tidy/checks/misc-avoid-std-io-outside-main>` check.
+
+ Flags if a predefined standard stream object (``cin``, ``wcin``, ``cout``,
+ ``wcout``, ``cerr`` or ``wcerr``) is used outside the ``main`` function.
+ It also flags uses of uses of ``cstdio``/``stdio.h`` functions like
+ ``printf()`` outside the ``main`` function.
+
New check aliases
^^^^^^^^^^^^^^^^^
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
@@ -9,6 +9,7 @@
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
+#include "AvoidStdIoOutsideMainCheck.h"
#include "DefinitionsInHeadersCheck.h"
#include "MisplacedConstCheck.h"
#include "NewDeleteOverloadsCheck.h"
@@ -31,6 +32,8 @@
class MiscModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<AvoidStdIoOutsideMainCheck>(
+ "misc-avoid-std-io-outside-main");
CheckFactories.registerCheck<DefinitionsInHeadersCheck>(
"misc-definitions-in-headers");
CheckFactories.registerCheck<MisplacedConstCheck>("misc-misplaced-const");
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
@@ -4,6 +4,7 @@
)
add_clang_library(clangTidyMiscModule
+ AvoidStdIoOutsideMainCheck.cpp
DefinitionsInHeadersCheck.cpp
MiscTidyModule.cpp
MisplacedConstCheck.cpp
Index: clang-tools-extra/clang-tidy/misc/AvoidStdIoOutsideMainCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/misc/AvoidStdIoOutsideMainCheck.h
@@ -0,0 +1,49 @@
+//===--- AvoidStdIoOutsideMainCheck.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_AVOIDSTDIOOUTSIDEMAINCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_AVOIDSTDIOOUTSIDEMAINCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Diagnoses if a predefined standard stream object (`cin`, `wcin`,
+/// `cout`, `wcout`, `cerr` or `wcerr`) is used outside the `main` function.
+/// It also flags uses of uses of `cstdio`/`stdio.h` functions like `printf()`
+/// outside the `main` function.
+///
+/// For the user-facing documentation and examples see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-avoid-std-io-outside-main.html
+class AvoidStdIoOutsideMainCheck : public ClangTidyCheck {
+public:
+ AvoidStdIoOutsideMainCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const std::vector<std::string> StdIOStreams = {"cin", "wcin", "cout",
+ "wcout", "cerr", "wcerr"};
+ const std::vector<std::string> CLikeIOFunctions = {
+ "printf", "vprintf", "puts", "putchar", "scanf", "getchar", "gets"};
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_AVOIDSTDIOOUTSIDEMAINCHECK_H
Index: clang-tools-extra/clang-tidy/misc/AvoidStdIoOutsideMainCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/misc/AvoidStdIoOutsideMainCheck.cpp
@@ -0,0 +1,70 @@
+//===--- AvoidStdIoOutsideMainCheck.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 "AvoidStdIoOutsideMainCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void AvoidStdIoOutsideMainCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ declRefExpr(to(varDecl(hasAnyName(SmallVector<StringRef>(
+ StdIOStreams.begin(), StdIOStreams.end())),
+ isInStdNamespace())),
+ unless(forFunction(isMain())))
+ .bind("StdStreamObject"),
+ this);
+
+ Finder->addMatcher(
+ declRefExpr(hasDeclaration(functionDecl(hasAnyName(SmallVector<StringRef>(
+ CLikeIOFunctions.begin(), CLikeIOFunctions.end())))),
+ unless(forFunction(isMain())))
+ .bind("CLibFunction"),
+ this);
+
+ /// Matcher for indirect stdio uses:
+ /// \code
+ /// auto Print = &puts;
+ /// Print("This is using stdio");
+ /// \endcode
+ Finder->addMatcher(
+ declRefExpr(
+ hasDeclaration(varDecl(hasDescendant(declRefExpr(hasDeclaration(
+ functionDecl(hasAnyName("printf", "vprintf", "puts", "putchar",
+ "scanf", "getchar", "gets"))))))),
+ unless(forFunction(isMain())))
+ .bind("CLibFunction"),
+ this);
+}
+
+void AvoidStdIoOutsideMainCheck::check(const MatchFinder::MatchResult &Result) {
+
+ if (const auto *MatchedStreamObj =
+ Result.Nodes.getNodeAs<DeclRefExpr>("StdStreamObject")) {
+ diag(MatchedStreamObj->getLocation(),
+ "predefined standard stream objects should "
+ "not be used outside the main function");
+ return;
+ }
+
+ if (const auto *MatchedCLibFunc =
+ Result.Nodes.getNodeAs<DeclRefExpr>("CLibFunction")) {
+ diag(MatchedCLibFunc->getLocation(),
+ "cstdio functions should not be used outside the main function");
+ return;
+ }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits