#include "MoveForwardingReferenceCheck.h"
#include "MultipleStatementMacroCheck.h"
#include "StringConstructorCheck.h"
+#include "StringIntegerAssignmentCheck.h"
+#include "StringLiteralWithEmbeddedNulCheck.h"
+#include "SuspiciousEnumUsageCheck.h"
#include "SuspiciousMemsetUsageCheck.h"
+#include "SuspiciousMissingCommaCheck.h"
#include "ThrowKeywordMissingCheck.h"
#include "UndefinedMemoryManipulationCheck.h"
#include "UseAfterMoveCheck.h"
"bugprone-multiple-statement-macro");
CheckFactories.registerCheck<StringConstructorCheck>(
"bugprone-string-constructor");
+ CheckFactories.registerCheck<StringIntegerAssignmentCheck>(
+ "bugprone-string-integer-assignment");
+ CheckFactories.registerCheck<StringLiteralWithEmbeddedNulCheck>(
+ "bugprone-string-literal-with-embedded-nul");
+ CheckFactories.registerCheck<SuspiciousEnumUsageCheck>(
+ "bugprone-suspicious-enum-usage");
CheckFactories.registerCheck<SuspiciousMemsetUsageCheck>(
"bugprone-suspicious-memset-usage");
+ CheckFactories.registerCheck<SuspiciousMissingCommaCheck>(
+ "bugprone-suspicious-missing-comma");
CheckFactories.registerCheck<ThrowKeywordMissingCheck>(
"bugprone-throw-keyword-missing");
CheckFactories.registerCheck<UndefinedMemoryManipulationCheck>(
MoveForwardingReferenceCheck.cpp
MultipleStatementMacroCheck.cpp
StringConstructorCheck.cpp
+ StringIntegerAssignmentCheck.cpp
+ StringLiteralWithEmbeddedNulCheck.cpp
+ SuspiciousEnumUsageCheck.cpp
SuspiciousMemsetUsageCheck.cpp
+ SuspiciousMissingCommaCheck.cpp
ThrowKeywordMissingCheck.cpp
UndefinedMemoryManipulationCheck.cpp
UseAfterMoveCheck.cpp
--- /dev/null
+//===--- StringIntegerAssignmentCheck.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 "StringIntegerAssignmentCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ anyOf(hasOverloadedOperatorName("="),
+ hasOverloadedOperatorName("+=")),
+ callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
+ hasName("::std::basic_string"),
+ hasTemplateArgument(0, refersToType(qualType().bind("type"))))))),
+ hasArgument(1,
+ ignoringImpCasts(expr(hasType(isInteger()),
+ unless(hasType(isAnyCharacter())))
+ .bind("expr"))),
+ unless(isInTemplateInstantiation())),
+ this);
+}
+
+void StringIntegerAssignmentCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Argument = Result.Nodes.getNodeAs<Expr>("expr");
+ SourceLocation Loc = Argument->getLocStart();
+
+ auto Diag =
+ diag(Loc, "an integer is interpreted as a character code when assigning "
+ "it to a string; if this is intended, cast the integer to the "
+ "appropriate character type; if you want a string "
+ "representation, use the appropriate conversion facility");
+
+ if (Loc.isMacroID())
+ return;
+
+ auto CharType = *Result.Nodes.getNodeAs<QualType>("type");
+ bool IsWideCharType = CharType->isWideCharType();
+ if (!CharType->isCharType() && !IsWideCharType)
+ return;
+ bool IsOneDigit = false;
+ bool IsLiteral = false;
+ if (const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
+ IsOneDigit = Literal->getValue().getLimitedValue() < 10;
+ IsLiteral = true;
+ }
+
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Argument->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
+ if (IsOneDigit) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L'" : "'")
+ << FixItHint::CreateInsertion(EndLoc, "'");
+ return;
+ }
+ if (IsLiteral) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L\"" : "\"")
+ << FixItHint::CreateInsertion(EndLoc, "\"");
+ return;
+ }
+
+ if (getLangOpts().CPlusPlus11) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "std::to_wstring("
+ : "std::to_string(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
--- /dev/null
+//===--- StringIntegerAssignmentCheck.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_STRINGINTEGERASSIGNMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGINTEGERASSIGNMENTCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds instances where an integer is assigned to a string.
+///
+/// For more details see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-string-assignment.html
+class StringIntegerAssignmentCheck : public ClangTidyCheck {
+public:
+ StringIntegerAssignmentCheck(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_STRINGINTEGERASSIGNMENTCHECK_H
--- /dev/null
+//===--- StringLiteralWithEmbeddedNulCheck.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 "StringLiteralWithEmbeddedNulCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER(StringLiteral, containsNul) {
+ for (size_t i = 0; i < Node.getLength(); ++i)
+ if (Node.getCodeUnit(i) == '\0')
+ return true;
+ return false;
+}
+} // namespace
+
+void StringLiteralWithEmbeddedNulCheck::registerMatchers(MatchFinder *Finder) {
+ // Match a string that contains embedded NUL character. Extra-checks are
+ // applied in |check| to find incorectly escaped characters.
+ Finder->addMatcher(stringLiteral(containsNul()).bind("strlit"), this);
+
+ // The remaining checks only apply to C++.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto StrLitWithNul =
+ ignoringParenImpCasts(stringLiteral(containsNul()).bind("truncated"));
+
+ // Match string constructor.
+ const auto StringConstructorExpr = expr(anyOf(
+ cxxConstructExpr(argumentCountIs(1),
+ hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
+ // If present, the second argument is the alloc object which must not
+ // be present explicitly.
+ cxxConstructExpr(argumentCountIs(2),
+ hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+ hasArgument(1, cxxDefaultArgExpr()))));
+
+ // Detect passing a suspicious string literal to a string constructor.
+ // example: std::string str = "abc\0def";
+ Finder->addMatcher(
+ cxxConstructExpr(StringConstructorExpr, hasArgument(0, StrLitWithNul)),
+ this);
+
+ // Detect passing a suspicious string literal through an overloaded operator.
+ Finder->addMatcher(cxxOperatorCallExpr(hasAnyArgument(StrLitWithNul)), this);
+}
+
+void StringLiteralWithEmbeddedNulCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("strlit")) {
+ for (size_t Offset = 0, Length = SL->getLength(); Offset < Length;
+ ++Offset) {
+ // Find a sequence of character like "\0x12".
+ if (Offset + 3 < Length && SL->getCodeUnit(Offset) == '\0' &&
+ SL->getCodeUnit(Offset + 1) == 'x' &&
+ isDigit(SL->getCodeUnit(Offset + 2)) &&
+ isDigit(SL->getCodeUnit(Offset + 3))) {
+ diag(SL->getLocStart(), "suspicious embedded NUL character");
+ return;
+ }
+ }
+ }
+
+ if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("truncated")) {
+ diag(SL->getLocStart(),
+ "truncated string literal with embedded NUL character");
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
--- /dev/null
+//===--- StringLiteralWithEmbeddedNulCheck.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_STRINGLITERALWITHEMBEDDEDNULCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGLITERALWITHEMBEDDEDNULCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Find suspicious string literals with embedded NUL characters.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-string-literal-with-embedded-nul.html
+class StringLiteralWithEmbeddedNulCheck : public ClangTidyCheck {
+public:
+ StringLiteralWithEmbeddedNulCheck(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_STRINGLITERALWITHEMBEDDEDNULCHECK_H
--- /dev/null
+//===--- SuspiciousEnumUsageCheck.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 "SuspiciousEnumUsageCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <algorithm>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+static const char DifferentEnumErrorMessage[] =
+ "enum values are from different enum types";
+
+static const char BitmaskErrorMessage[] =
+ "enum type seems like a bitmask (contains mostly "
+ "power-of-2 literals), but this literal is not a "
+ "power-of-2";
+
+static const char BitmaskVarErrorMessage[] =
+ "enum type seems like a bitmask (contains mostly "
+ "power-of-2 literals) but %plural{1:a literal is|:some literals are}0 not "
+ "power-of-2";
+
+static const char BitmaskNoteMessage[] = "used here as a bitmask";
+
+/// Stores a min and a max value which describe an interval.
+struct ValueRange {
+ llvm::APSInt MinVal;
+ llvm::APSInt MaxVal;
+
+ ValueRange(const EnumDecl *EnumDec) {
+ const auto MinMaxVal = std::minmax_element(
+ EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
+ [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
+ return llvm::APSInt::compareValues(E1->getInitVal(),
+ E2->getInitVal()) < 0;
+ });
+ MinVal = MinMaxVal.first->getInitVal();
+ MaxVal = MinMaxVal.second->getInitVal();
+ }
+};
+
+/// Return the number of EnumConstantDecls in an EnumDecl.
+static int enumLength(const EnumDecl *EnumDec) {
+ return std::distance(EnumDec->enumerator_begin(), EnumDec->enumerator_end());
+}
+
+static bool hasDisjointValueRange(const EnumDecl *Enum1,
+ const EnumDecl *Enum2) {
+ ValueRange Range1(Enum1), Range2(Enum2);
+ return llvm::APSInt::compareValues(Range1.MaxVal, Range2.MinVal) < 0 ||
+ llvm::APSInt::compareValues(Range2.MaxVal, Range1.MinVal) < 0;
+}
+
+static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst) {
+ llvm::APSInt Val = EnumConst->getInitVal();
+ if (Val.isPowerOf2() || !Val.getBoolValue())
+ return false;
+ const Expr *InitExpr = EnumConst->getInitExpr();
+ if (!InitExpr)
+ return true;
+ return isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
+}
+
+static bool isMaxValAllBitSetLiteral(const EnumDecl *EnumDec) {
+ auto EnumConst = std::max_element(
+ EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
+ [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
+ return E1->getInitVal() < E2->getInitVal();
+ });
+
+ if (const Expr *InitExpr = EnumConst->getInitExpr()) {
+ return EnumConst->getInitVal().countTrailingOnes() ==
+ EnumConst->getInitVal().getActiveBits() &&
+ isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
+ }
+ return false;
+}
+
+static int countNonPowOfTwoLiteralNum(const EnumDecl *EnumDec) {
+ return std::count_if(
+ EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
+ [](const EnumConstantDecl *E) { return isNonPowerOf2NorNullLiteral(E); });
+}
+
+/// Check if there is one or two enumerators that are not a power of 2 and are
+/// initialized by a literal in the enum type, and that the enumeration contains
+/// enough elements to reasonably act as a bitmask. Exclude the case where the
+/// last enumerator is the sum of the lesser values (and initialized by a
+/// literal) or when it could contain consecutive values.
+static bool isPossiblyBitMask(const EnumDecl *EnumDec) {
+ ValueRange VR(EnumDec);
+ int EnumLen = enumLength(EnumDec);
+ int NonPowOfTwoCounter = countNonPowOfTwoLiteralNum(EnumDec);
+ return NonPowOfTwoCounter >= 1 && NonPowOfTwoCounter <= 2 &&
+ NonPowOfTwoCounter < EnumLen / 2 &&
+ (VR.MaxVal - VR.MinVal != EnumLen - 1) &&
+ !(NonPowOfTwoCounter == 1 && isMaxValAllBitSetLiteral(EnumDec));
+}
+
+SuspiciousEnumUsageCheck::SuspiciousEnumUsageCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ StrictMode(Options.getLocalOrGlobal("StrictMode", 0)) {}
+
+void SuspiciousEnumUsageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "StrictMode", StrictMode);
+}
+
+void SuspiciousEnumUsageCheck::registerMatchers(MatchFinder *Finder) {
+ const auto enumExpr = [](StringRef RefName, StringRef DeclName) {
+ return allOf(ignoringImpCasts(expr().bind(RefName)),
+ ignoringImpCasts(hasType(enumDecl().bind(DeclName))));
+ };
+
+ Finder->addMatcher(
+ binaryOperator(hasOperatorName("|"), hasLHS(enumExpr("", "enumDecl")),
+ hasRHS(allOf(enumExpr("", "otherEnumDecl"),
+ ignoringImpCasts(hasType(enumDecl(
+ unless(equalsBoundNode("enumDecl"))))))))
+ .bind("diffEnumOp"),
+ this);
+
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|")),
+ hasLHS(enumExpr("lhsExpr", "enumDecl")),
+ hasRHS(allOf(enumExpr("rhsExpr", ""),
+ ignoringImpCasts(hasType(enumDecl(
+ equalsBoundNode("enumDecl"))))))),
+ this);
+
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|")),
+ hasEitherOperand(
+ allOf(hasType(isInteger()), unless(enumExpr("", "")))),
+ hasEitherOperand(enumExpr("enumExpr", "enumDecl"))),
+ this);
+
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("|="), hasOperatorName("+=")),
+ hasRHS(enumExpr("enumExpr", "enumDecl"))),
+ this);
+}
+
+void SuspiciousEnumUsageCheck::checkSuspiciousBitmaskUsage(
+ const Expr *NodeExpr, const EnumDecl *EnumDec) {
+ const auto *EnumExpr = dyn_cast<DeclRefExpr>(NodeExpr);
+ const auto *EnumConst =
+ EnumExpr ? dyn_cast<EnumConstantDecl>(EnumExpr->getDecl()) : nullptr;
+
+ // Report the parameter if neccessary.
+ if (!EnumConst) {
+ diag(EnumDec->getInnerLocStart(), BitmaskVarErrorMessage)
+ << countNonPowOfTwoLiteralNum(EnumDec);
+ diag(EnumExpr->getExprLoc(), BitmaskNoteMessage, DiagnosticIDs::Note);
+ } else if (isNonPowerOf2NorNullLiteral(EnumConst)) {
+ diag(EnumConst->getSourceRange().getBegin(), BitmaskErrorMessage);
+ diag(EnumExpr->getExprLoc(), BitmaskNoteMessage, DiagnosticIDs::Note);
+ }
+}
+
+void SuspiciousEnumUsageCheck::check(const MatchFinder::MatchResult &Result) {
+ // Case 1: The two enum values come from different types.
+ if (const auto *DiffEnumOp =
+ Result.Nodes.getNodeAs<BinaryOperator>("diffEnumOp")) {
+ const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>("enumDecl");
+ const auto *OtherEnumDec =
+ Result.Nodes.getNodeAs<EnumDecl>("otherEnumDecl");
+ // Skip when one of the parameters is an empty enum. The
+ // hasDisjointValueRange function could not decide the values properly in
+ // case of an empty enum.
+ if (EnumDec->enumerator_begin() == EnumDec->enumerator_end() ||
+ OtherEnumDec->enumerator_begin() == OtherEnumDec->enumerator_end())
+ return;
+
+ if (!hasDisjointValueRange(EnumDec, OtherEnumDec))
+ diag(DiffEnumOp->getOperatorLoc(), DifferentEnumErrorMessage);
+ return;
+ }
+
+ // Case 2 and 3 only checked in strict mode. The checker tries to detect
+ // suspicious bitmasks which contains values initialized by non power-of-2
+ // literals.
+ if (!StrictMode)
+ return;
+ const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>("enumDecl");
+ if (!isPossiblyBitMask(EnumDec))
+ return;
+
+ // Case 2:
+ // a. Investigating the right hand side of `+=` or `|=` operator.
+ // b. When the operator is `|` or `+` but only one of them is an EnumExpr
+ if (const auto *EnumExpr = Result.Nodes.getNodeAs<Expr>("enumExpr")) {
+ checkSuspiciousBitmaskUsage(EnumExpr, EnumDec);
+ return;
+ }
+
+ // Case 3:
+ // '|' or '+' operator where both argument comes from the same enum type
+ const auto *LhsExpr = Result.Nodes.getNodeAs<Expr>("lhsExpr");
+ checkSuspiciousBitmaskUsage(LhsExpr, EnumDec);
+
+ const auto *RhsExpr = Result.Nodes.getNodeAs<Expr>("rhsExpr");
+ checkSuspiciousBitmaskUsage(RhsExpr, EnumDec);
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
--- /dev/null
+//===--- SuspiciousEnumUsageCheck.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_SUSPICIOUSENUMUSAGECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSENUMUSAGECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// The checker detects various cases when an enum is probably misused (as a
+/// bitmask).
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-enum-usage.html
+class SuspiciousEnumUsageCheck : public ClangTidyCheck {
+public:
+ SuspiciousEnumUsageCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ void checkSuspiciousBitmaskUsage(const Expr*, const EnumDecl*);
+ const bool StrictMode;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSENUMUSAGECHECK_H
--- /dev/null
+//===--- SuspiciousMissingCommaCheck.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 "SuspiciousMissingCommaCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
+ const StringLiteral *Lit) {
+ // String literals surrounded by parentheses are assumed to be on purpose.
+ // i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
+ auto Parents = Ctx->getParents(*Lit);
+ if (Parents.size() == 1 && Parents[0].get<ParenExpr>() != nullptr)
+ return true;
+
+ // Appropriately indented string literals are assumed to be on purpose.
+ // The following frequent indentation is accepted:
+ // const char* Array[] = {
+ // "first literal"
+ // "indented literal"
+ // "indented literal",
+ // "second literal",
+ // [...]
+ // };
+ const SourceManager &SM = Ctx->getSourceManager();
+ bool IndentedCorrectly = true;
+ SourceLocation FirstToken = Lit->getStrTokenLoc(0);
+ FileID BaseFID = SM.getFileID(FirstToken);
+ unsigned int BaseIndent = SM.getSpellingColumnNumber(FirstToken);
+ unsigned int BaseLine = SM.getSpellingLineNumber(FirstToken);
+ for (unsigned int TokNum = 1; TokNum < Lit->getNumConcatenated(); ++TokNum) {
+ SourceLocation Token = Lit->getStrTokenLoc(TokNum);
+ FileID FID = SM.getFileID(Token);
+ unsigned int Indent = SM.getSpellingColumnNumber(Token);
+ unsigned int Line = SM.getSpellingLineNumber(Token);
+ if (FID != BaseFID || Line != BaseLine + TokNum || Indent <= BaseIndent) {
+ IndentedCorrectly = false;
+ break;
+ }
+ }
+ if (IndentedCorrectly)
+ return true;
+
+ // There is no pattern recognized by the checker, assume it's not on purpose.
+ return false;
+}
+
+AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
+ MaxConcatenatedTokens) {
+ return Node.getNumConcatenated() > 1 &&
+ Node.getNumConcatenated() < MaxConcatenatedTokens &&
+ !isConcatenatedLiteralsOnPurpose(&Finder->getASTContext(), &Node);
+}
+
+} // namespace
+
+SuspiciousMissingCommaCheck::SuspiciousMissingCommaCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ SizeThreshold(Options.get("SizeThreshold", 5U)),
+ RatioThreshold(std::stod(Options.get("RatioThreshold", ".2"))),
+ MaxConcatenatedTokens(Options.get("MaxConcatenatedTokens", 5U)) {}
+
+void SuspiciousMissingCommaCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "SizeThreshold", SizeThreshold);
+ Options.store(Opts, "RatioThreshold", std::to_string(RatioThreshold));
+ Options.store(Opts, "MaxConcatenatedTokens", MaxConcatenatedTokens);
+}
+
+void SuspiciousMissingCommaCheck::registerMatchers(MatchFinder *Finder) {
+ const auto ConcatenatedStringLiteral =
+ stringLiteral(isConcatenatedLiteral(MaxConcatenatedTokens)).bind("str");
+
+ const auto StringsInitializerList =
+ initListExpr(hasType(constantArrayType()),
+ has(ignoringParenImpCasts(expr(ConcatenatedStringLiteral))));
+
+ Finder->addMatcher(StringsInitializerList.bind("list"), this);
+}
+
+void SuspiciousMissingCommaCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *InitializerList = Result.Nodes.getNodeAs<InitListExpr>("list");
+ const auto *ConcatenatedLiteral =
+ Result.Nodes.getNodeAs<StringLiteral>("str");
+ assert(InitializerList && ConcatenatedLiteral);
+
+ // Skip small arrays as they often generate false-positive.
+ unsigned int Size = InitializerList->getNumInits();
+ if (Size < SizeThreshold)
+ return;
+
+ // Count the number of occurence of concatenated string literal.
+ unsigned int Count = 0;
+ for (unsigned int i = 0; i < Size; ++i) {
+ const Expr *Child = InitializerList->getInit(i)->IgnoreImpCasts();
+ if (const auto *Literal = dyn_cast<StringLiteral>(Child)) {
+ if (Literal->getNumConcatenated() > 1)
+ ++Count;
+ }
+ }
+
+ // Warn only when concatenation is not common in this initializer list.
+ // The current threshold is set to less than 1/5 of the string literals.
+ if (double(Count) / Size > RatioThreshold)
+ return;
+
+ diag(ConcatenatedLiteral->getLocStart(),
+ "suspicious string literal, probably missing a comma");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
--- /dev/null
+//===--- SuspiciousMissingCommaCheck.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_SUSPICIOUSMISSINGCOMMACHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSMISSINGCOMMACHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// This check finds string literals which are probably concatenated
+/// accidentally.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-missing-comma.html
+class SuspiciousMissingCommaCheck : public ClangTidyCheck {
+public:
+ SuspiciousMissingCommaCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ // Minimal size of a string literals array to be considered by the checker.
+ const unsigned SizeThreshold;
+ // Maximal threshold ratio of suspicious string literals to be considered.
+ const double RatioThreshold;
+ // Maximal number of concatenated tokens.
+ const unsigned MaxConcatenatedTokens;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSMISSINGCOMMACHECK_H
SizeofContainerCheck.cpp
SizeofExpressionCheck.cpp
StaticAssertCheck.cpp
- StringIntegerAssignmentCheck.cpp
- StringLiteralWithEmbeddedNulCheck.cpp
- SuspiciousEnumUsageCheck.cpp
- SuspiciousMissingCommaCheck.cpp
SuspiciousSemicolonCheck.cpp
SuspiciousStringCompareCheck.cpp
SwappedArgumentsCheck.cpp
#include "SizeofContainerCheck.h"
#include "SizeofExpressionCheck.h"
#include "StaticAssertCheck.h"
-#include "StringIntegerAssignmentCheck.h"
-#include "StringLiteralWithEmbeddedNulCheck.h"
-#include "SuspiciousEnumUsageCheck.h"
-#include "SuspiciousMissingCommaCheck.h"
#include "SuspiciousSemicolonCheck.h"
#include "SuspiciousStringCompareCheck.h"
#include "SwappedArgumentsCheck.h"
CheckFactories.registerCheck<SizeofExpressionCheck>(
"misc-sizeof-expression");
CheckFactories.registerCheck<StaticAssertCheck>("misc-static-assert");
- CheckFactories.registerCheck<StringIntegerAssignmentCheck>(
- "misc-string-integer-assignment");
- CheckFactories.registerCheck<StringLiteralWithEmbeddedNulCheck>(
- "misc-string-literal-with-embedded-nul");
- CheckFactories.registerCheck<SuspiciousEnumUsageCheck>(
- "misc-suspicious-enum-usage");
- CheckFactories.registerCheck<SuspiciousMissingCommaCheck>(
- "misc-suspicious-missing-comma");
CheckFactories.registerCheck<SuspiciousSemicolonCheck>(
"misc-suspicious-semicolon");
CheckFactories.registerCheck<SuspiciousStringCompareCheck>(
+++ /dev/null
-//===--- StringIntegerAssignmentCheck.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 "StringIntegerAssignmentCheck.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Lex/Lexer.h"
-
-using namespace clang::ast_matchers;
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) {
- if (!getLangOpts().CPlusPlus)
- return;
- Finder->addMatcher(
- cxxOperatorCallExpr(
- anyOf(hasOverloadedOperatorName("="),
- hasOverloadedOperatorName("+=")),
- callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
- hasName("::std::basic_string"),
- hasTemplateArgument(0, refersToType(qualType().bind("type"))))))),
- hasArgument(1,
- ignoringImpCasts(expr(hasType(isInteger()),
- unless(hasType(isAnyCharacter())))
- .bind("expr"))),
- unless(isInTemplateInstantiation())),
- this);
-}
-
-void StringIntegerAssignmentCheck::check(
- const MatchFinder::MatchResult &Result) {
- const auto *Argument = Result.Nodes.getNodeAs<Expr>("expr");
- SourceLocation Loc = Argument->getLocStart();
-
- auto Diag =
- diag(Loc, "an integer is interpreted as a character code when assigning "
- "it to a string; if this is intended, cast the integer to the "
- "appropriate character type; if you want a string "
- "representation, use the appropriate conversion facility");
-
- if (Loc.isMacroID())
- return;
-
- auto CharType = *Result.Nodes.getNodeAs<QualType>("type");
- bool IsWideCharType = CharType->isWideCharType();
- if (!CharType->isCharType() && !IsWideCharType)
- return;
- bool IsOneDigit = false;
- bool IsLiteral = false;
- if (const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
- IsOneDigit = Literal->getValue().getLimitedValue() < 10;
- IsLiteral = true;
- }
-
- SourceLocation EndLoc = Lexer::getLocForEndOfToken(
- Argument->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
- if (IsOneDigit) {
- Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L'" : "'")
- << FixItHint::CreateInsertion(EndLoc, "'");
- return;
- }
- if (IsLiteral) {
- Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L\"" : "\"")
- << FixItHint::CreateInsertion(EndLoc, "\"");
- return;
- }
-
- if (getLangOpts().CPlusPlus11) {
- Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "std::to_wstring("
- : "std::to_string(")
- << FixItHint::CreateInsertion(EndLoc, ")");
- }
-}
-
-} // namespace misc
-} // namespace tidy
-} // namespace clang
+++ /dev/null
-//===--- StringIntegerAssignmentCheck.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_MISC_STRING_INTEGER_ASSIGNMENT_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STRING_INTEGER_ASSIGNMENT_H
-
-#include "../ClangTidy.h"
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-/// Finds instances where an integer is assigned to a string.
-///
-/// For more details see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/misc-string-assignment.html
-class StringIntegerAssignmentCheck : public ClangTidyCheck {
-public:
- StringIntegerAssignmentCheck(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_STRING_INTEGER_ASSIGNMENT_H
+++ /dev/null
-//===--- StringLiteralWithEmbeddedNulCheck.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 "StringLiteralWithEmbeddedNulCheck.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-
-using namespace clang::ast_matchers;
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-namespace {
-AST_MATCHER(StringLiteral, containsNul) {
- for (size_t i = 0; i < Node.getLength(); ++i)
- if (Node.getCodeUnit(i) == '\0')
- return true;
- return false;
-}
-} // namespace
-
-void StringLiteralWithEmbeddedNulCheck::registerMatchers(MatchFinder *Finder) {
- // Match a string that contains embedded NUL character. Extra-checks are
- // applied in |check| to find incorectly escaped characters.
- Finder->addMatcher(stringLiteral(containsNul()).bind("strlit"), this);
-
- // The remaining checks only apply to C++.
- if (!getLangOpts().CPlusPlus)
- return;
-
- const auto StrLitWithNul =
- ignoringParenImpCasts(stringLiteral(containsNul()).bind("truncated"));
-
- // Match string constructor.
- const auto StringConstructorExpr = expr(anyOf(
- cxxConstructExpr(argumentCountIs(1),
- hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
- // If present, the second argument is the alloc object which must not
- // be present explicitly.
- cxxConstructExpr(argumentCountIs(2),
- hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
- hasArgument(1, cxxDefaultArgExpr()))));
-
- // Detect passing a suspicious string literal to a string constructor.
- // example: std::string str = "abc\0def";
- Finder->addMatcher(
- cxxConstructExpr(StringConstructorExpr, hasArgument(0, StrLitWithNul)),
- this);
-
- // Detect passing a suspicious string literal through an overloaded operator.
- Finder->addMatcher(cxxOperatorCallExpr(hasAnyArgument(StrLitWithNul)), this);
-}
-
-void StringLiteralWithEmbeddedNulCheck::check(
- const MatchFinder::MatchResult &Result) {
- if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("strlit")) {
- for (size_t Offset = 0, Length = SL->getLength(); Offset < Length;
- ++Offset) {
- // Find a sequence of character like "\0x12".
- if (Offset + 3 < Length && SL->getCodeUnit(Offset) == '\0' &&
- SL->getCodeUnit(Offset + 1) == 'x' &&
- isDigit(SL->getCodeUnit(Offset + 2)) &&
- isDigit(SL->getCodeUnit(Offset + 3))) {
- diag(SL->getLocStart(), "suspicious embedded NUL character");
- return;
- }
- }
- }
-
- if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("truncated")) {
- diag(SL->getLocStart(),
- "truncated string literal with embedded NUL character");
- }
-}
-
-} // namespace misc
-} // namespace tidy
-} // namespace clang
+++ /dev/null
-//===--- StringLiteralWithEmbeddedNulCheck.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_MISC_STRING_LITERAL_WITH_EMBEDDED_NUL_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STRING_LITERAL_WITH_EMBEDDED_NUL_H
-
-#include "../ClangTidy.h"
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-/// Find suspicious string literals with embedded NUL characters.
-///
-/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/misc-string-literal-with-embedded-nul.html
-class StringLiteralWithEmbeddedNulCheck : public ClangTidyCheck {
-public:
- StringLiteralWithEmbeddedNulCheck(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_STRING_LITERAL_WITH_EMBEDDED_NUL_H
+++ /dev/null
-//===--- SuspiciousEnumUsageCheck.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 "SuspiciousEnumUsageCheck.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include <algorithm>
-
-using namespace clang::ast_matchers;
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-static const char DifferentEnumErrorMessage[] =
- "enum values are from different enum types";
-
-static const char BitmaskErrorMessage[] =
- "enum type seems like a bitmask (contains mostly "
- "power-of-2 literals), but this literal is not a "
- "power-of-2";
-
-static const char BitmaskVarErrorMessage[] =
- "enum type seems like a bitmask (contains mostly "
- "power-of-2 literals) but %plural{1:a literal is|:some literals are}0 not "
- "power-of-2";
-
-static const char BitmaskNoteMessage[] = "used here as a bitmask";
-
-/// Stores a min and a max value which describe an interval.
-struct ValueRange {
- llvm::APSInt MinVal;
- llvm::APSInt MaxVal;
-
- ValueRange(const EnumDecl *EnumDec) {
- const auto MinMaxVal = std::minmax_element(
- EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
- [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
- return llvm::APSInt::compareValues(E1->getInitVal(),
- E2->getInitVal()) < 0;
- });
- MinVal = MinMaxVal.first->getInitVal();
- MaxVal = MinMaxVal.second->getInitVal();
- }
-};
-
-/// Return the number of EnumConstantDecls in an EnumDecl.
-static int enumLength(const EnumDecl *EnumDec) {
- return std::distance(EnumDec->enumerator_begin(), EnumDec->enumerator_end());
-}
-
-static bool hasDisjointValueRange(const EnumDecl *Enum1,
- const EnumDecl *Enum2) {
- ValueRange Range1(Enum1), Range2(Enum2);
- return llvm::APSInt::compareValues(Range1.MaxVal, Range2.MinVal) < 0 ||
- llvm::APSInt::compareValues(Range2.MaxVal, Range1.MinVal) < 0;
-}
-
-static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst) {
- llvm::APSInt Val = EnumConst->getInitVal();
- if (Val.isPowerOf2() || !Val.getBoolValue())
- return false;
- const Expr *InitExpr = EnumConst->getInitExpr();
- if (!InitExpr)
- return true;
- return isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
-}
-
-static bool isMaxValAllBitSetLiteral(const EnumDecl *EnumDec) {
- auto EnumConst = std::max_element(
- EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
- [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
- return E1->getInitVal() < E2->getInitVal();
- });
-
- if (const Expr *InitExpr = EnumConst->getInitExpr()) {
- return EnumConst->getInitVal().countTrailingOnes() ==
- EnumConst->getInitVal().getActiveBits() &&
- isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
- }
- return false;
-}
-
-static int countNonPowOfTwoLiteralNum(const EnumDecl *EnumDec) {
- return std::count_if(
- EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
- [](const EnumConstantDecl *E) { return isNonPowerOf2NorNullLiteral(E); });
-}
-
-/// Check if there is one or two enumerators that are not a power of 2 and are
-/// initialized by a literal in the enum type, and that the enumeration contains
-/// enough elements to reasonably act as a bitmask. Exclude the case where the
-/// last enumerator is the sum of the lesser values (and initialized by a
-/// literal) or when it could contain consecutive values.
-static bool isPossiblyBitMask(const EnumDecl *EnumDec) {
- ValueRange VR(EnumDec);
- int EnumLen = enumLength(EnumDec);
- int NonPowOfTwoCounter = countNonPowOfTwoLiteralNum(EnumDec);
- return NonPowOfTwoCounter >= 1 && NonPowOfTwoCounter <= 2 &&
- NonPowOfTwoCounter < EnumLen / 2 &&
- (VR.MaxVal - VR.MinVal != EnumLen - 1) &&
- !(NonPowOfTwoCounter == 1 && isMaxValAllBitSetLiteral(EnumDec));
-}
-
-SuspiciousEnumUsageCheck::SuspiciousEnumUsageCheck(StringRef Name,
- ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context),
- StrictMode(Options.getLocalOrGlobal("StrictMode", 0)) {}
-
-void SuspiciousEnumUsageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
- Options.store(Opts, "StrictMode", StrictMode);
-}
-
-void SuspiciousEnumUsageCheck::registerMatchers(MatchFinder *Finder) {
- const auto enumExpr = [](StringRef RefName, StringRef DeclName) {
- return allOf(ignoringImpCasts(expr().bind(RefName)),
- ignoringImpCasts(hasType(enumDecl().bind(DeclName))));
- };
-
- Finder->addMatcher(
- binaryOperator(hasOperatorName("|"), hasLHS(enumExpr("", "enumDecl")),
- hasRHS(allOf(enumExpr("", "otherEnumDecl"),
- ignoringImpCasts(hasType(enumDecl(
- unless(equalsBoundNode("enumDecl"))))))))
- .bind("diffEnumOp"),
- this);
-
- Finder->addMatcher(
- binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|")),
- hasLHS(enumExpr("lhsExpr", "enumDecl")),
- hasRHS(allOf(enumExpr("rhsExpr", ""),
- ignoringImpCasts(hasType(enumDecl(
- equalsBoundNode("enumDecl"))))))),
- this);
-
- Finder->addMatcher(
- binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|")),
- hasEitherOperand(
- allOf(hasType(isInteger()), unless(enumExpr("", "")))),
- hasEitherOperand(enumExpr("enumExpr", "enumDecl"))),
- this);
-
- Finder->addMatcher(
- binaryOperator(anyOf(hasOperatorName("|="), hasOperatorName("+=")),
- hasRHS(enumExpr("enumExpr", "enumDecl"))),
- this);
-}
-
-void SuspiciousEnumUsageCheck::checkSuspiciousBitmaskUsage(
- const Expr *NodeExpr, const EnumDecl *EnumDec) {
- const auto *EnumExpr = dyn_cast<DeclRefExpr>(NodeExpr);
- const auto *EnumConst =
- EnumExpr ? dyn_cast<EnumConstantDecl>(EnumExpr->getDecl()) : nullptr;
-
- // Report the parameter if neccessary.
- if (!EnumConst) {
- diag(EnumDec->getInnerLocStart(), BitmaskVarErrorMessage)
- << countNonPowOfTwoLiteralNum(EnumDec);
- diag(EnumExpr->getExprLoc(), BitmaskNoteMessage, DiagnosticIDs::Note);
- } else if (isNonPowerOf2NorNullLiteral(EnumConst)) {
- diag(EnumConst->getSourceRange().getBegin(), BitmaskErrorMessage);
- diag(EnumExpr->getExprLoc(), BitmaskNoteMessage, DiagnosticIDs::Note);
- }
-}
-
-void SuspiciousEnumUsageCheck::check(const MatchFinder::MatchResult &Result) {
- // Case 1: The two enum values come from different types.
- if (const auto *DiffEnumOp =
- Result.Nodes.getNodeAs<BinaryOperator>("diffEnumOp")) {
- const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>("enumDecl");
- const auto *OtherEnumDec =
- Result.Nodes.getNodeAs<EnumDecl>("otherEnumDecl");
- // Skip when one of the parameters is an empty enum. The
- // hasDisjointValueRange function could not decide the values properly in
- // case of an empty enum.
- if (EnumDec->enumerator_begin() == EnumDec->enumerator_end() ||
- OtherEnumDec->enumerator_begin() == OtherEnumDec->enumerator_end())
- return;
-
- if (!hasDisjointValueRange(EnumDec, OtherEnumDec))
- diag(DiffEnumOp->getOperatorLoc(), DifferentEnumErrorMessage);
- return;
- }
-
- // Case 2 and 3 only checked in strict mode. The checker tries to detect
- // suspicious bitmasks which contains values initialized by non power-of-2
- // literals.
- if (!StrictMode)
- return;
- const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>("enumDecl");
- if (!isPossiblyBitMask(EnumDec))
- return;
-
- // Case 2:
- // a. Investigating the right hand side of `+=` or `|=` operator.
- // b. When the operator is `|` or `+` but only one of them is an EnumExpr
- if (const auto *EnumExpr = Result.Nodes.getNodeAs<Expr>("enumExpr")) {
- checkSuspiciousBitmaskUsage(EnumExpr, EnumDec);
- return;
- }
-
- // Case 3:
- // '|' or '+' operator where both argument comes from the same enum type
- const auto *LhsExpr = Result.Nodes.getNodeAs<Expr>("lhsExpr");
- checkSuspiciousBitmaskUsage(LhsExpr, EnumDec);
-
- const auto *RhsExpr = Result.Nodes.getNodeAs<Expr>("rhsExpr");
- checkSuspiciousBitmaskUsage(RhsExpr, EnumDec);
-}
-
-} // namespace misc
-} // namespace tidy
-} // namespace clang
+++ /dev/null
-//===--- SuspiciousEnumUsageCheck.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_MISC_SUSPICIOUS_ENUM_USAGE_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_ENUM_USAGE_H
-
-#include "../ClangTidy.h"
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-/// The checker detects various cases when an enum is probably misused (as a
-/// bitmask).
-/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/misc-suspicious-enum-usage.html
-class SuspiciousEnumUsageCheck : public ClangTidyCheck {
-public:
- SuspiciousEnumUsageCheck(StringRef Name, ClangTidyContext *Context);
- void registerMatchers(ast_matchers::MatchFinder *Finder) override;
- void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
- void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
-
-private:
- void checkSuspiciousBitmaskUsage(const Expr*, const EnumDecl*);
- const bool StrictMode;
-};
-
-} // namespace misc
-} // namespace tidy
-} // namespace clang
-
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_ENUM_USAGE_H
+++ /dev/null
-//===--- SuspiciousMissingCommaCheck.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 "SuspiciousMissingCommaCheck.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-
-using namespace clang::ast_matchers;
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-namespace {
-
-bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
- const StringLiteral *Lit) {
- // String literals surrounded by parentheses are assumed to be on purpose.
- // i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
- auto Parents = Ctx->getParents(*Lit);
- if (Parents.size() == 1 && Parents[0].get<ParenExpr>() != nullptr)
- return true;
-
- // Appropriately indented string literals are assumed to be on purpose.
- // The following frequent indentation is accepted:
- // const char* Array[] = {
- // "first literal"
- // "indented literal"
- // "indented literal",
- // "second literal",
- // [...]
- // };
- const SourceManager &SM = Ctx->getSourceManager();
- bool IndentedCorrectly = true;
- SourceLocation FirstToken = Lit->getStrTokenLoc(0);
- FileID BaseFID = SM.getFileID(FirstToken);
- unsigned int BaseIndent = SM.getSpellingColumnNumber(FirstToken);
- unsigned int BaseLine = SM.getSpellingLineNumber(FirstToken);
- for (unsigned int TokNum = 1; TokNum < Lit->getNumConcatenated(); ++TokNum) {
- SourceLocation Token = Lit->getStrTokenLoc(TokNum);
- FileID FID = SM.getFileID(Token);
- unsigned int Indent = SM.getSpellingColumnNumber(Token);
- unsigned int Line = SM.getSpellingLineNumber(Token);
- if (FID != BaseFID || Line != BaseLine + TokNum || Indent <= BaseIndent) {
- IndentedCorrectly = false;
- break;
- }
- }
- if (IndentedCorrectly)
- return true;
-
- // There is no pattern recognized by the checker, assume it's not on purpose.
- return false;
-}
-
-AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
- MaxConcatenatedTokens) {
- return Node.getNumConcatenated() > 1 &&
- Node.getNumConcatenated() < MaxConcatenatedTokens &&
- !isConcatenatedLiteralsOnPurpose(&Finder->getASTContext(), &Node);
-}
-
-} // namespace
-
-SuspiciousMissingCommaCheck::SuspiciousMissingCommaCheck(
- StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context),
- SizeThreshold(Options.get("SizeThreshold", 5U)),
- RatioThreshold(std::stod(Options.get("RatioThreshold", ".2"))),
- MaxConcatenatedTokens(Options.get("MaxConcatenatedTokens", 5U)) {}
-
-void SuspiciousMissingCommaCheck::storeOptions(
- ClangTidyOptions::OptionMap &Opts) {
- Options.store(Opts, "SizeThreshold", SizeThreshold);
- Options.store(Opts, "RatioThreshold", std::to_string(RatioThreshold));
- Options.store(Opts, "MaxConcatenatedTokens", MaxConcatenatedTokens);
-}
-
-void SuspiciousMissingCommaCheck::registerMatchers(MatchFinder *Finder) {
- const auto ConcatenatedStringLiteral =
- stringLiteral(isConcatenatedLiteral(MaxConcatenatedTokens)).bind("str");
-
- const auto StringsInitializerList =
- initListExpr(hasType(constantArrayType()),
- has(ignoringParenImpCasts(expr(ConcatenatedStringLiteral))));
-
- Finder->addMatcher(StringsInitializerList.bind("list"), this);
-}
-
-void SuspiciousMissingCommaCheck::check(
- const MatchFinder::MatchResult &Result) {
- const auto *InitializerList = Result.Nodes.getNodeAs<InitListExpr>("list");
- const auto *ConcatenatedLiteral =
- Result.Nodes.getNodeAs<StringLiteral>("str");
- assert(InitializerList && ConcatenatedLiteral);
-
- // Skip small arrays as they often generate false-positive.
- unsigned int Size = InitializerList->getNumInits();
- if (Size < SizeThreshold)
- return;
-
- // Count the number of occurence of concatenated string literal.
- unsigned int Count = 0;
- for (unsigned int i = 0; i < Size; ++i) {
- const Expr *Child = InitializerList->getInit(i)->IgnoreImpCasts();
- if (const auto *Literal = dyn_cast<StringLiteral>(Child)) {
- if (Literal->getNumConcatenated() > 1)
- ++Count;
- }
- }
-
- // Warn only when concatenation is not common in this initializer list.
- // The current threshold is set to less than 1/5 of the string literals.
- if (double(Count) / Size > RatioThreshold)
- return;
-
- diag(ConcatenatedLiteral->getLocStart(),
- "suspicious string literal, probably missing a comma");
-}
-
-} // namespace misc
-} // namespace tidy
-} // namespace clang
+++ /dev/null
-//===--- SuspiciousMissingCommaCheck.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_MISC_SUSPICIOUS_MISSING_COMMA_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_MISSING_COMMA_H
-
-#include "../ClangTidy.h"
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-/// This check finds string literals which are probably concatenated
-/// accidentally.
-///
-/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/misc-suspicious-missing-comma.html
-class SuspiciousMissingCommaCheck : public ClangTidyCheck {
-public:
- SuspiciousMissingCommaCheck(StringRef Name, ClangTidyContext *Context);
- void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
- void registerMatchers(ast_matchers::MatchFinder *Finder) override;
- void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
-
-private:
- // Minimal size of a string literals array to be considered by the checker.
- const unsigned SizeThreshold;
- // Maximal threshold ratio of suspicious string literals to be considered.
- const double RatioThreshold;
- // Maximal number of concatenated tokens.
- const unsigned MaxConcatenatedTokens;
-};
-
-} // namespace misc
-} // namespace tidy
-} // namespace clang
-
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_MISSING_COMMA_H
Warns if SIMD intrinsics are used which can be replaced by
``std::experimental::simd`` operations.
-
+
- New alias `hicpp-avoid-goto
- <http://clang.llvm.org/extra/clang-tidy/checks/hicpp-avoid-goto.html>`_ to
+ <http://clang.llvm.org/extra/clang-tidy/checks/hicpp-avoid-goto.html>`_ to
`cppcoreguidelines-avoid-goto <http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-avoid-goto.html>`_
added.
- The 'misc-string-compare' check was renamed to `readability-string-compare
<http://clang.llvm.org/extra/clang-tidy/checks/readability-string-compare.html>`_
+- The 'misc-string-integer-assignment' check was renamed to `bugprone-string-integer-assignment
+ <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-string-integer-assignment.html>`_
+
+- The 'misc-string-literal-with-embedded-nul' check was renamed to `bugprone-string-literal-with-embedded-nul
+ <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-string-literal-with-embedded-nul.html>`_
+
+- The 'misc-suspicious-enum-usage' check was renamed to `bugprone-suspicious-enum-usage
+ <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-enum-usage.html>`_
+
+- The 'misc-suspicious-missing-comma' check was renamed to `bugprone-suspicious-missing-comma
+ <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-missing-comma.html>`_
+
Improvements to include-fixer
-----------------------------
--- /dev/null
+.. title:: clang-tidy - bugprone-string-integer-assignment
+
+bugprone-string-integer-assignment
+==================================
+
+The check finds assignments of an integer to ``std::basic_string<CharT>``
+(``std::string``, ``std::wstring``, etc.). The source of the problem is the
+following assignment operator of ``std::basic_string<CharT>``:
+
+.. code-block:: c++
+
+ basic_string& operator=( CharT ch );
+
+Numeric types can be implicitly casted to character types.
+
+.. code-block:: c++
+
+ std::string s;
+ int x = 5965;
+ s = 6;
+ s = x;
+
+Use the appropriate conversion functions or character literals.
+
+.. code-block:: c++
+
+ std::string s;
+ int x = 5965;
+ s = '6';
+ s = std::to_string(x);
+
+In order to suppress false positives, use an explicit cast.
+
+.. code-block:: c++
+
+ std::string s;
+ s = static_cast<char>(6);
--- /dev/null
+.. title:: clang-tidy - bugprone-string-literal-with-embedded-nul
+
+bugprone-string-literal-with-embedded-nul
+=========================================
+
+Finds occurrences of string literal with embedded NUL character and validates
+their usage.
+
+Invalid escaping
+----------------
+
+Special characters can be escaped within a string literal by using their
+hexadecimal encoding like ``\x42``. A common mistake is to escape them
+like this ``\0x42`` where the ``\0`` stands for the NUL character.
+
+.. code-block:: c++
+
+ const char* Example[] = "Invalid character: \0x12 should be \x12";
+ const char* Bytes[] = "\x03\0x02\0x01\0x00\0xFF\0xFF\0xFF";
+
+Truncated literal
+-----------------
+
+String-like classes can manipulate strings with embedded NUL as they are keeping
+track of the bytes and the length. This is not the case for a ``char*``
+(NUL-terminated) string.
+
+A common mistake is to pass a string-literal with embedded NUL to a string
+constructor expecting a NUL-terminated string. The bytes after the first NUL
+character are truncated.
+
+.. code-block:: c++
+
+ std::string str("abc\0def"); // "def" is truncated
+ str += "\0"; // This statement is doing nothing
+ if (str == "\0abc") return; // This expression is always true
--- /dev/null
+.. title:: clang-tidy - bugprone-suspicious-enum-usage
+
+bugprone-suspicious-enum-usage
+==============================
+
+The checker detects various cases when an enum is probably misused (as a bitmask
+).
+
+1. When "ADD" or "bitwise OR" is used between two enum which come from different
+ types and these types value ranges are not disjoint.
+
+The following cases will be investigated only using :option:`StrictMode`. We
+regard the enum as a (suspicious)
+bitmask if the three conditions below are true at the same time:
+
+* at most half of the elements of the enum are non pow-of-2 numbers (because of
+ short enumerations)
+* there is another non pow-of-2 number than the enum constant representing all
+ choices (the result "bitwise OR" operation of all enum elements)
+* enum type variable/enumconstant is used as an argument of a `+` or "bitwise OR
+ " operator
+
+So whenever the non pow-of-2 element is used as a bitmask element we diagnose a
+misuse and give a warning.
+
+2. Investigating the right hand side of `+=` and `|=` operator.
+3. Check only the enum value side of a `|` and `+` operator if one of them is not
+ enum val.
+4. Check both side of `|` or `+` operator where the enum values are from the
+ same enum type.
+
+Examples:
+
+.. code-block:: c++
+
+ enum { A, B, C };
+ enum { D, E, F = 5 };
+ enum { G = 10, H = 11, I = 12 };
+
+ unsigned flag;
+ flag =
+ A |
+ H; // OK, disjoint value intervalls in the enum types ->probably good use.
+ flag = B | F; // Warning, have common values so they are probably misused.
+
+ // Case 2:
+ enum Bitmask {
+ A = 0,
+ B = 1,
+ C = 2,
+ D = 4,
+ E = 8,
+ F = 16,
+ G = 31 // OK, real bitmask.
+ };
+
+ enum Almostbitmask {
+ AA = 0,
+ BB = 1,
+ CC = 2,
+ DD = 4,
+ EE = 8,
+ FF = 16,
+ GG // Problem, forgot to initialize.
+ };
+
+ unsigned flag = 0;
+ flag |= E; // OK.
+ flag |=
+ EE; // Warning at the decl, and note that it was used here as a bitmask.
+
+Options
+-------
+.. option:: StrictMode
+
+ Default value: 0.
+ When non-null the suspicious bitmask usage will be investigated additionally
+ to the different enum usage check.
--- /dev/null
+.. title:: clang-tidy - bugprone-suspicious-missing-comma
+
+bugprone-suspicious-missing-comma
+=================================
+
+String literals placed side-by-side are concatenated at translation phase 6
+(after the preprocessor). This feature is used to represent long string
+literal on multiple lines.
+
+For instance, the following declarations are equivalent:
+
+.. code-block:: c++
+
+ const char* A[] = "This is a test";
+ const char* B[] = "This" " is a " "test";
+
+A common mistake done by programmers is to forget a comma between two string
+literals in an array initializer list.
+
+.. code-block:: c++
+
+ const char* Test[] = {
+ "line 1",
+ "line 2" // Missing comma!
+ "line 3",
+ "line 4",
+ "line 5"
+ };
+
+The array contains the string "line 2line3" at offset 1 (i.e. Test[1]). Clang
+won't generate warnings at compile time.
+
+This check may warn incorrectly on cases like:
+
+.. code-block:: c++
+
+ const char* SupportedFormat[] = {
+ "Error %s",
+ "Code " PRIu64, // May warn here.
+ "Warning %s",
+ };
+
+Options
+-------
+
+.. option:: SizeThreshold
+
+ An unsigned integer specifying the minimum size of a string literal to be
+ considered by the check. Default is `5U`.
+
+.. option:: RatioThreshold
+
+ A string specifying the maximum threshold ratio [0, 1.0] of suspicious string
+ literals to be considered. Default is `".2"`.
+
+.. option:: MaxConcatenatedTokens
+
+ An unsigned integer specifying the maximum number of concatenated tokens.
+ Default is `5U`.
bugprone-move-forwarding-reference
bugprone-multiple-statement-macro
bugprone-string-constructor
+ bugprone-string-integer-assignment
+ bugprone-string-literal-with-embedded-nul
+ bugprone-suspicious-enum-usage
bugprone-suspicious-memset-usage
+ bugprone-suspicious-missing-comma
bugprone-throw-keyword-missing
bugprone-undefined-memory-manipulation
bugprone-use-after-move
misc-sizeof-container
misc-sizeof-expression
misc-static-assert
- misc-string-integer-assignment
- misc-string-literal-with-embedded-nul
- misc-suspicious-enum-usage
- misc-suspicious-missing-comma
misc-suspicious-semicolon
misc-suspicious-string-compare
misc-swapped-arguments
+++ /dev/null
-.. title:: clang-tidy - misc-string-integer-assignment
-
-misc-string-integer-assignment
-==============================
-
-The check finds assignments of an integer to ``std::basic_string<CharT>``
-(``std::string``, ``std::wstring``, etc.). The source of the problem is the
-following assignment operator of ``std::basic_string<CharT>``:
-
-.. code-block:: c++
-
- basic_string& operator=( CharT ch );
-
-Numeric types can be implicitly casted to character types.
-
-.. code-block:: c++
-
- std::string s;
- int x = 5965;
- s = 6;
- s = x;
-
-Use the appropriate conversion functions or character literals.
-
-.. code-block:: c++
-
- std::string s;
- int x = 5965;
- s = '6';
- s = std::to_string(x);
-
-In order to suppress false positives, use an explicit cast.
-
-.. code-block:: c++
-
- std::string s;
- s = static_cast<char>(6);
+++ /dev/null
-.. title:: clang-tidy - misc-string-literal-with-embedded-nul
-
-misc-string-literal-with-embedded-nul
-=====================================
-
-Finds occurrences of string literal with embedded NUL character and validates
-their usage.
-
-Invalid escaping
-----------------
-
-Special characters can be escaped within a string literal by using their
-hexadecimal encoding like ``\x42``. A common mistake is to escape them
-like this ``\0x42`` where the ``\0`` stands for the NUL character.
-
-.. code-block:: c++
-
- const char* Example[] = "Invalid character: \0x12 should be \x12";
- const char* Bytes[] = "\x03\0x02\0x01\0x00\0xFF\0xFF\0xFF";
-
-Truncated literal
------------------
-
-String-like classes can manipulate strings with embedded NUL as they are keeping
-track of the bytes and the length. This is not the case for a ``char*``
-(NUL-terminated) string.
-
-A common mistake is to pass a string-literal with embedded NUL to a string
-constructor expecting a NUL-terminated string. The bytes after the first NUL
-character are truncated.
-
-.. code-block:: c++
-
- std::string str("abc\0def"); // "def" is truncated
- str += "\0"; // This statement is doing nothing
- if (str == "\0abc") return; // This expression is always true
+++ /dev/null
-.. title:: clang-tidy - misc-suspicious-enum-usage
-
-misc-suspicious-enum-usage
-==========================
-
-The checker detects various cases when an enum is probably misused (as a bitmask
-).
-
-1. When "ADD" or "bitwise OR" is used between two enum which come from different
- types and these types value ranges are not disjoint.
-
-The following cases will be investigated only using :option:`StrictMode`. We
-regard the enum as a (suspicious)
-bitmask if the three conditions below are true at the same time:
-
-* at most half of the elements of the enum are non pow-of-2 numbers (because of
- short enumerations)
-* there is another non pow-of-2 number than the enum constant representing all
- choices (the result "bitwise OR" operation of all enum elements)
-* enum type variable/enumconstant is used as an argument of a `+` or "bitwise OR
- " operator
-
-So whenever the non pow-of-2 element is used as a bitmask element we diagnose a
-misuse and give a warning.
-
-2. Investigating the right hand side of `+=` and `|=` operator.
-3. Check only the enum value side of a `|` and `+` operator if one of them is not
- enum val.
-4. Check both side of `|` or `+` operator where the enum values are from the
- same enum type.
-
-Examples:
-
-.. code-block:: c++
-
- enum { A, B, C };
- enum { D, E, F = 5 };
- enum { G = 10, H = 11, I = 12 };
-
- unsigned flag;
- flag =
- A |
- H; // OK, disjoint value intervalls in the enum types ->probably good use.
- flag = B | F; // Warning, have common values so they are probably misused.
-
- // Case 2:
- enum Bitmask {
- A = 0,
- B = 1,
- C = 2,
- D = 4,
- E = 8,
- F = 16,
- G = 31 // OK, real bitmask.
- };
-
- enum Almostbitmask {
- AA = 0,
- BB = 1,
- CC = 2,
- DD = 4,
- EE = 8,
- FF = 16,
- GG // Problem, forgot to initialize.
- };
-
- unsigned flag = 0;
- flag |= E; // OK.
- flag |=
- EE; // Warning at the decl, and note that it was used here as a bitmask.
-
-Options
--------
-.. option:: StrictMode
-
- Default value: 0.
- When non-null the suspicious bitmask usage will be investigated additionally
- to the different enum usage check.
+++ /dev/null
-.. title:: clang-tidy - misc-suspicious-missing-comma
-
-misc-suspicious-missing-comma
-=============================
-
-String literals placed side-by-side are concatenated at translation phase 6
-(after the preprocessor). This feature is used to represent long string
-literal on multiple lines.
-
-For instance, the following declarations are equivalent:
-
-.. code-block:: c++
-
- const char* A[] = "This is a test";
- const char* B[] = "This" " is a " "test";
-
-A common mistake done by programmers is to forget a comma between two string
-literals in an array initializer list.
-
-.. code-block:: c++
-
- const char* Test[] = {
- "line 1",
- "line 2" // Missing comma!
- "line 3",
- "line 4",
- "line 5"
- };
-
-The array contains the string "line 2line3" at offset 1 (i.e. Test[1]). Clang
-won't generate warnings at compile time.
-
-This check may warn incorrectly on cases like:
-
-.. code-block:: c++
-
- const char* SupportedFormat[] = {
- "Error %s",
- "Code " PRIu64, // May warn here.
- "Warning %s",
- };
-
-Options
--------
-
-.. option:: SizeThreshold
-
- An unsigned integer specifying the minimum size of a string literal to be
- considered by the check. Default is `5U`.
-
-.. option:: RatioThreshold
-
- A string specifying the maximum threshold ratio [0, 1.0] of suspicious string
- literals to be considered. Default is `".2"`.
-
-.. option:: MaxConcatenatedTokens
-
- An unsigned integer specifying the maximum number of concatenated tokens.
- Default is `5U`.
--- /dev/null
+// RUN: %check_clang_tidy %s bugprone-string-integer-assignment %t
+
+namespace std {
+template<typename T>
+struct basic_string {
+ basic_string& operator=(T);
+ basic_string& operator=(basic_string);
+ basic_string& operator+=(T);
+ basic_string& operator+=(basic_string);
+};
+
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+typedef int MyArcaneChar;
+
+int main() {
+ std::string s;
+ std::wstring ws;
+ int x = 5;
+
+ s = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a character code when assigning {{.*}} [bugprone-string-integer-assignment]
+// CHECK-FIXES: {{^}} s = '6';{{$}}
+ s = 66;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} s = "66";{{$}}
+ s = x;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} s = std::to_string(x);{{$}}
+ s = 'c';
+ s = static_cast<char>(6);
+
+// +=
+ ws += 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += L'6';{{$}}
+ ws += 66;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += L"66";{{$}}
+ ws += x;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += std::to_wstring(x);{{$}}
+ ws += L'c';
+ ws += (wchar_t)6;
+
+ std::basic_string<MyArcaneChar> as;
+ as = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} as = 6;{{$}}
+
+}
--- /dev/null
+// RUN: %check_clang_tidy %s bugprone-string-literal-with-embedded-nul %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T, typename A>
+struct basic_string {
+ typedef basic_string<C, T, A> _Type;
+ basic_string();
+ basic_string(const C *p, const A &a = A());
+
+ _Type& operator+=(const C* s);
+ _Type& operator=(const C* s);
+};
+
+typedef basic_string<char, std::char_traits<char>, std::allocator<char>> string;
+typedef basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>> wstring;
+}
+
+bool operator==(const std::string&, const char*);
+bool operator==(const char*, const std::string&);
+
+
+const char Valid[] = "This is valid \x12.";
+const char Strange[] = "This is strange \0x12 and must be fixed";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: suspicious embedded NUL character [bugprone-string-literal-with-embedded-nul]
+
+const char textA[] = "\0x01\0x02\0x03\0x04";
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious embedded NUL character
+const wchar_t textW[] = L"\0x01\0x02\0x03\0x04";
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious embedded NUL character
+
+const char A[] = "\0";
+const char B[] = "\0x";
+const char C[] = "\0x1";
+const char D[] = "\0x11";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: suspicious embedded NUL character
+
+const wchar_t E[] = L"\0";
+const wchar_t F[] = L"\0x";
+const wchar_t G[] = L"\0x1";
+const wchar_t H[] = L"\0x11";
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious embedded NUL character
+
+const char I[] = "\000\000\000\000";
+const char J[] = "\0\0\0\0\0\0";
+const char K[] = "";
+
+const char L[] = "\0x12" "\0x12" "\0x12" "\0x12";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: suspicious embedded NUL character
+
+void TestA() {
+ std::string str1 = "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: truncated string literal
+ std::string str2 = "\0";
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: truncated string literal
+ std::string str3("\0");
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: truncated string literal
+ std::string str4{"\x00\x01\x02\x03"};
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: truncated string literal
+
+ std::string str;
+ str += "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: truncated string literal
+ str = "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: truncated string literal
+
+ if (str == "abc\0def") return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: truncated string literal
+ if ("abc\0def" == str) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: truncated string literal
+}
+
+void TestW() {
+ std::wstring str1 = L"abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: truncated string literal
+ std::wstring str2 = L"\0";
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: truncated string literal
+ std::wstring str3(L"\0");
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: truncated string literal
+ std::wstring str4{L"\x00\x01\x02\x03"};
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: truncated string literal
+}
--- /dev/null
+// RUN: %check_clang_tidy %s bugprone-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: bugprone-suspicious-enum-usage.StrictMode, value: 1}]}" --
+
+enum A {
+ A = 1,
+ B = 2,
+ C = 4,
+ D = 8,
+ E = 16,
+ F = 32,
+ G = 63
+};
+
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but a literal is not power-of-2
+// CHECK-MESSAGES: :76:7: note: used here as a bitmask
+enum X {
+ X = 8,
+ Y = 16,
+ Z = 4,
+ ZZ = 3
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2 [bugprone-suspicious-enum-usage]
+// CHECK-MESSAGES: :70:13: note: used here as a bitmask
+};
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but some literals are not power-of-2
+// CHECK-MESSAGES: :73:8: note: used here as a bitmask
+enum PP {
+ P = 2,
+ Q = 3,
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2
+ // CHECK-MESSAGES: :65:11: note: used here as a bitmask
+ R = 4,
+ S = 8,
+ T = 16,
+ U = 31
+};
+
+enum {
+ H,
+ I,
+ J,
+ K,
+ L
+};
+
+enum Days {
+ Monday,
+ Tuesday,
+ Wednesday,
+ Thursday,
+ Friday,
+ Saturday,
+ Sunday
+};
+
+Days bestDay() {
+ return Friday;
+}
+
+int trigger() {
+ if (bestDay() | A)
+ return 1;
+ // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
+ if (I | Y)
+ return 1;
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+ if (P + Q == R)
+ return 1;
+ else if ((S | R) == T)
+ return 1;
+ else
+ int k = ZZ | Z;
+ unsigned p = R;
+ PP pp = Q;
+ p |= pp;
+
+ enum X x = Z;
+ p = x | Z;
+ return 0;
+}
+
+int dont_trigger() {
+ int a = 1, b = 5;
+ int c = a + b;
+ int d = c | H, e = b * a;
+ a = B | C;
+ b = X | Z;
+
+ unsigned bitflag;
+ enum A aa = B;
+ bitflag = aa | C;
+
+ if (Tuesday != Monday + 1 ||
+ Friday - Thursday != 1 ||
+ Sunday + Wednesday == (Sunday | Wednesday))
+ return 1;
+ if (H + I + L == 42)
+ return 1;
+ return 42;
+}
--- /dev/null
+// RUN: %check_clang_tidy %s bugprone-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: bugprone-suspicious-enum-usage.StrictMode, value: 0}]}" --
+
+enum Empty {
+};
+
+enum A {
+ A = 1,
+ B = 2,
+ C = 4,
+ D = 8,
+ E = 16,
+ F = 32,
+ G = 63
+};
+
+enum X {
+ X = 8,
+ Y = 16,
+ Z = 4
+};
+
+enum {
+ P = 2,
+ Q = 3,
+ R = 4,
+ S = 8,
+ T = 16
+};
+
+enum {
+ H,
+ I,
+ J,
+ K,
+ L
+};
+
+enum Days {
+ Monday,
+ Tuesday,
+ Wednesday,
+ Thursday,
+ Friday,
+ Saturday,
+ Sunday
+};
+
+Days bestDay() {
+ return Friday;
+}
+
+int trigger() {
+ Empty EmptyVal;
+ int emptytest = EmptyVal | B;
+ if (bestDay() | A)
+ return 1;
+ // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
+ if (I | Y)
+ return 1;
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+}
+
+int dont_trigger() {
+ unsigned p;
+ p = Q | P;
+
+ if (A + G == E)
+ return 1;
+ else if ((Q | R) == T)
+ return 1;
+ else
+ int k = T | Q;
+
+ Empty EmptyVal;
+ int emptytest = EmptyVal | B;
+
+ int a = 1, b = 5;
+ int c = a + b;
+ int d = c | H, e = b * a;
+ a = B | C;
+ b = X | Z;
+
+ if (Tuesday != Monday + 1 ||
+ Friday - Thursday != 1 ||
+ Sunday + Wednesday == (Sunday | Wednesday))
+ return 1;
+ if (H + I + L == 42)
+ return 1;
+ return 42;
+}
+
+namespace PR34400 {
+enum { E1 = 0 };
+enum { E2 = -1 };
+enum { l = E1 | E2 };
+}
--- /dev/null
+// RUN: %check_clang_tidy %s bugprone-suspicious-missing-comma %t
+
+const char* Cartoons[] = {
+ "Bugs Bunny",
+ "Homer Simpson",
+ "Mickey Mouse",
+ "Bart Simpson",
+ "Charlie Brown" // There is a missing comma here.
+ "Fred Flintstone",
+ "Popeye",
+};
+// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: suspicious string literal, probably missing a comma [bugprone-suspicious-missing-comma]
+
+const wchar_t* Colors[] = {
+ L"Red", L"Yellow", L"Blue", L"Green", L"Purple", L"Rose", L"White", L"Black"
+};
+
+// The following array should not trigger any warnings. There is more than 5
+// elements, but they are all concatenated string literals.
+const char* HttpCommands[] = {
+ "GET / HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /favicon.ico HTTP/1.0\r\n"
+ "header: dummy"
+ "\r\n",
+
+ "GET /index.html-en HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html-fr HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html-es HTTP/1.0\r\n"
+ "\r\n",
+};
+
+// This array is too small to trigger a warning.
+const char* SmallArray[] = {
+ "a" "b", "c"
+};
+
+// Parentheses should be enough to avoid warnings.
+const char* ParentheseArray[] = {
+ ("a" "b"), "c",
+ ("d"
+ "e"
+ "f"),
+ "g", "h", "i", "j", "k", "l"
+};
+
+// Indentation should be enough to avoid warnings.
+const char* CorrectlyIndentedArray[] = {
+ "This is a long message "
+ "which is spanning over multiple lines."
+ "And this should be fine.",
+ "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l"
+};
+
+const char* IncorrectlyIndentedArray[] = {
+ "This is a long message "
+ "which is spanning over multiple lines."
+ "And this should be fine.",
+ "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l"
+};
+// CHECK-MESSAGES: :[[@LINE-6]]:3: warning: suspicious string literal, probably missing a comma [bugprone-suspicious-missing-comma]
+
+const char* TooManyConcatenatedTokensArray[] = {
+ "Dummy line",
+ "Dummy line",
+ "a" "b" "c" "d" "e" "f",
+ "g" "h" "i" "j" "k" "l",
+ "Dummy line",
+ "Dummy line",
+ "Dummy line",
+ "Dummy line",
+};
+++ /dev/null
-// RUN: %check_clang_tidy %s misc-string-integer-assignment %t
-
-namespace std {
-template<typename T>
-struct basic_string {
- basic_string& operator=(T);
- basic_string& operator=(basic_string);
- basic_string& operator+=(T);
- basic_string& operator+=(basic_string);
-};
-
-typedef basic_string<char> string;
-typedef basic_string<wchar_t> wstring;
-}
-
-typedef int MyArcaneChar;
-
-int main() {
- std::string s;
- std::wstring ws;
- int x = 5;
-
- s = 6;
-// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a character code when assigning {{.*}} [misc-string-integer-assignment]
-// CHECK-FIXES: {{^}} s = '6';{{$}}
- s = 66;
-// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
-// CHECK-FIXES: {{^}} s = "66";{{$}}
- s = x;
-// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
-// CHECK-FIXES: {{^}} s = std::to_string(x);{{$}}
- s = 'c';
- s = static_cast<char>(6);
-
-// +=
- ws += 6;
-// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
-// CHECK-FIXES: {{^}} ws += L'6';{{$}}
- ws += 66;
-// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
-// CHECK-FIXES: {{^}} ws += L"66";{{$}}
- ws += x;
-// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
-// CHECK-FIXES: {{^}} ws += std::to_wstring(x);{{$}}
- ws += L'c';
- ws += (wchar_t)6;
-
- std::basic_string<MyArcaneChar> as;
- as = 6;
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
-// CHECK-FIXES: {{^}} as = 6;{{$}}
-
-}
+++ /dev/null
-// RUN: %check_clang_tidy %s misc-string-literal-with-embedded-nul %t
-
-namespace std {
-template <typename T>
-class allocator {};
-template <typename T>
-class char_traits {};
-template <typename C, typename T, typename A>
-struct basic_string {
- typedef basic_string<C, T, A> _Type;
- basic_string();
- basic_string(const C *p, const A &a = A());
-
- _Type& operator+=(const C* s);
- _Type& operator=(const C* s);
-};
-
-typedef basic_string<char, std::char_traits<char>, std::allocator<char>> string;
-typedef basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>> wstring;
-}
-
-bool operator==(const std::string&, const char*);
-bool operator==(const char*, const std::string&);
-
-
-const char Valid[] = "This is valid \x12.";
-const char Strange[] = "This is strange \0x12 and must be fixed";
-// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: suspicious embedded NUL character [misc-string-literal-with-embedded-nul]
-
-const char textA[] = "\0x01\0x02\0x03\0x04";
-// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious embedded NUL character
-const wchar_t textW[] = L"\0x01\0x02\0x03\0x04";
-// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious embedded NUL character
-
-const char A[] = "\0";
-const char B[] = "\0x";
-const char C[] = "\0x1";
-const char D[] = "\0x11";
-// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: suspicious embedded NUL character
-
-const wchar_t E[] = L"\0";
-const wchar_t F[] = L"\0x";
-const wchar_t G[] = L"\0x1";
-const wchar_t H[] = L"\0x11";
-// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious embedded NUL character
-
-const char I[] = "\000\000\000\000";
-const char J[] = "\0\0\0\0\0\0";
-const char K[] = "";
-
-const char L[] = "\0x12" "\0x12" "\0x12" "\0x12";
-// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: suspicious embedded NUL character
-
-void TestA() {
- std::string str1 = "abc\0def";
- // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: truncated string literal
- std::string str2 = "\0";
- // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: truncated string literal
- std::string str3("\0");
- // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: truncated string literal
- std::string str4{"\x00\x01\x02\x03"};
- // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: truncated string literal
-
- std::string str;
- str += "abc\0def";
- // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: truncated string literal
- str = "abc\0def";
- // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: truncated string literal
-
- if (str == "abc\0def") return;
- // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: truncated string literal
- if ("abc\0def" == str) return;
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: truncated string literal
-}
-
-void TestW() {
- std::wstring str1 = L"abc\0def";
- // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: truncated string literal
- std::wstring str2 = L"\0";
- // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: truncated string literal
- std::wstring str3(L"\0");
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: truncated string literal
- std::wstring str4{L"\x00\x01\x02\x03"};
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: truncated string literal
-}
+++ /dev/null
-// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 1}]}" --
-
-enum A {
- A = 1,
- B = 2,
- C = 4,
- D = 8,
- E = 16,
- F = 32,
- G = 63
-};
-
-// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but a literal is not power-of-2
-// CHECK-MESSAGES: :76:7: note: used here as a bitmask
-enum X {
- X = 8,
- Y = 16,
- Z = 4,
- ZZ = 3
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2 [misc-suspicious-enum-usage]
-// CHECK-MESSAGES: :70:13: note: used here as a bitmask
-};
-// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but some literals are not power-of-2
-// CHECK-MESSAGES: :73:8: note: used here as a bitmask
-enum PP {
- P = 2,
- Q = 3,
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2
- // CHECK-MESSAGES: :65:11: note: used here as a bitmask
- R = 4,
- S = 8,
- T = 16,
- U = 31
-};
-
-enum {
- H,
- I,
- J,
- K,
- L
-};
-
-enum Days {
- Monday,
- Tuesday,
- Wednesday,
- Thursday,
- Friday,
- Saturday,
- Sunday
-};
-
-Days bestDay() {
- return Friday;
-}
-
-int trigger() {
- if (bestDay() | A)
- return 1;
- // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
- if (I | Y)
- return 1;
- // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
- if (P + Q == R)
- return 1;
- else if ((S | R) == T)
- return 1;
- else
- int k = ZZ | Z;
- unsigned p = R;
- PP pp = Q;
- p |= pp;
-
- enum X x = Z;
- p = x | Z;
- return 0;
-}
-
-int dont_trigger() {
- int a = 1, b = 5;
- int c = a + b;
- int d = c | H, e = b * a;
- a = B | C;
- b = X | Z;
-
- unsigned bitflag;
- enum A aa = B;
- bitflag = aa | C;
-
- if (Tuesday != Monday + 1 ||
- Friday - Thursday != 1 ||
- Sunday + Wednesday == (Sunday | Wednesday))
- return 1;
- if (H + I + L == 42)
- return 1;
- return 42;
-}
+++ /dev/null
-// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 0}]}" --
-
-enum Empty {
-};
-
-enum A {
- A = 1,
- B = 2,
- C = 4,
- D = 8,
- E = 16,
- F = 32,
- G = 63
-};
-
-enum X {
- X = 8,
- Y = 16,
- Z = 4
-};
-
-enum {
- P = 2,
- Q = 3,
- R = 4,
- S = 8,
- T = 16
-};
-
-enum {
- H,
- I,
- J,
- K,
- L
-};
-
-enum Days {
- Monday,
- Tuesday,
- Wednesday,
- Thursday,
- Friday,
- Saturday,
- Sunday
-};
-
-Days bestDay() {
- return Friday;
-}
-
-int trigger() {
- Empty EmptyVal;
- int emptytest = EmptyVal | B;
- if (bestDay() | A)
- return 1;
- // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
- if (I | Y)
- return 1;
- // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
-}
-
-int dont_trigger() {
- unsigned p;
- p = Q | P;
-
- if (A + G == E)
- return 1;
- else if ((Q | R) == T)
- return 1;
- else
- int k = T | Q;
-
- Empty EmptyVal;
- int emptytest = EmptyVal | B;
-
- int a = 1, b = 5;
- int c = a + b;
- int d = c | H, e = b * a;
- a = B | C;
- b = X | Z;
-
- if (Tuesday != Monday + 1 ||
- Friday - Thursday != 1 ||
- Sunday + Wednesday == (Sunday | Wednesday))
- return 1;
- if (H + I + L == 42)
- return 1;
- return 42;
-}
-
-namespace PR34400 {
-enum { E1 = 0 };
-enum { E2 = -1 };
-enum { l = E1 | E2 };
-}
+++ /dev/null
-// RUN: %check_clang_tidy %s misc-suspicious-missing-comma %t
-
-const char* Cartoons[] = {
- "Bugs Bunny",
- "Homer Simpson",
- "Mickey Mouse",
- "Bart Simpson",
- "Charlie Brown" // There is a missing comma here.
- "Fred Flintstone",
- "Popeye",
-};
-// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: suspicious string literal, probably missing a comma [misc-suspicious-missing-comma]
-
-const wchar_t* Colors[] = {
- L"Red", L"Yellow", L"Blue", L"Green", L"Purple", L"Rose", L"White", L"Black"
-};
-
-// The following array should not trigger any warnings. There is more than 5
-// elements, but they are all concatenated string literals.
-const char* HttpCommands[] = {
- "GET / HTTP/1.0\r\n"
- "\r\n",
-
- "GET /index.html HTTP/1.0\r\n"
- "\r\n",
-
- "GET /favicon.ico HTTP/1.0\r\n"
- "header: dummy"
- "\r\n",
-
- "GET /index.html-en HTTP/1.0\r\n"
- "\r\n",
-
- "GET /index.html-fr HTTP/1.0\r\n"
- "\r\n",
-
- "GET /index.html-es HTTP/1.0\r\n"
- "\r\n",
-};
-
-// This array is too small to trigger a warning.
-const char* SmallArray[] = {
- "a" "b", "c"
-};
-
-// Parentheses should be enough to avoid warnings.
-const char* ParentheseArray[] = {
- ("a" "b"), "c",
- ("d"
- "e"
- "f"),
- "g", "h", "i", "j", "k", "l"
-};
-
-// Indentation should be enough to avoid warnings.
-const char* CorrectlyIndentedArray[] = {
- "This is a long message "
- "which is spanning over multiple lines."
- "And this should be fine.",
- "a", "b", "c", "d", "e", "f",
- "g", "h", "i", "j", "k", "l"
-};
-
-const char* IncorrectlyIndentedArray[] = {
- "This is a long message "
- "which is spanning over multiple lines."
- "And this should be fine.",
- "a", "b", "c", "d", "e", "f",
- "g", "h", "i", "j", "k", "l"
-};
-// CHECK-MESSAGES: :[[@LINE-6]]:3: warning: suspicious string literal, probably missing a comma [misc-suspicious-missing-comma]
-
-const char* TooManyConcatenatedTokensArray[] = {
- "Dummy line",
- "Dummy line",
- "a" "b" "c" "d" "e" "f",
- "g" "h" "i" "j" "k" "l",
- "Dummy line",
- "Dummy line",
- "Dummy line",
- "Dummy line",
-};