Index: clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tidy/bugprone/BugproneTidyModule.cpp @@ -22,6 +22,7 @@ #include "MisplacedOperatorInStrlenInAllocCheck.h" #include "MoveForwardingReferenceCheck.h" #include "MultipleStatementMacroCheck.h" +#include "StreamInt8Check.h" #include "StringConstructorCheck.h" #include "SuspiciousMemsetUsageCheck.h" #include "UndefinedMemoryManipulationCheck.h" @@ -59,6 +60,8 @@ "bugprone-move-forwarding-reference"); CheckFactories.registerCheck( "bugprone-multiple-statement-macro"); + CheckFactories.registerCheck( + "bugprone-stream-int8"); CheckFactories.registerCheck( "bugprone-string-constructor"); CheckFactories.registerCheck( Index: clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tidy/bugprone/CMakeLists.txt +++ clang-tidy/bugprone/CMakeLists.txt @@ -14,6 +14,7 @@ MisplacedOperatorInStrlenInAllocCheck.cpp MoveForwardingReferenceCheck.cpp MultipleStatementMacroCheck.cpp + StreamInt8Check.cpp StringConstructorCheck.cpp SuspiciousMemsetUsageCheck.cpp UndefinedMemoryManipulationCheck.cpp Index: clang-tidy/bugprone/StreamInt8Check.h =================================================================== --- /dev/null +++ clang-tidy/bugprone/StreamInt8Check.h @@ -0,0 +1,35 @@ +//===--- StreamInt8Check.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_BUGPRONE_STREAMUINT8_TCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STREAMUINT8_TCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-stream-int8.html +class StreamInt8Check : public ClangTidyCheck { +public: + StreamInt8Check(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STREAMUINT8_TCHECK_H Index: clang-tidy/bugprone/StreamInt8Check.cpp =================================================================== --- /dev/null +++ clang-tidy/bugprone/StreamInt8Check.cpp @@ -0,0 +1,55 @@ +//===--- StreamInt8Check.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 "StreamInt8Check.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +void StreamInt8Check::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + cxxOperatorCallExpr( + hasOverloadedOperatorName("<<"), + hasArgument(0, expr(hasType(qualType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(hasName("std::basic_ostream")))))))), + hasArgument(1, expr(hasType(hasCanonicalType( + anyOf(asString("signed char"), + asString("const signed char"), + asString("unsigned char"), + asString("const unsigned char")))))) + ).bind("oper"), this); +} + +void StreamInt8Check::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedExpr = Result.Nodes.getNodeAs("oper"); + const auto *Offender = MatchedExpr->getArg(1); + + for (auto Typedef = Offender->getType().getTypePtr()->getAs(); Typedef; ) { + auto Name = Typedef->getDecl()->getNameAsString(); + if (Name == "uint8_t") { + diag(Offender->getLocStart(), "streaming uint8_t"); + break; + } else if (Name == "int8_t") { + diag(Offender->getLocStart(), "streaming int8_t"); + break; + } + + auto Underlying = Typedef->getDecl()->getUnderlyingType(); + Typedef = Underlying.getTypePtr()->getAs(); + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,9 @@ Improvements to clang-tidy -------------------------- +- New `bugprone-stream-int8_t + `_ check + - New module `fuchsia` for Fuchsia style checks. - New module `objc` for Objective-C style checks. Index: docs/clang-tidy/checks/bugprone-stream-int8.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/bugprone-stream-int8.rst @@ -0,0 +1,15 @@ +.. title:: clang-tidy - bugprone-stream-int8 + +bugprone-stream-int8 +==================== + +Checks that objects of type ``int8_t`` or ``uint8_t`` aren't streamed, if those +are typedefs to ``signed char`` or ``unsigned char``, as this likely intends to +be streaming these types as ``int`` s instead. + +Examples: + +.. code-block:: c++ + + uint8_t value = 0; + std::cout << "Value is " << value; // prints ^@ instead of likely intended 0 Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -29,6 +29,7 @@ bugprone-misplaced-operator-in-strlen-in-alloc bugprone-move-forwarding-reference bugprone-multiple-statement-macro + bugprone-stream-int8 bugprone-string-constructor bugprone-suspicious-memset-usage bugprone-undefined-memory-manipulation Index: test/clang-tidy/bugprone-stream-int8.cpp =================================================================== --- /dev/null +++ test/clang-tidy/bugprone-stream-int8.cpp @@ -0,0 +1,37 @@ +// RUN: %check_clang_tidy %s bugprone-stream-int8 %t +using int8_t = signed char; +using uint8_t = unsigned char; + +namespace std { + template + struct basic_ostream; + + using ostream = basic_ostream; + + basic_ostream& operator<<(basic_ostream&, char ); + basic_ostream& operator<<(basic_ostream&, unsigned char ); + basic_ostream& operator<<(basic_ostream&, signed char ); + basic_ostream& operator<<(basic_ostream&, int ); +} + +void f(std::ostream& os, uint8_t i) { + // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: streaming uint8_t [bugprone-stream-int8] + os << i; + + // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: streaming uint8_t [bugprone-stream-int8] + os << 4 << i; + + // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: streaming int8_t [bugprone-stream-int8] + os << int8_t{}; + + using Num = int8_t; + // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: streaming int8_t [bugprone-stream-int8] + os << Num{}; +} + +void awesome_f2(std::ostream& os, uint8_t i) { + using UC = unsigned char; + + unsigned char uc; + os << +i << 4 << uc << UC{}; +}