Index: clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -33,8 +33,12 @@ #include "SuspiciousEnumUsageCheck.h" #include "SuspiciousMemsetUsageCheck.h" #include "SuspiciousMissingCommaCheck.h" +#include "SuspiciousSemicolonCheck.h" +#include "SuspiciousStringCompareCheck.h" +#include "SwappedArgumentsCheck.h" #include "ThrowKeywordMissingCheck.h" #include "UndefinedMemoryManipulationCheck.h" +#include "UndelegatedConstructorCheck.h" #include "UseAfterMoveCheck.h" #include "VirtualNearMissCheck.h" @@ -91,10 +95,18 @@ "bugprone-suspicious-memset-usage"); CheckFactories.registerCheck( "bugprone-suspicious-missing-comma"); + CheckFactories.registerCheck( + "bugprone-suspicious-semicolon"); + CheckFactories.registerCheck( + "bugprone-suspicious-string-compare"); + CheckFactories.registerCheck( + "bugprone-swapped-arguments"); CheckFactories.registerCheck( "bugprone-throw-keyword-missing"); CheckFactories.registerCheck( "bugprone-undefined-memory-manipulation"); + CheckFactories.registerCheck( + "bugprone-undelegated-constructor"); CheckFactories.registerCheck( "bugprone-use-after-move"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt @@ -25,8 +25,12 @@ SuspiciousEnumUsageCheck.cpp SuspiciousMemsetUsageCheck.cpp SuspiciousMissingCommaCheck.cpp + SuspiciousSemicolonCheck.cpp + SuspiciousStringCompareCheck.cpp + SwappedArgumentsCheck.cpp ThrowKeywordMissingCheck.cpp UndefinedMemoryManipulationCheck.cpp + UndelegatedConstructorCheck.cpp UseAfterMoveCheck.cpp VirtualNearMissCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousSemicolonCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousSemicolonCheck.h +++ clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousSemicolonCheck.h @@ -0,0 +1,36 @@ +//===--- SuspiciousSemicolonCheck.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_SUSPICIOUSSEMICOLONCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSEMICOLONCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// This check finds semicolon that modifies the meaning of the program +/// unintendedly. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-semicolon.html +class SuspiciousSemicolonCheck : public ClangTidyCheck { +public: + SuspiciousSemicolonCheck(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_SUSPICIOUSSEMICOLONCHECK_H Index: clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp @@ -0,0 +1,77 @@ +//===--- SuspiciousSemicolonCheck.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 "SuspiciousSemicolonCheck.h" +#include "../utils/LexerUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +void SuspiciousSemicolonCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + stmt(anyOf(ifStmt(hasThen(nullStmt().bind("semi")), + unless(hasElse(stmt()))), + forStmt(hasBody(nullStmt().bind("semi"))), + cxxForRangeStmt(hasBody(nullStmt().bind("semi"))), + whileStmt(hasBody(nullStmt().bind("semi"))))) + .bind("stmt"), + this); +} + +void SuspiciousSemicolonCheck::check(const MatchFinder::MatchResult &Result) { + if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred()) + return; + + const auto *Semicolon = Result.Nodes.getNodeAs("semi"); + SourceLocation LocStart = Semicolon->getLocStart(); + + if (LocStart.isMacroID()) + return; + + ASTContext &Ctxt = *Result.Context; + auto Token = utils::lexer::getPreviousToken(Ctxt, LocStart); + auto &SM = *Result.SourceManager; + unsigned SemicolonLine = SM.getSpellingLineNumber(LocStart); + + const auto *Statement = Result.Nodes.getNodeAs("stmt"); + const bool IsIfStmt = isa(Statement); + + if (!IsIfStmt && + SM.getSpellingLineNumber(Token.getLocation()) != SemicolonLine) + return; + + SourceLocation LocEnd = Semicolon->getLocEnd(); + FileID FID = SM.getFileID(LocEnd); + llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd); + Lexer Lexer(SM.getLocForStartOfFile(FID), Ctxt.getLangOpts(), + Buffer->getBufferStart(), SM.getCharacterData(LocEnd) + 1, + Buffer->getBufferEnd()); + if (Lexer.LexFromRawLexer(Token)) + return; + + unsigned BaseIndent = SM.getSpellingColumnNumber(Statement->getLocStart()); + unsigned NewTokenIndent = SM.getSpellingColumnNumber(Token.getLocation()); + unsigned NewTokenLine = SM.getSpellingLineNumber(Token.getLocation()); + + if (!IsIfStmt && NewTokenIndent <= BaseIndent && + Token.getKind() != tok::l_brace && NewTokenLine != SemicolonLine) + return; + + diag(LocStart, "potentially unintended semicolon") + << FixItHint::CreateRemoval(SourceRange(LocStart, LocEnd)); +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousStringCompareCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousStringCompareCheck.h +++ clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousStringCompareCheck.h @@ -0,0 +1,40 @@ +//===--- SuspiciousStringCompareCheck.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_SUSPICIOUSSTRINGCOMPARECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSTRINGCOMPARECHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Find suspicious calls to string compare functions. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-string-compare.html +class SuspiciousStringCompareCheck : public ClangTidyCheck { +public: + SuspiciousStringCompareCheck(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: + const bool WarnOnImplicitComparison; + const bool WarnOnLogicalNotComparison; + const std::string StringCompareLikeFunctions; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSTRINGCOMPARECHECK_H Index: clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp @@ -0,0 +1,218 @@ +//===--- SuspiciousStringCompareCheck.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 "SuspiciousStringCompareCheck.h" +#include "../utils/Matchers.h" +#include "../utils/OptionsUtils.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 { + +// Semicolon separated list of known string compare-like functions. The list +// must ends with a semicolon. +static const char KnownStringCompareFunctions[] = "__builtin_memcmp;" + "__builtin_strcasecmp;" + "__builtin_strcmp;" + "__builtin_strncasecmp;" + "__builtin_strncmp;" + "_mbscmp;" + "_mbscmp_l;" + "_mbsicmp;" + "_mbsicmp_l;" + "_mbsnbcmp;" + "_mbsnbcmp_l;" + "_mbsnbicmp;" + "_mbsnbicmp_l;" + "_mbsncmp;" + "_mbsncmp_l;" + "_mbsnicmp;" + "_mbsnicmp_l;" + "_memicmp;" + "_memicmp_l;" + "_stricmp;" + "_stricmp_l;" + "_strnicmp;" + "_strnicmp_l;" + "_wcsicmp;" + "_wcsicmp_l;" + "_wcsnicmp;" + "_wcsnicmp_l;" + "lstrcmp;" + "lstrcmpi;" + "memcmp;" + "memicmp;" + "strcasecmp;" + "strcmp;" + "strcmpi;" + "stricmp;" + "strncasecmp;" + "strncmp;" + "strnicmp;" + "wcscasecmp;" + "wcscmp;" + "wcsicmp;" + "wcsncmp;" + "wcsnicmp;" + "wmemcmp;"; + +SuspiciousStringCompareCheck::SuspiciousStringCompareCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + WarnOnImplicitComparison(Options.get("WarnOnImplicitComparison", 1)), + WarnOnLogicalNotComparison(Options.get("WarnOnLogicalNotComparison", 0)), + StringCompareLikeFunctions( + Options.get("StringCompareLikeFunctions", "")) {} + +void SuspiciousStringCompareCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnImplicitComparison", WarnOnImplicitComparison); + Options.store(Opts, "WarnOnLogicalNotComparison", WarnOnLogicalNotComparison); + Options.store(Opts, "StringCompareLikeFunctions", StringCompareLikeFunctions); +} + +void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) { + // Match relational operators. + const auto ComparisonUnaryOperator = unaryOperator(hasOperatorName("!")); + const auto ComparisonBinaryOperator = + binaryOperator(matchers::isComparisonOperator()); + const auto ComparisonOperator = + expr(anyOf(ComparisonUnaryOperator, ComparisonBinaryOperator)); + + // Add the list of known string compare-like functions and add user-defined + // functions. + std::vector FunctionNames = utils::options::parseStringList( + (llvm::Twine(KnownStringCompareFunctions) + StringCompareLikeFunctions) + .str()); + + // Match a call to a string compare functions. + const auto FunctionCompareDecl = + functionDecl(hasAnyName(std::vector(FunctionNames.begin(), + FunctionNames.end()))) + .bind("decl"); + const auto DirectStringCompareCallExpr = + callExpr(hasDeclaration(FunctionCompareDecl)).bind("call"); + const auto MacroStringCompareCallExpr = conditionalOperator(anyOf( + hasTrueExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)), + hasFalseExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)))); + // The implicit cast is not present in C. + const auto StringCompareCallExpr = ignoringParenImpCasts( + anyOf(DirectStringCompareCallExpr, MacroStringCompareCallExpr)); + + if (WarnOnImplicitComparison) { + // Detect suspicious calls to string compare: + // 'if (strcmp())' -> 'if (strcmp() != 0)' + Finder->addMatcher( + stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)), + whileStmt(hasCondition(StringCompareCallExpr)), + doStmt(hasCondition(StringCompareCallExpr)), + forStmt(hasCondition(StringCompareCallExpr)), + binaryOperator( + anyOf(hasOperatorName("&&"), hasOperatorName("||")), + hasEitherOperand(StringCompareCallExpr)))) + .bind("missing-comparison"), + this); + } + + if (WarnOnLogicalNotComparison) { + // Detect suspicious calls to string compared with '!' operator: + // 'if (!strcmp())' -> 'if (strcmp() == 0)' + Finder->addMatcher(unaryOperator(hasOperatorName("!"), + hasUnaryOperand(ignoringParenImpCasts( + StringCompareCallExpr))) + .bind("logical-not-comparison"), + this); + } + + // Detect suspicious cast to an inconsistant type (i.e. not integer type). + Finder->addMatcher( + implicitCastExpr(unless(hasType(isInteger())), + hasSourceExpression(StringCompareCallExpr)) + .bind("invalid-conversion"), + this); + + // Detect suspicious operator with string compare function as operand. + Finder->addMatcher( + binaryOperator( + unless(anyOf(matchers::isComparisonOperator(), hasOperatorName("&&"), + hasOperatorName("||"), hasOperatorName("="))), + hasEitherOperand(StringCompareCallExpr)) + .bind("suspicious-operator"), + this); + + // Detect comparison to invalid constant: 'strcmp() == -1'. + const auto InvalidLiteral = ignoringParenImpCasts( + anyOf(integerLiteral(unless(equals(0))), + unaryOperator( + hasOperatorName("-"), + has(ignoringParenImpCasts(integerLiteral(unless(equals(0)))))), + characterLiteral(), cxxBoolLiteral())); + + Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(), + hasEitherOperand(StringCompareCallExpr), + hasEitherOperand(InvalidLiteral)) + .bind("invalid-comparison"), + this); +} + +void SuspiciousStringCompareCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *Decl = Result.Nodes.getNodeAs("decl"); + const auto *Call = Result.Nodes.getNodeAs("call"); + assert(Decl != nullptr && Call != nullptr); + + if (Result.Nodes.getNodeAs("missing-comparison")) { + SourceLocation EndLoc = Lexer::getLocForEndOfToken( + Call->getRParenLoc(), 0, Result.Context->getSourceManager(), + getLangOpts()); + + diag(Call->getLocStart(), + "function %0 is called without explicitly comparing result") + << Decl << FixItHint::CreateInsertion(EndLoc, " != 0"); + } + + if (const auto *E = Result.Nodes.getNodeAs("logical-not-comparison")) { + SourceLocation EndLoc = Lexer::getLocForEndOfToken( + Call->getRParenLoc(), 0, Result.Context->getSourceManager(), + getLangOpts()); + SourceLocation NotLoc = E->getLocStart(); + + diag(Call->getLocStart(), + "function %0 is compared using logical not operator") + << Decl << FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(NotLoc, NotLoc)) + << FixItHint::CreateInsertion(EndLoc, " == 0"); + } + + if (Result.Nodes.getNodeAs("invalid-comparison")) { + diag(Call->getLocStart(), + "function %0 is compared to a suspicious constant") + << Decl; + } + + if (const auto *BinOp = + Result.Nodes.getNodeAs("suspicious-operator")) { + diag(Call->getLocStart(), "results of function %0 used by operator '%1'") + << Decl << BinOp->getOpcodeStr(); + } + + if (Result.Nodes.getNodeAs("invalid-conversion")) { + diag(Call->getLocStart(), "function %0 has suspicious implicit cast") + << Decl; + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/clang-tidy/bugprone/SwappedArgumentsCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/SwappedArgumentsCheck.h +++ clang-tools-extra/trunk/clang-tidy/bugprone/SwappedArgumentsCheck.h @@ -0,0 +1,32 @@ +//===--- SwappedArgumentsCheck.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_SWAPPEDARGUMENTSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SWAPPEDARGUMENTSCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Finds potentially swapped arguments by looking at implicit conversions. +class SwappedArgumentsCheck : public ClangTidyCheck { +public: + SwappedArgumentsCheck(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_SWAPPEDARGUMENTSCHECK_H Index: clang-tools-extra/trunk/clang-tidy/bugprone/SwappedArgumentsCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/SwappedArgumentsCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/bugprone/SwappedArgumentsCheck.cpp @@ -0,0 +1,102 @@ +//===--- SwappedArgumentsCheck.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 "SwappedArgumentsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/FixIt.h" +#include "llvm/ADT/SmallPtrSet.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +void SwappedArgumentsCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(callExpr().bind("call"), this); +} + +/// \brief Look through lvalue to rvalue and nop casts. This filters out +/// implicit conversions that have no effect on the input but block our view for +/// other implicit casts. +static const Expr *ignoreNoOpCasts(const Expr *E) { + if (auto *Cast = dyn_cast(E)) + if (Cast->getCastKind() == CK_LValueToRValue || + Cast->getCastKind() == CK_NoOp) + return ignoreNoOpCasts(Cast->getSubExpr()); + return E; +} + +/// \brief Restrict the warning to implicit casts that are most likely +/// accidental. User defined or integral conversions fit in this category, +/// lvalue to rvalue or derived to base does not. +static bool isImplicitCastCandidate(const CastExpr *Cast) { + return Cast->getCastKind() == CK_UserDefinedConversion || + Cast->getCastKind() == CK_FloatingToBoolean || + Cast->getCastKind() == CK_FloatingToIntegral || + Cast->getCastKind() == CK_IntegralToBoolean || + Cast->getCastKind() == CK_IntegralToFloating || + Cast->getCastKind() == CK_MemberPointerToBoolean || + Cast->getCastKind() == CK_PointerToBoolean; +} + +void SwappedArgumentsCheck::check(const MatchFinder::MatchResult &Result) { + const ASTContext &Ctx = *Result.Context; + const auto *Call = Result.Nodes.getNodeAs("call"); + + llvm::SmallPtrSet UsedArgs; + for (unsigned I = 1, E = Call->getNumArgs(); I < E; ++I) { + const Expr *LHS = Call->getArg(I - 1); + const Expr *RHS = Call->getArg(I); + + // Only need to check RHS, as LHS has already been covered. We don't want to + // emit two warnings for a single argument. + if (UsedArgs.count(RHS)) + continue; + + const auto *LHSCast = dyn_cast(ignoreNoOpCasts(LHS)); + const auto *RHSCast = dyn_cast(ignoreNoOpCasts(RHS)); + + // Look if this is a potentially swapped argument pair. First look for + // implicit casts. + if (!LHSCast || !RHSCast || !isImplicitCastCandidate(LHSCast) || + !isImplicitCastCandidate(RHSCast)) + continue; + + // If the types that go into the implicit casts match the types of the other + // argument in the declaration there is a high probability that the + // arguments were swapped. + // TODO: We could make use of the edit distance between the argument name + // and the name of the passed variable in addition to this type based + // heuristic. + const Expr *LHSFrom = ignoreNoOpCasts(LHSCast->getSubExpr()); + const Expr *RHSFrom = ignoreNoOpCasts(RHSCast->getSubExpr()); + if (LHS->getType() == RHS->getType() || + LHS->getType() != RHSFrom->getType() || + RHS->getType() != LHSFrom->getType()) + continue; + + // Emit a warning and fix-its that swap the arguments. + diag(Call->getLocStart(), "argument with implicit conversion from %0 " + "to %1 followed by argument converted from " + "%2 to %3, potentially swapped arguments.") + << LHS->getType() << LHSFrom->getType() << RHS->getType() + << RHSFrom->getType() + << tooling::fixit::createReplacement(*LHS, *RHS, Ctx) + << tooling::fixit::createReplacement(*RHS, *LHS, Ctx); + + // Remember that we emitted a warning for this argument. + UsedArgs.insert(RHSCast); + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/clang-tidy/bugprone/UndelegatedConstructorCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/UndelegatedConstructorCheck.h +++ clang-tools-extra/trunk/clang-tidy/bugprone/UndelegatedConstructorCheck.h @@ -0,0 +1,36 @@ +//===--- UndelegatedConstructorCheck.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_UNDELEGATEDCONSTRUCTOR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNDELEGATEDCONSTRUCTOR_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Finds creation of temporary objects in constructors that look like a +/// function call to another constructor of the same class. +/// +/// The user most likely meant to use a delegating constructor or base class +/// initializer. +class UndelegatedConstructorCheck : public ClangTidyCheck { +public: + UndelegatedConstructorCheck(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_MISC_UNDELEGATEDCONSTRUCTOR_H Index: clang-tools-extra/trunk/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp @@ -0,0 +1,84 @@ +//===--- UndelegatedConstructorCheck.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 "UndelegatedConstructorCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +namespace { +AST_MATCHER_P(Stmt, ignoringTemporaryExpr, + ast_matchers::internal::Matcher, InnerMatcher) { + const Stmt *E = &Node; + for (;;) { + // Temporaries with non-trivial dtors. + if (const auto *EWC = dyn_cast(E)) + E = EWC->getSubExpr(); + // Temporaries with zero or more than two ctor arguments. + else if (const auto *BTE = dyn_cast(E)) + E = BTE->getSubExpr(); + // Temporaries with exactly one ctor argument. + else if (const auto *FCE = dyn_cast(E)) + E = FCE->getSubExpr(); + else + break; + } + + return InnerMatcher.matches(*E, Finder, Builder); +} + +// Finds a node if it's a base of an already bound node. +AST_MATCHER_P(CXXRecordDecl, baseOfBoundNode, std::string, ID) { + return Builder->removeBindings( + [&](const ast_matchers::internal::BoundNodesMap &Nodes) { + const auto *Derived = Nodes.getNodeAs(ID); + return Derived != &Node && !Derived->isDerivedFrom(&Node); + }); +} +} // namespace + +void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) { + // We look for calls to constructors of the same type in constructors. To do + // this we have to look through a variety of nodes that occur in the path, + // depending on the type's destructor and the number of arguments on the + // constructor call, this is handled by ignoringTemporaryExpr. Ignore template + // instantiations to reduce the number of duplicated warnings. + // + // Only register the matchers for C++11; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (!getLangOpts().CPlusPlus11) + return; + + Finder->addMatcher( + compoundStmt( + hasParent( + cxxConstructorDecl(ofClass(cxxRecordDecl().bind("parent")))), + forEach(ignoringTemporaryExpr( + cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass( + cxxRecordDecl(baseOfBoundNode("parent")))))) + .bind("construct"))), + unless(isInTemplateInstantiation())), + this); +} + +void UndelegatedConstructorCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *E = Result.Nodes.getNodeAs("construct"); + diag(E->getLocStart(), "did you intend to call a delegated constructor? " + "A temporary object is created here instead"); +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/clang-tidy/hicpp/HICPPTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/hicpp/HICPPTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/hicpp/HICPPTidyModule.cpp @@ -21,7 +21,7 @@ #include "../google/ExplicitConstructorCheck.h" #include "../misc/NewDeleteOverloadsCheck.h" #include "../misc/StaticAssertCheck.h" -#include "../misc/UndelegatedConstructor.h" +#include "../bugprone/UndelegatedConstructorCheck.h" #include "../modernize/DeprecatedHeadersCheck.h" #include "../modernize/UseAutoCheck.h" #include "../modernize/UseEmplaceCheck.h" @@ -83,7 +83,7 @@ CheckFactories.registerCheck( "hicpp-static-assert"); CheckFactories.registerCheck("hicpp-use-auto"); - CheckFactories.registerCheck( + CheckFactories.registerCheck( "hicpp-undelegated-constructor"); CheckFactories.registerCheck( "hicpp-use-emplace"); Index: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt @@ -12,11 +12,7 @@ SizeofContainerCheck.cpp SizeofExpressionCheck.cpp StaticAssertCheck.cpp - SuspiciousSemicolonCheck.cpp - SuspiciousStringCompareCheck.cpp - SwappedArgumentsCheck.cpp ThrowByValueCatchByReferenceCheck.cpp - UndelegatedConstructor.cpp UniqueptrResetReleaseCheck.cpp UnusedAliasDeclsCheck.cpp UnusedParametersCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp @@ -19,12 +19,8 @@ #include "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" #include "StaticAssertCheck.h" -#include "SuspiciousSemicolonCheck.h" -#include "SuspiciousStringCompareCheck.h" -#include "SwappedArgumentsCheck.h" #include "ThrowByValueCatchByReferenceCheck.h" #include "UnconventionalAssignOperatorCheck.h" -#include "UndelegatedConstructor.h" #include "UniqueptrResetReleaseCheck.h" #include "UnusedAliasDeclsCheck.h" #include "UnusedParametersCheck.h" @@ -55,16 +51,8 @@ CheckFactories.registerCheck( "misc-sizeof-expression"); CheckFactories.registerCheck("misc-static-assert"); - CheckFactories.registerCheck( - "misc-suspicious-semicolon"); - CheckFactories.registerCheck( - "misc-suspicious-string-compare"); - CheckFactories.registerCheck( - "misc-swapped-arguments"); CheckFactories.registerCheck( "misc-throw-by-value-catch-by-reference"); - CheckFactories.registerCheck( - "misc-undelegated-constructor"); CheckFactories.registerCheck( "misc-uniqueptr-reset-release"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/misc/SuspiciousSemicolonCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/SuspiciousSemicolonCheck.h +++ clang-tools-extra/trunk/clang-tidy/misc/SuspiciousSemicolonCheck.h @@ -1,36 +0,0 @@ -//===--- SuspiciousSemicolonCheck.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_SEMICOLON_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_SEMICOLON_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// This check finds semicolon that modifies the meaning of the program -/// unintendedly. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-suspicious-semicolon.html -class SuspiciousSemicolonCheck : public ClangTidyCheck { -public: - SuspiciousSemicolonCheck(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_SUSPICIOUS_SEMICOLON_H Index: clang-tools-extra/trunk/clang-tidy/misc/SuspiciousSemicolonCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/SuspiciousSemicolonCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/SuspiciousSemicolonCheck.cpp @@ -1,77 +0,0 @@ -//===--- SuspiciousSemicolonCheck.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 "SuspiciousSemicolonCheck.h" -#include "../utils/LexerUtils.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -void SuspiciousSemicolonCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - stmt(anyOf(ifStmt(hasThen(nullStmt().bind("semi")), - unless(hasElse(stmt()))), - forStmt(hasBody(nullStmt().bind("semi"))), - cxxForRangeStmt(hasBody(nullStmt().bind("semi"))), - whileStmt(hasBody(nullStmt().bind("semi"))))) - .bind("stmt"), - this); -} - -void SuspiciousSemicolonCheck::check(const MatchFinder::MatchResult &Result) { - if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred()) - return; - - const auto *Semicolon = Result.Nodes.getNodeAs("semi"); - SourceLocation LocStart = Semicolon->getLocStart(); - - if (LocStart.isMacroID()) - return; - - ASTContext &Ctxt = *Result.Context; - auto Token = utils::lexer::getPreviousToken(Ctxt, LocStart); - auto &SM = *Result.SourceManager; - unsigned SemicolonLine = SM.getSpellingLineNumber(LocStart); - - const auto *Statement = Result.Nodes.getNodeAs("stmt"); - const bool IsIfStmt = isa(Statement); - - if (!IsIfStmt && - SM.getSpellingLineNumber(Token.getLocation()) != SemicolonLine) - return; - - SourceLocation LocEnd = Semicolon->getLocEnd(); - FileID FID = SM.getFileID(LocEnd); - llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd); - Lexer Lexer(SM.getLocForStartOfFile(FID), Ctxt.getLangOpts(), - Buffer->getBufferStart(), SM.getCharacterData(LocEnd) + 1, - Buffer->getBufferEnd()); - if (Lexer.LexFromRawLexer(Token)) - return; - - unsigned BaseIndent = SM.getSpellingColumnNumber(Statement->getLocStart()); - unsigned NewTokenIndent = SM.getSpellingColumnNumber(Token.getLocation()); - unsigned NewTokenLine = SM.getSpellingLineNumber(Token.getLocation()); - - if (!IsIfStmt && NewTokenIndent <= BaseIndent && - Token.getKind() != tok::l_brace && NewTokenLine != SemicolonLine) - return; - - diag(LocStart, "potentially unintended semicolon") - << FixItHint::CreateRemoval(SourceRange(LocStart, LocEnd)); -} - -} // namespace misc -} // namespace tidy -} // namespace clang Index: clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.h +++ clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.h @@ -1,40 +0,0 @@ -//===--- SuspiciousStringCompareCheck.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_STRING_COMPARE_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_STRING_COMPARE_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// Find suspicious calls to string compare functions. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-suspicious-string-compare.html -class SuspiciousStringCompareCheck : public ClangTidyCheck { -public: - SuspiciousStringCompareCheck(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: - const bool WarnOnImplicitComparison; - const bool WarnOnLogicalNotComparison; - const std::string StringCompareLikeFunctions; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_STRING_COMPARE_H Index: clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.cpp @@ -1,218 +0,0 @@ -//===--- SuspiciousStringCompareCheck.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 "SuspiciousStringCompareCheck.h" -#include "../utils/Matchers.h" -#include "../utils/OptionsUtils.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 { - -// Semicolon separated list of known string compare-like functions. The list -// must ends with a semicolon. -static const char KnownStringCompareFunctions[] = "__builtin_memcmp;" - "__builtin_strcasecmp;" - "__builtin_strcmp;" - "__builtin_strncasecmp;" - "__builtin_strncmp;" - "_mbscmp;" - "_mbscmp_l;" - "_mbsicmp;" - "_mbsicmp_l;" - "_mbsnbcmp;" - "_mbsnbcmp_l;" - "_mbsnbicmp;" - "_mbsnbicmp_l;" - "_mbsncmp;" - "_mbsncmp_l;" - "_mbsnicmp;" - "_mbsnicmp_l;" - "_memicmp;" - "_memicmp_l;" - "_stricmp;" - "_stricmp_l;" - "_strnicmp;" - "_strnicmp_l;" - "_wcsicmp;" - "_wcsicmp_l;" - "_wcsnicmp;" - "_wcsnicmp_l;" - "lstrcmp;" - "lstrcmpi;" - "memcmp;" - "memicmp;" - "strcasecmp;" - "strcmp;" - "strcmpi;" - "stricmp;" - "strncasecmp;" - "strncmp;" - "strnicmp;" - "wcscasecmp;" - "wcscmp;" - "wcsicmp;" - "wcsncmp;" - "wcsnicmp;" - "wmemcmp;"; - -SuspiciousStringCompareCheck::SuspiciousStringCompareCheck( - StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - WarnOnImplicitComparison(Options.get("WarnOnImplicitComparison", 1)), - WarnOnLogicalNotComparison(Options.get("WarnOnLogicalNotComparison", 0)), - StringCompareLikeFunctions( - Options.get("StringCompareLikeFunctions", "")) {} - -void SuspiciousStringCompareCheck::storeOptions( - ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "WarnOnImplicitComparison", WarnOnImplicitComparison); - Options.store(Opts, "WarnOnLogicalNotComparison", WarnOnLogicalNotComparison); - Options.store(Opts, "StringCompareLikeFunctions", StringCompareLikeFunctions); -} - -void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) { - // Match relational operators. - const auto ComparisonUnaryOperator = unaryOperator(hasOperatorName("!")); - const auto ComparisonBinaryOperator = - binaryOperator(matchers::isComparisonOperator()); - const auto ComparisonOperator = - expr(anyOf(ComparisonUnaryOperator, ComparisonBinaryOperator)); - - // Add the list of known string compare-like functions and add user-defined - // functions. - std::vector FunctionNames = utils::options::parseStringList( - (llvm::Twine(KnownStringCompareFunctions) + StringCompareLikeFunctions) - .str()); - - // Match a call to a string compare functions. - const auto FunctionCompareDecl = - functionDecl(hasAnyName(std::vector(FunctionNames.begin(), - FunctionNames.end()))) - .bind("decl"); - const auto DirectStringCompareCallExpr = - callExpr(hasDeclaration(FunctionCompareDecl)).bind("call"); - const auto MacroStringCompareCallExpr = conditionalOperator(anyOf( - hasTrueExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)), - hasFalseExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)))); - // The implicit cast is not present in C. - const auto StringCompareCallExpr = ignoringParenImpCasts( - anyOf(DirectStringCompareCallExpr, MacroStringCompareCallExpr)); - - if (WarnOnImplicitComparison) { - // Detect suspicious calls to string compare: - // 'if (strcmp())' -> 'if (strcmp() != 0)' - Finder->addMatcher( - stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)), - whileStmt(hasCondition(StringCompareCallExpr)), - doStmt(hasCondition(StringCompareCallExpr)), - forStmt(hasCondition(StringCompareCallExpr)), - binaryOperator( - anyOf(hasOperatorName("&&"), hasOperatorName("||")), - hasEitherOperand(StringCompareCallExpr)))) - .bind("missing-comparison"), - this); - } - - if (WarnOnLogicalNotComparison) { - // Detect suspicious calls to string compared with '!' operator: - // 'if (!strcmp())' -> 'if (strcmp() == 0)' - Finder->addMatcher(unaryOperator(hasOperatorName("!"), - hasUnaryOperand(ignoringParenImpCasts( - StringCompareCallExpr))) - .bind("logical-not-comparison"), - this); - } - - // Detect suspicious cast to an inconsistant type (i.e. not integer type). - Finder->addMatcher( - implicitCastExpr(unless(hasType(isInteger())), - hasSourceExpression(StringCompareCallExpr)) - .bind("invalid-conversion"), - this); - - // Detect suspicious operator with string compare function as operand. - Finder->addMatcher( - binaryOperator( - unless(anyOf(matchers::isComparisonOperator(), hasOperatorName("&&"), - hasOperatorName("||"), hasOperatorName("="))), - hasEitherOperand(StringCompareCallExpr)) - .bind("suspicious-operator"), - this); - - // Detect comparison to invalid constant: 'strcmp() == -1'. - const auto InvalidLiteral = ignoringParenImpCasts( - anyOf(integerLiteral(unless(equals(0))), - unaryOperator( - hasOperatorName("-"), - has(ignoringParenImpCasts(integerLiteral(unless(equals(0)))))), - characterLiteral(), cxxBoolLiteral())); - - Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(), - hasEitherOperand(StringCompareCallExpr), - hasEitherOperand(InvalidLiteral)) - .bind("invalid-comparison"), - this); -} - -void SuspiciousStringCompareCheck::check( - const MatchFinder::MatchResult &Result) { - const auto *Decl = Result.Nodes.getNodeAs("decl"); - const auto *Call = Result.Nodes.getNodeAs("call"); - assert(Decl != nullptr && Call != nullptr); - - if (Result.Nodes.getNodeAs("missing-comparison")) { - SourceLocation EndLoc = Lexer::getLocForEndOfToken( - Call->getRParenLoc(), 0, Result.Context->getSourceManager(), - getLangOpts()); - - diag(Call->getLocStart(), - "function %0 is called without explicitly comparing result") - << Decl << FixItHint::CreateInsertion(EndLoc, " != 0"); - } - - if (const auto *E = Result.Nodes.getNodeAs("logical-not-comparison")) { - SourceLocation EndLoc = Lexer::getLocForEndOfToken( - Call->getRParenLoc(), 0, Result.Context->getSourceManager(), - getLangOpts()); - SourceLocation NotLoc = E->getLocStart(); - - diag(Call->getLocStart(), - "function %0 is compared using logical not operator") - << Decl << FixItHint::CreateRemoval( - CharSourceRange::getTokenRange(NotLoc, NotLoc)) - << FixItHint::CreateInsertion(EndLoc, " == 0"); - } - - if (Result.Nodes.getNodeAs("invalid-comparison")) { - diag(Call->getLocStart(), - "function %0 is compared to a suspicious constant") - << Decl; - } - - if (const auto *BinOp = - Result.Nodes.getNodeAs("suspicious-operator")) { - diag(Call->getLocStart(), "results of function %0 used by operator '%1'") - << Decl << BinOp->getOpcodeStr(); - } - - if (Result.Nodes.getNodeAs("invalid-conversion")) { - diag(Call->getLocStart(), "function %0 has suspicious implicit cast") - << Decl; - } -} - -} // namespace misc -} // namespace tidy -} // namespace clang Index: clang-tools-extra/trunk/clang-tidy/misc/SwappedArgumentsCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/SwappedArgumentsCheck.h +++ clang-tools-extra/trunk/clang-tidy/misc/SwappedArgumentsCheck.h @@ -1,32 +0,0 @@ -//===--- SwappedArgumentsCheck.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_SWAPPEDARGUMENTSCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SWAPPEDARGUMENTSCHECK_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// Finds potentially swapped arguments by looking at implicit conversions. -class SwappedArgumentsCheck : public ClangTidyCheck { -public: - SwappedArgumentsCheck(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_SWAPPEDARGUMENTSCHECK_H Index: clang-tools-extra/trunk/clang-tidy/misc/SwappedArgumentsCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/SwappedArgumentsCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/SwappedArgumentsCheck.cpp @@ -1,102 +0,0 @@ -//===--- SwappedArgumentsCheck.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 "SwappedArgumentsCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/Lex/Lexer.h" -#include "clang/Tooling/FixIt.h" -#include "llvm/ADT/SmallPtrSet.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -void SwappedArgumentsCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(callExpr().bind("call"), this); -} - -/// \brief Look through lvalue to rvalue and nop casts. This filters out -/// implicit conversions that have no effect on the input but block our view for -/// other implicit casts. -static const Expr *ignoreNoOpCasts(const Expr *E) { - if (auto *Cast = dyn_cast(E)) - if (Cast->getCastKind() == CK_LValueToRValue || - Cast->getCastKind() == CK_NoOp) - return ignoreNoOpCasts(Cast->getSubExpr()); - return E; -} - -/// \brief Restrict the warning to implicit casts that are most likely -/// accidental. User defined or integral conversions fit in this category, -/// lvalue to rvalue or derived to base does not. -static bool isImplicitCastCandidate(const CastExpr *Cast) { - return Cast->getCastKind() == CK_UserDefinedConversion || - Cast->getCastKind() == CK_FloatingToBoolean || - Cast->getCastKind() == CK_FloatingToIntegral || - Cast->getCastKind() == CK_IntegralToBoolean || - Cast->getCastKind() == CK_IntegralToFloating || - Cast->getCastKind() == CK_MemberPointerToBoolean || - Cast->getCastKind() == CK_PointerToBoolean; -} - -void SwappedArgumentsCheck::check(const MatchFinder::MatchResult &Result) { - const ASTContext &Ctx = *Result.Context; - const auto *Call = Result.Nodes.getNodeAs("call"); - - llvm::SmallPtrSet UsedArgs; - for (unsigned I = 1, E = Call->getNumArgs(); I < E; ++I) { - const Expr *LHS = Call->getArg(I - 1); - const Expr *RHS = Call->getArg(I); - - // Only need to check RHS, as LHS has already been covered. We don't want to - // emit two warnings for a single argument. - if (UsedArgs.count(RHS)) - continue; - - const auto *LHSCast = dyn_cast(ignoreNoOpCasts(LHS)); - const auto *RHSCast = dyn_cast(ignoreNoOpCasts(RHS)); - - // Look if this is a potentially swapped argument pair. First look for - // implicit casts. - if (!LHSCast || !RHSCast || !isImplicitCastCandidate(LHSCast) || - !isImplicitCastCandidate(RHSCast)) - continue; - - // If the types that go into the implicit casts match the types of the other - // argument in the declaration there is a high probability that the - // arguments were swapped. - // TODO: We could make use of the edit distance between the argument name - // and the name of the passed variable in addition to this type based - // heuristic. - const Expr *LHSFrom = ignoreNoOpCasts(LHSCast->getSubExpr()); - const Expr *RHSFrom = ignoreNoOpCasts(RHSCast->getSubExpr()); - if (LHS->getType() == RHS->getType() || - LHS->getType() != RHSFrom->getType() || - RHS->getType() != LHSFrom->getType()) - continue; - - // Emit a warning and fix-its that swap the arguments. - diag(Call->getLocStart(), "argument with implicit conversion from %0 " - "to %1 followed by argument converted from " - "%2 to %3, potentially swapped arguments.") - << LHS->getType() << LHSFrom->getType() << RHS->getType() - << RHSFrom->getType() - << tooling::fixit::createReplacement(*LHS, *RHS, Ctx) - << tooling::fixit::createReplacement(*RHS, *LHS, Ctx); - - // Remember that we emitted a warning for this argument. - UsedArgs.insert(RHSCast); - } -} - -} // namespace misc -} // namespace tidy -} // namespace clang Index: clang-tools-extra/trunk/clang-tidy/misc/UndelegatedConstructor.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/UndelegatedConstructor.h +++ clang-tools-extra/trunk/clang-tidy/misc/UndelegatedConstructor.h @@ -1,36 +0,0 @@ -//===--- UndelegatedConstructor.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_UNDELEGATEDCONSTRUCTOR_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNDELEGATEDCONSTRUCTOR_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// Finds creation of temporary objects in constructors that look like a -/// function call to another constructor of the same class. -/// -/// The user most likely meant to use a delegating constructor or base class -/// initializer. -class UndelegatedConstructorCheck : public ClangTidyCheck { -public: - UndelegatedConstructorCheck(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_UNDELEGATEDCONSTRUCTOR_H Index: clang-tools-extra/trunk/clang-tidy/misc/UndelegatedConstructor.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/UndelegatedConstructor.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/UndelegatedConstructor.cpp @@ -1,84 +0,0 @@ -//===--- UndelegatedConstructor.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 "UndelegatedConstructor.h" -#include "clang/AST/ASTContext.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -namespace { -AST_MATCHER_P(Stmt, ignoringTemporaryExpr, - ast_matchers::internal::Matcher, InnerMatcher) { - const Stmt *E = &Node; - for (;;) { - // Temporaries with non-trivial dtors. - if (const auto *EWC = dyn_cast(E)) - E = EWC->getSubExpr(); - // Temporaries with zero or more than two ctor arguments. - else if (const auto *BTE = dyn_cast(E)) - E = BTE->getSubExpr(); - // Temporaries with exactly one ctor argument. - else if (const auto *FCE = dyn_cast(E)) - E = FCE->getSubExpr(); - else - break; - } - - return InnerMatcher.matches(*E, Finder, Builder); -} - -// Finds a node if it's a base of an already bound node. -AST_MATCHER_P(CXXRecordDecl, baseOfBoundNode, std::string, ID) { - return Builder->removeBindings( - [&](const ast_matchers::internal::BoundNodesMap &Nodes) { - const auto *Derived = Nodes.getNodeAs(ID); - return Derived != &Node && !Derived->isDerivedFrom(&Node); - }); -} -} // namespace - -void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) { - // We look for calls to constructors of the same type in constructors. To do - // this we have to look through a variety of nodes that occur in the path, - // depending on the type's destructor and the number of arguments on the - // constructor call, this is handled by ignoringTemporaryExpr. Ignore template - // instantiations to reduce the number of duplicated warnings. - // - // Only register the matchers for C++11; the functionality currently does not - // provide any benefit to other languages, despite being benign. - if (!getLangOpts().CPlusPlus11) - return; - - Finder->addMatcher( - compoundStmt( - hasParent( - cxxConstructorDecl(ofClass(cxxRecordDecl().bind("parent")))), - forEach(ignoringTemporaryExpr( - cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass( - cxxRecordDecl(baseOfBoundNode("parent")))))) - .bind("construct"))), - unless(isInTemplateInstantiation())), - this); -} - -void UndelegatedConstructorCheck::check( - const MatchFinder::MatchResult &Result) { - const auto *E = Result.Nodes.getNodeAs("construct"); - diag(E->getLocStart(), "did you intend to call a delegated constructor? " - "A temporary object is created here instead"); -} - -} // namespace misc -} // namespace tidy -} // namespace clang Index: clang-tools-extra/trunk/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/trunk/docs/ReleaseNotes.rst +++ clang-tools-extra/trunk/docs/ReleaseNotes.rst @@ -136,6 +136,18 @@ - The 'misc-suspicious-missing-comma' check was renamed to `bugprone-suspicious-missing-comma `_ +- The 'misc-suspicious-semicolon' check was renamed to `bugprone-suspicious-semicolon + `_ + +- The 'misc-suspicious-string-compare' check was renamed to `bugprone-suspicious-string-compare + `_ + +- The 'misc-swapped-arguments' check was renamed to `bugprone-swapped-arguments + `_ + +- The 'misc-undelegated-constructor' check was renamed to `bugprone-undelegated-constructor + `_ + Improvements to include-fixer ----------------------------- Index: clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-suspicious-semicolon.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-suspicious-semicolon.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-suspicious-semicolon.rst @@ -0,0 +1,72 @@ +.. title:: clang-tidy - bugprone-suspicious-semicolon + +bugprone-suspicious-semicolon +============================= + +Finds most instances of stray semicolons that unexpectedly alter the meaning of +the code. More specifically, it looks for ``if``, ``while``, ``for`` and +``for-range`` statements whose body is a single semicolon, and then analyzes the +context of the code (e.g. indentation) in an attempt to determine whether that +is intentional. + + .. code-block:: c++ + + if (x < y); + { + x++; + } + +Here the body of the ``if`` statement consists of only the semicolon at the end +of the first line, and `x` will be incremented regardless of the condition. + + + .. code-block:: c++ + + while ((line = readLine(file)) != NULL); + processLine(line); + +As a result of this code, `processLine()` will only be called once, when the +``while`` loop with the empty body exits with `line == NULL`. The indentation of +the code indicates the intention of the programmer. + + + .. code-block:: c++ + + if (x >= y); + x -= y; + +While the indentation does not imply any nesting, there is simply no valid +reason to have an `if` statement with an empty body (but it can make sense for +a loop). So this check issues a warning for the code above. + +To solve the issue remove the stray semicolon or in case the empty body is +intentional, reflect this using code indentation or put the semicolon in a new +line. For example: + + .. code-block:: c++ + + while (readWhitespace()); + Token t = readNextToken(); + +Here the second line is indented in a way that suggests that it is meant to be +the body of the `while` loop - whose body is in fact empty, because of the +semicolon at the end of the first line. + +Either remove the indentation from the second line: + + .. code-block:: c++ + + while (readWhitespace()); + Token t = readNextToken(); + +... or move the semicolon from the end of the first line to a new line: + + .. code-block:: c++ + + while (readWhitespace()) + ; + + Token t = readNextToken(); + +In this case the check will assume that you know what you are doing, and will +not raise a warning. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-suspicious-string-compare.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-suspicious-string-compare.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-suspicious-string-compare.rst @@ -0,0 +1,64 @@ +.. title:: clang-tidy - bugprone-suspicious-string-compare + +bugprone-suspicious-string-compare +================================== + +Find suspicious usage of runtime string comparison functions. +This check is valid in C and C++. + +Checks for calls with implicit comparator and proposed to explicitly add it. + +.. code-block:: c++ + + if (strcmp(...)) // Implicitly compare to zero + if (!strcmp(...)) // Won't warn + if (strcmp(...) != 0) // Won't warn + +Checks that compare function results (i,e, ``strcmp``) are compared to valid +constant. The resulting value is + +.. code:: + + < 0 when lower than, + > 0 when greater than, + == 0 when equals. + +A common mistake is to compare the result to `1` or `-1`. + +.. code-block:: c++ + + if (strcmp(...) == -1) // Incorrect usage of the returned value. + +Additionally, the check warns if the results value is implicitly cast to a +*suspicious* non-integer type. It's happening when the returned value is used in +a wrong context. + +.. code-block:: c++ + + if (strcmp(...) < 0.) // Incorrect usage of the returned value. + +Options +------- + +.. option:: WarnOnImplicitComparison + + When non-zero, the check will warn on implicit comparison. `1` by default. + +.. option:: WarnOnLogicalNotComparison + + When non-zero, the check will warn on logical not comparison. `0` by default. + +.. option:: StringCompareLikeFunctions + + A string specifying the comma-separated names of the extra string comparison + functions. Default is an empty string. + The check will detect the following string comparison functions: + `__builtin_memcmp`, `__builtin_strcasecmp`, `__builtin_strcmp`, + `__builtin_strncasecmp`, `__builtin_strncmp`, `_mbscmp`, `_mbscmp_l`, + `_mbsicmp`, `_mbsicmp_l`, `_mbsnbcmp`, `_mbsnbcmp_l`, `_mbsnbicmp`, + `_mbsnbicmp_l`, `_mbsncmp`, `_mbsncmp_l`, `_mbsnicmp`, `_mbsnicmp_l`, + `_memicmp`, `_memicmp_l`, `_stricmp`, `_stricmp_l`, `_strnicmp`, + `_strnicmp_l`, `_wcsicmp`, `_wcsicmp_l`, `_wcsnicmp`, `_wcsnicmp_l`, + `lstrcmp`, `lstrcmpi`, `memcmp`, `memicmp`, `strcasecmp`, `strcmp`, + `strcmpi`, `stricmp`, `strncasecmp`, `strncmp`, `strnicmp`, `wcscasecmp`, + `wcscmp`, `wcsicmp`, `wcsncmp`, `wcsnicmp`, `wmemcmp`. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-swapped-arguments.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-swapped-arguments.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-swapped-arguments.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - bugprone-swapped-arguments + +bugprone-swapped-arguments +========================== + +Finds potentially swapped arguments by looking at implicit conversions. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-undelegated-constructor.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-undelegated-constructor.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-undelegated-constructor.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - bugprone-undelegated-constructor + +bugprone-undelegated-constructor +================================ + +Finds creation of temporary objects in constructors that look like a +function call to another constructor of the same class. + +The user most likely meant to use a delegating constructor or base class +initializer. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/hicpp-undelegated-constructor.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/hicpp-undelegated-constructor.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/hicpp-undelegated-constructor.rst @@ -1,11 +1,11 @@ .. title:: clang-tidy - hicpp-undelegated-construtor .. meta:: - :http-equiv=refresh: 5;URL=misc-undelegated-constructor.html + :http-equiv=refresh: 5;URL=bugprone-undelegated-constructor.html hicpp-undelegated-constructor ============================= -This check is an alias for `misc-undelegated-constructor `_. +This check is an alias for `bugprone-undelegated-constructor `_. Partially implements `rule 12.4.5 `_ to find misplaced constructor calls inside a constructor. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst @@ -40,8 +40,12 @@ bugprone-suspicious-enum-usage bugprone-suspicious-memset-usage bugprone-suspicious-missing-comma + bugprone-suspicious-semicolon + bugprone-suspicious-string-compare + bugprone-swapped-arguments bugprone-throw-keyword-missing bugprone-undefined-memory-manipulation + bugprone-undelegated-constructor bugprone-use-after-move bugprone-virtual-near-miss cert-dcl03-c (redirects to misc-static-assert) @@ -121,7 +125,7 @@ hicpp-signed-bitwise hicpp-special-member-functions (redirects to cppcoreguidelines-special-member-functions) hicpp-static-assert (redirects to misc-static-assert) - hicpp-undelegated-constructor (redirects to misc-undelegated-constructor) + hicpp-undelegated-constructor (redirects to bugprone-undelegated-constructor) hicpp-use-auto (redirects to modernize-use-auto) hicpp-use-emplace (redirects to modernize-use-emplace) hicpp-use-equals-default (redirects to modernize-use-equals-default) @@ -143,12 +147,8 @@ misc-sizeof-container misc-sizeof-expression misc-static-assert - misc-suspicious-semicolon - misc-suspicious-string-compare - misc-swapped-arguments misc-throw-by-value-catch-by-reference misc-unconventional-assign-operator - misc-undelegated-constructor misc-uniqueptr-reset-release misc-unused-alias-decls misc-unused-parameters Index: clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-semicolon.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-semicolon.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-semicolon.rst @@ -1,72 +0,0 @@ -.. title:: clang-tidy - misc-suspicious-semicolon - -misc-suspicious-semicolon -========================= - -Finds most instances of stray semicolons that unexpectedly alter the meaning of -the code. More specifically, it looks for ``if``, ``while``, ``for`` and -``for-range`` statements whose body is a single semicolon, and then analyzes the -context of the code (e.g. indentation) in an attempt to determine whether that -is intentional. - - .. code-block:: c++ - - if (x < y); - { - x++; - } - -Here the body of the ``if`` statement consists of only the semicolon at the end -of the first line, and `x` will be incremented regardless of the condition. - - - .. code-block:: c++ - - while ((line = readLine(file)) != NULL); - processLine(line); - -As a result of this code, `processLine()` will only be called once, when the -``while`` loop with the empty body exits with `line == NULL`. The indentation of -the code indicates the intention of the programmer. - - - .. code-block:: c++ - - if (x >= y); - x -= y; - -While the indentation does not imply any nesting, there is simply no valid -reason to have an `if` statement with an empty body (but it can make sense for -a loop). So this check issues a warning for the code above. - -To solve the issue remove the stray semicolon or in case the empty body is -intentional, reflect this using code indentation or put the semicolon in a new -line. For example: - - .. code-block:: c++ - - while (readWhitespace()); - Token t = readNextToken(); - -Here the second line is indented in a way that suggests that it is meant to be -the body of the `while` loop - whose body is in fact empty, because of the -semicolon at the end of the first line. - -Either remove the indentation from the second line: - - .. code-block:: c++ - - while (readWhitespace()); - Token t = readNextToken(); - -... or move the semicolon from the end of the first line to a new line: - - .. code-block:: c++ - - while (readWhitespace()) - ; - - Token t = readNextToken(); - -In this case the check will assume that you know what you are doing, and will -not raise a warning. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-string-compare.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-string-compare.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-string-compare.rst @@ -1,64 +0,0 @@ -.. title:: clang-tidy - misc-suspicious-string-compare - -misc-suspicious-string-compare -============================== - -Find suspicious usage of runtime string comparison functions. -This check is valid in C and C++. - -Checks for calls with implicit comparator and proposed to explicitly add it. - -.. code-block:: c++ - - if (strcmp(...)) // Implicitly compare to zero - if (!strcmp(...)) // Won't warn - if (strcmp(...) != 0) // Won't warn - -Checks that compare function results (i,e, ``strcmp``) are compared to valid -constant. The resulting value is - -.. code:: - - < 0 when lower than, - > 0 when greater than, - == 0 when equals. - -A common mistake is to compare the result to `1` or `-1`. - -.. code-block:: c++ - - if (strcmp(...) == -1) // Incorrect usage of the returned value. - -Additionally, the check warns if the results value is implicitly cast to a -*suspicious* non-integer type. It's happening when the returned value is used in -a wrong context. - -.. code-block:: c++ - - if (strcmp(...) < 0.) // Incorrect usage of the returned value. - -Options -------- - -.. option:: WarnOnImplicitComparison - - When non-zero, the check will warn on implicit comparison. `1` by default. - -.. option:: WarnOnLogicalNotComparison - - When non-zero, the check will warn on logical not comparison. `0` by default. - -.. option:: StringCompareLikeFunctions - - A string specifying the comma-separated names of the extra string comparison - functions. Default is an empty string. - The check will detect the following string comparison functions: - `__builtin_memcmp`, `__builtin_strcasecmp`, `__builtin_strcmp`, - `__builtin_strncasecmp`, `__builtin_strncmp`, `_mbscmp`, `_mbscmp_l`, - `_mbsicmp`, `_mbsicmp_l`, `_mbsnbcmp`, `_mbsnbcmp_l`, `_mbsnbicmp`, - `_mbsnbicmp_l`, `_mbsncmp`, `_mbsncmp_l`, `_mbsnicmp`, `_mbsnicmp_l`, - `_memicmp`, `_memicmp_l`, `_stricmp`, `_stricmp_l`, `_strnicmp`, - `_strnicmp_l`, `_wcsicmp`, `_wcsicmp_l`, `_wcsnicmp`, `_wcsnicmp_l`, - `lstrcmp`, `lstrcmpi`, `memcmp`, `memicmp`, `strcasecmp`, `strcmp`, - `strcmpi`, `stricmp`, `strncasecmp`, `strncmp`, `strnicmp`, `wcscasecmp`, - `wcscmp`, `wcsicmp`, `wcsncmp`, `wcsnicmp`, `wmemcmp`. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/misc-swapped-arguments.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/misc-swapped-arguments.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/misc-swapped-arguments.rst @@ -1,7 +0,0 @@ -.. title:: clang-tidy - misc-swapped-arguments - -misc-swapped-arguments -====================== - - -Finds potentially swapped arguments by looking at implicit conversions. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/misc-undelegated-constructor.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/misc-undelegated-constructor.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/misc-undelegated-constructor.rst @@ -1,11 +0,0 @@ -.. title:: clang-tidy - misc-undelegated-constructor - -misc-undelegated-constructor -============================ - - -Finds creation of temporary objects in constructors that look like a -function call to another constructor of the same class. - -The user most likely meant to use a delegating constructor or base class -initializer. Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-semicolon-fail.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-semicolon-fail.cpp +++ clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-semicolon-fail.cpp @@ -0,0 +1,26 @@ +// RUN: clang-tidy %s -checks="-*,bugprone-suspicious-semicolon" -- -DERROR 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-ERROR \ +// RUN: -implicit-check-not="{{warning|error}}:" +// RUN: clang-tidy %s -checks="-*,bugprone-suspicious-semicolon,clang-diagnostic*" \ +// RUN: -- -DWERROR -Wno-everything -Werror=unused-variable 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-WERROR \ +// RUN: -implicit-check-not="{{warning|error}}:" + +// Note: This test verifies that, the checker does not emit any warning for +// files that do not compile. + +bool g(); + +void f() { + if (g()); + // CHECK-WERROR: :[[@LINE-1]]:11: warning: potentially unintended semicolon [bugprone-suspicious-semicolon] +#if ERROR + int a + // CHECK-ERROR: :[[@LINE-1]]:8: error: expected ';' at end of declaration [clang-diagnostic-error] +#elif WERROR + int a; + // CHECK-WERROR: :[[@LINE-1]]:7: error: unused variable 'a' [clang-diagnostic-unused-variable] +#else +#error "One of ERROR or WERROR should be defined. +#endif +} Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-semicolon.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-semicolon.cpp +++ clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-semicolon.cpp @@ -0,0 +1,117 @@ +// RUN: %check_clang_tidy %s bugprone-suspicious-semicolon %t + +int x = 5; + +void nop(); + +void correct1() +{ + if(x < 5) nop(); +} + +void correct2() +{ + if(x == 5) + nop(); +} + +void correct3() +{ + if(x > 5) + { + nop(); + } +} + +void fail1() +{ + if(x > 5); nop(); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: potentially unintended semicolon [bugprone-suspicious-semicolon] + // CHECK-FIXES: if(x > 5) nop(); +} + +void fail2() +{ + if(x == 5); + nop(); + // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: potentially unintended semicolon [bugprone-suspicious-semicolon] + // CHECK-FIXES: if(x == 5){{$}} +} + +void fail3() +{ + if(x < 5); + { + nop(); + } + // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: potentially unintended semicolon + // CHECK-FIXES: if(x < 5){{$}} +} + +void correct4() +{ + while(x % 5 == 1); + nop(); +} + +void correct5() +{ + for(int i = 0; i < x; ++i) + ; +} + +void fail4() +{ + for(int i = 0; i < x; ++i); + nop(); + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: potentially unintended semicolon + // CHECK-FIXES: for(int i = 0; i < x; ++i){{$}} +} + +void fail5() +{ + if(x % 5 == 1); + nop(); + // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: potentially unintended semicolon + // CHECK-FIXES: if(x % 5 == 1){{$}} +} + +void fail6() { + int a = 0; + if (a != 0) { + } else if (a != 1); + a = 2; + // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: potentially unintended semicolon + // CHECK-FIXES: } else if (a != 1){{$}} +} + +void fail7() { + if (true) + ; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: potentially unintended semicolon +} + +void correct6() +{ + do; while(false); +} + +int correct7() +{ + int t_num = 0; + char c = 'b'; + char *s = "a"; + if (s == "(" || s != "'" || c == '"') { + t_num += 3; + return (c == ')' && c == '\''); + } + + return 0; +} + +void correct8() { + if (true) + ; + else { + } +} Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-string-compare.c =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-string-compare.c +++ clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-string-compare.c @@ -0,0 +1,79 @@ +// RUN: %check_clang_tidy %s bugprone-suspicious-string-compare %t -- \ +// RUN: -config='{CheckOptions: \ +// RUN: [{key: bugprone-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \ +// RUN: {key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \ +// RUN: -- -std=c99 + +static const char A[] = "abc"; + +int strcmp(const char *, const char *); + +int test_warning_patterns() { + if (strcmp(A, "a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [bugprone-suspicious-string-compare] + // CHECK-FIXES: if (strcmp(A, "a") != 0) + + if (strcmp(A, "a") != 0 || + strcmp(A, "b")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result + // CHECK-FIXES: strcmp(A, "b") != 0) + + if (strcmp(A, "a") == 1) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant + + if (strcmp(A, "a") == -1) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant + + if (strcmp(A, "a") < '0') + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant + + if (strcmp(A, "a") < 0.) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast + + if (!strcmp(A, "a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:8: warning: function 'strcmp' is compared using logical not operator + // CHECK-FIXES: if (strcmp(A, "a") == 0) +} + +void test_structure_patterns() { + if (strcmp(A, "a")) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: function 'strcmp' is called without explicitly comparing result + // CHECK-FIXES: if (strcmp(A, "a") != 0) {} + + while (strcmp(A, "a")) {} + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: function 'strcmp' is called without explicitly comparing result + // CHECK-FIXES: while (strcmp(A, "a") != 0) {} + + for (;strcmp(A, "a");) {} + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: function 'strcmp' is called without explicitly comparing result + // CHECK-FIXES: for (;strcmp(A, "a") != 0;) {} +} + +int test_valid_patterns() { + // The following cases are valid. + if (strcmp(A, "a") < 0) return 0; + if (strcmp(A, "a") == 0) return 0; + if (strcmp(A, "a") <= 0) return 0; + if (strcmp(A, "a") == strcmp(A, "b")) return 0; + return 1; +} + +int wrapper(const char* a, const char* b) { + return strcmp(a, b); +} + +int assignment_wrapper(const char* a, const char* b) { + int cmp = strcmp(a, b); + return cmp; +} + +int condexpr_wrapper(const char* a, const char* b) { + return (a < b) ? strcmp(a, b) : strcmp(b, a); +} Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-string-compare.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-string-compare.cpp +++ clang-tools-extra/trunk/test/clang-tidy/bugprone-suspicious-string-compare.cpp @@ -0,0 +1,337 @@ +// RUN: %check_clang_tidy %s bugprone-suspicious-string-compare %t -- \ +// RUN: -config='{CheckOptions: \ +// RUN: [{key: bugprone-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \ +// RUN: {key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \ +// RUN: -- + +typedef __SIZE_TYPE__ size; + +struct locale_t { + void* dummy; +} locale; + +static const char A[] = "abc"; +static const unsigned char U[] = "abc"; +static const unsigned char V[] = "xyz"; +static const wchar_t W[] = L"abc"; + +int strlen(const char *); + +int memcmp(const void *, const void *, size); +int wmemcmp(const wchar_t *, const wchar_t *, size); +int memicmp(const void *, const void *, size); +int _memicmp(const void *, const void *, size); +int _memicmp_l(const void *, const void *, size, locale_t); + +int strcmp(const char *, const char *); +int strncmp(const char *, const char *, size); +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size); +int stricmp(const char *, const char *); +int strcmpi(const char *, const char *); +int strnicmp(const char *, const char *, size); +int _stricmp(const char *, const char * ); +int _strnicmp(const char *, const char *, size); +int _stricmp_l(const char *, const char *, locale_t); +int _strnicmp_l(const char *, const char *, size, locale_t); + +int wcscmp(const wchar_t *, const wchar_t *); +int wcsncmp(const wchar_t *, const wchar_t *, size); +int wcscasecmp(const wchar_t *, const wchar_t *); +int wcsicmp(const wchar_t *, const wchar_t *); +int wcsnicmp(const wchar_t *, const wchar_t *, size); +int _wcsicmp(const wchar_t *, const wchar_t *); +int _wcsnicmp(const wchar_t *, const wchar_t *, size); +int _wcsicmp_l(const wchar_t *, const wchar_t *, locale_t); +int _wcsnicmp_l(const wchar_t *, const wchar_t *, size, locale_t); + +int _mbscmp(const unsigned char *, const unsigned char *); +int _mbsncmp(const unsigned char *, const unsigned char *, size); +int _mbsnbcmp(const unsigned char *, const unsigned char *, size); +int _mbsnbicmp(const unsigned char *, const unsigned char *, size); +int _mbsicmp(const unsigned char *, const unsigned char *); +int _mbsnicmp(const unsigned char *, const unsigned char *, size); +int _mbscmp_l(const unsigned char *, const unsigned char *, locale_t); +int _mbsncmp_l(const unsigned char *, const unsigned char *, size, locale_t); +int _mbsicmp_l(const unsigned char *, const unsigned char *, locale_t); +int _mbsnicmp_l(const unsigned char *, const unsigned char *, size, locale_t); +int _mbsnbcmp_l(const unsigned char *, const unsigned char *, size, locale_t); +int _mbsnbicmp_l(const unsigned char *, const unsigned char *, size, locale_t); + +int test_warning_patterns() { + if (strcmp(A, "a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [bugprone-suspicious-string-compare] + // CHECK-FIXES: if (strcmp(A, "a") != 0) + + if (strcmp(A, "a") == 0 || + strcmp(A, "b")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result + // CHECK-FIXES: strcmp(A, "b") != 0) + + if (strcmp(A, "a") == 1) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant + + if (strcmp(A, "a") == -1) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant + + if (strcmp(A, "a") == true) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant + + if (strcmp(A, "a") < '0') + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant + + if (strcmp(A, "a") < 0.) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast +} + +int test_valid_patterns() { + // The following cases are valid. + if (strcmp(A, "a") < 0) + return 0; + if (strcmp(A, "a") == 0) + return 0; + if (strcmp(A, "a") <= 0) + return 0; + + if (wcscmp(W, L"a") < 0) + return 0; + if (wcscmp(W, L"a") == 0) + return 0; + if (wcscmp(W, L"a") <= 0) + return 0; + + return 1; +} + +int test_implicit_compare_with_functions() { + + if (memcmp(A, "a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memcmp' is called without explicitly comparing result + // CHECK-FIXES: memcmp(A, "a", 1) != 0) + + if (wmemcmp(W, L"a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wmemcmp' is called without explicitly comparing result + // CHECK-FIXES: wmemcmp(W, L"a", 1) != 0) + + if (memicmp(A, "a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memicmp' is called without explicitly comparing result + // CHECK-FIXES: memicmp(A, "a", 1) != 0) + + if (_memicmp(A, "a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp' is called without explicitly comparing result + // CHECK-FIXES: _memicmp(A, "a", 1) != 0) + + if (_memicmp_l(A, "a", 1, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp_l' is called without explicitly comparing result + // CHECK-FIXES: _memicmp_l(A, "a", 1, locale) != 0) + + if (strcmp(A, "a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result + // CHECK-FIXES: strcmp(A, "a") != 0) + + if (strncmp(A, "a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncmp' is called without explicitly comparing result + // CHECK-FIXES: strncmp(A, "a", 1) != 0) + + if (strcasecmp(A, "a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcasecmp' is called without explicitly comparing result + // CHECK-FIXES: strcasecmp(A, "a") != 0) + + if (strncasecmp(A, "a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncasecmp' is called without explicitly comparing result + // CHECK-FIXES: strncasecmp(A, "a", 1) != 0) + + if (stricmp(A, "a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'stricmp' is called without explicitly comparing result + // CHECK-FIXES: stricmp(A, "a") != 0) + + if (strcmpi(A, "a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmpi' is called without explicitly comparing result + // CHECK-FIXES: strcmpi(A, "a") != 0) + + if (_stricmp(A, "a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp' is called without explicitly comparing result + // CHECK-FIXES: _stricmp(A, "a") != 0) + + if (strnicmp(A, "a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strnicmp' is called without explicitly comparing result + // CHECK-FIXES: strnicmp(A, "a", 1) != 0) + + if (_strnicmp(A, "a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp' is called without explicitly comparing result + // CHECK-FIXES: _strnicmp(A, "a", 1) != 0) + + if (_stricmp_l(A, "a", locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp_l' is called without explicitly comparing result + // CHECK-FIXES: _stricmp_l(A, "a", locale) != 0) + + if (_strnicmp_l(A, "a", 1, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp_l' is called without explicitly comparing result + // CHECK-FIXES: _strnicmp_l(A, "a", 1, locale) != 0) + + if (wcscmp(W, L"a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscmp' is called without explicitly comparing result + // CHECK-FIXES: wcscmp(W, L"a") != 0) + + if (wcsncmp(W, L"a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsncmp' is called without explicitly comparing result + // CHECK-FIXES: wcsncmp(W, L"a", 1) != 0) + + if (wcscasecmp(W, L"a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscasecmp' is called without explicitly comparing result + // CHECK-FIXES: wcscasecmp(W, L"a") != 0) + + if (wcsicmp(W, L"a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsicmp' is called without explicitly comparing result + // CHECK-FIXES: wcsicmp(W, L"a") != 0) + + if (_wcsicmp(W, L"a")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp' is called without explicitly comparing result + // CHECK-FIXES: _wcsicmp(W, L"a") != 0) + + if (_wcsicmp_l(W, L"a", locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp_l' is called without explicitly comparing result + // CHECK-FIXES: _wcsicmp_l(W, L"a", locale) != 0) + + if (wcsnicmp(W, L"a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsnicmp' is called without explicitly comparing result + // CHECK-FIXES: wcsnicmp(W, L"a", 1) != 0) + + if (_wcsnicmp(W, L"a", 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp' is called without explicitly comparing result + // CHECK-FIXES: _wcsnicmp(W, L"a", 1) != 0) + + if (_wcsnicmp_l(W, L"a", 1, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp_l' is called without explicitly comparing result + // CHECK-FIXES: _wcsnicmp_l(W, L"a", 1, locale) != 0) + + if (_mbscmp(U, V)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp' is called without explicitly comparing result + // CHECK-FIXES: _mbscmp(U, V) != 0) + + if (_mbsncmp(U, V, 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp' is called without explicitly comparing result + // CHECK-FIXES: _mbsncmp(U, V, 1) != 0) + + if (_mbsnbcmp(U, V, 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp' is called without explicitly comparing result + // CHECK-FIXES: _mbsnbcmp(U, V, 1) != 0) + + if (_mbsnbicmp(U, V, 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp' is called without explicitly comparing result + // CHECK-FIXES: _mbsnbicmp(U, V, 1) != 0) + + if (_mbsicmp(U, V)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp' is called without explicitly comparing result + // CHECK-FIXES: _mbsicmp(U, V) != 0) + + if (_mbsnicmp(U, V, 1)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp' is called without explicitly comparing result + // CHECK-FIXES: _mbsnicmp(U, V, 1) != 0) + + if (_mbscmp_l(U, V, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp_l' is called without explicitly comparing result + // CHECK-FIXES: _mbscmp_l(U, V, locale) != 0) + + if (_mbsncmp_l(U, V, 1, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp_l' is called without explicitly comparing result + // CHECK-FIXES: _mbsncmp_l(U, V, 1, locale) != 0) + + if (_mbsicmp_l(U, V, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp_l' is called without explicitly comparing result + // CHECK-FIXES: _mbsicmp_l(U, V, locale) != 0) + + if (_mbsnicmp_l(U, V, 1, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp_l' is called without explicitly comparing result + // CHECK-FIXES: _mbsnicmp_l(U, V, 1, locale) != 0) + + if (_mbsnbcmp_l(U, V, 1, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp_l' is called without explicitly comparing result + // CHECK-FIXES: _mbsnbcmp_l(U, V, 1, locale) != 0) + + if (_mbsnbicmp_l(U, V, 1, locale)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp_l' is called without explicitly comparing result + // CHECK-FIXES: _mbsnbicmp_l(U, V, 1, locale) != 0) + + return 1; +} + +int strcmp_wrapper1(const char* a, const char* b) { + return strcmp(a, b); +} + +int strcmp_wrapper2(const char* a, const char* b) { + return (a && b) ? strcmp(a, b) : 0; +} + +#define macro_strncmp(s1, s2, n) \ + (__extension__ (__builtin_constant_p (n) \ + && ((__builtin_constant_p (s1) \ + && strlen (s1) < ((size) (n))) \ + || (__builtin_constant_p (s2) \ + && strlen (s2) < ((size) (n)))) \ + ? strcmp (s1, s2) : strncmp (s1, s2, n))) + +int strncmp_macro(const char* a, const char* b) { + if (macro_strncmp(a, b, 4)) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result + + if (macro_strncmp(a, b, 4) == 2) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant + + if (macro_strncmp(a, b, 4) <= .0) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast + + if (macro_strncmp(a, b, 4) + 0) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: results of function 'strcmp' used by operator '+' + + return 1; +} Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-swapped-arguments.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/bugprone-swapped-arguments.cpp +++ clang-tools-extra/trunk/test/clang-tidy/bugprone-swapped-arguments.cpp @@ -0,0 +1,53 @@ +// RUN: %check_clang_tidy %s bugprone-swapped-arguments %t + +void F(int, double); + +int SomeFunction(); + +template +void G(T a, U b) { + F(a, b); // no-warning + F(2.0, 4); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. +// CHECK-FIXES: F(4, 2.0) +} + +void foo() { + F(1.0, 3); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. +// CHECK-FIXES: F(3, 1.0) + +#define M(x, y) x##y() + + double b = 1.0; + F(b, M(Some, Function)); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. +// CHECK-FIXES: F(M(Some, Function), b); + +#define N F(b, SomeFunction()) + + N; +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. +// In macro, don't emit fixits. +// CHECK-FIXES: #define N F(b, SomeFunction()) + + G(b, 3); + G(3, 1.0); + G(0, 0); + + F(1.0, 1.0); // no-warning + F(3, 1.0); // no-warning + F(true, false); // no-warning + F(0, 'c'); // no-warning + +#define APPLY(f, x, y) f(x, y) + APPLY(F, 1.0, 3); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. +// CHECK-FIXES: APPLY(F, 3, 1.0); + +#define PARAMS 1.0, 3 +#define CALL(P) F(P) + CALL(PARAMS); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. +// In macro, don't emit fixits. +} Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-undelegated-constructor-cxx98.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/bugprone-undelegated-constructor-cxx98.cpp +++ clang-tools-extra/trunk/test/clang-tidy/bugprone-undelegated-constructor-cxx98.cpp @@ -0,0 +1,23 @@ +// RUN: clang-tidy %s -checks=-*,bugprone-undelegated-constructor -- -std=c++98 | count 0 + +// Note: this test expects no diagnostics, but FileCheck cannot handle that, +// hence the use of | count 0. + +struct Ctor; +Ctor foo(); + +struct Ctor { + Ctor(); + Ctor(int); + Ctor(int, int); + Ctor(Ctor *i) { + Ctor(); + Ctor(0); + Ctor(1, 2); + foo(); + } +}; + +Ctor::Ctor() { + Ctor(1); +} Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-undelegated-constructor.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/bugprone-undelegated-constructor.cpp +++ clang-tools-extra/trunk/test/clang-tidy/bugprone-undelegated-constructor.cpp @@ -0,0 +1,54 @@ +// RUN: %check_clang_tidy %s bugprone-undelegated-constructor %t + +struct Ctor; +Ctor foo(); + +struct Ctor { + Ctor(); + Ctor(int); + Ctor(int, int); + Ctor(Ctor *i) { + Ctor(); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead [bugprone-undelegated-constructor] + Ctor(0); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? + Ctor(1, 2); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? + foo(); + } +}; + +Ctor::Ctor() { + Ctor(1); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: did you intend to call a delegated constructor? +} + +Ctor::Ctor(int i) : Ctor(i, 1) {} // properly delegated. + +struct Dtor { + Dtor(); + Dtor(int); + Dtor(int, int); + Dtor(Ctor *i) { + Dtor(); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? + Dtor(0); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? + Dtor(1, 2); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? + } + ~Dtor(); +}; + +struct Base {}; +struct Derived : public Base { + Derived() { Base(); } +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: did you intend to call a delegated constructor? +}; + +template +struct TDerived : public Base { + TDerived() { Base(); } +}; + +TDerived t; Index: clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-semicolon-fail.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-semicolon-fail.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-semicolon-fail.cpp @@ -1,26 +0,0 @@ -// RUN: clang-tidy %s -checks="-*,misc-suspicious-semicolon" -- -DERROR 2>&1 \ -// RUN: | FileCheck %s -check-prefix=CHECK-ERROR \ -// RUN: -implicit-check-not="{{warning|error}}:" -// RUN: clang-tidy %s -checks="-*,misc-suspicious-semicolon,clang-diagnostic*" \ -// RUN: -- -DWERROR -Wno-everything -Werror=unused-variable 2>&1 \ -// RUN: | FileCheck %s -check-prefix=CHECK-WERROR \ -// RUN: -implicit-check-not="{{warning|error}}:" - -// Note: This test verifies that, the checker does not emit any warning for -// files that do not compile. - -bool g(); - -void f() { - if (g()); - // CHECK-WERROR: :[[@LINE-1]]:11: warning: potentially unintended semicolon [misc-suspicious-semicolon] -#if ERROR - int a - // CHECK-ERROR: :[[@LINE-1]]:8: error: expected ';' at end of declaration [clang-diagnostic-error] -#elif WERROR - int a; - // CHECK-WERROR: :[[@LINE-1]]:7: error: unused variable 'a' [clang-diagnostic-unused-variable] -#else -#error "One of ERROR or WERROR should be defined. -#endif -} Index: clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-semicolon.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-semicolon.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-semicolon.cpp @@ -1,117 +0,0 @@ -// RUN: %check_clang_tidy %s misc-suspicious-semicolon %t - -int x = 5; - -void nop(); - -void correct1() -{ - if(x < 5) nop(); -} - -void correct2() -{ - if(x == 5) - nop(); -} - -void correct3() -{ - if(x > 5) - { - nop(); - } -} - -void fail1() -{ - if(x > 5); nop(); - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: potentially unintended semicolon [misc-suspicious-semicolon] - // CHECK-FIXES: if(x > 5) nop(); -} - -void fail2() -{ - if(x == 5); - nop(); - // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: potentially unintended semicolon [misc-suspicious-semicolon] - // CHECK-FIXES: if(x == 5){{$}} -} - -void fail3() -{ - if(x < 5); - { - nop(); - } - // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: potentially unintended semicolon - // CHECK-FIXES: if(x < 5){{$}} -} - -void correct4() -{ - while(x % 5 == 1); - nop(); -} - -void correct5() -{ - for(int i = 0; i < x; ++i) - ; -} - -void fail4() -{ - for(int i = 0; i < x; ++i); - nop(); - // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: potentially unintended semicolon - // CHECK-FIXES: for(int i = 0; i < x; ++i){{$}} -} - -void fail5() -{ - if(x % 5 == 1); - nop(); - // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: potentially unintended semicolon - // CHECK-FIXES: if(x % 5 == 1){{$}} -} - -void fail6() { - int a = 0; - if (a != 0) { - } else if (a != 1); - a = 2; - // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: potentially unintended semicolon - // CHECK-FIXES: } else if (a != 1){{$}} -} - -void fail7() { - if (true) - ; - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: potentially unintended semicolon -} - -void correct6() -{ - do; while(false); -} - -int correct7() -{ - int t_num = 0; - char c = 'b'; - char *s = "a"; - if (s == "(" || s != "'" || c == '"') { - t_num += 3; - return (c == ')' && c == '\''); - } - - return 0; -} - -void correct8() { - if (true) - ; - else { - } -} Index: clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.c =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.c +++ clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.c @@ -1,79 +0,0 @@ -// RUN: %check_clang_tidy %s misc-suspicious-string-compare %t -- \ -// RUN: -config='{CheckOptions: \ -// RUN: [{key: misc-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \ -// RUN: {key: misc-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \ -// RUN: -- -std=c99 - -static const char A[] = "abc"; - -int strcmp(const char *, const char *); - -int test_warning_patterns() { - if (strcmp(A, "a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [misc-suspicious-string-compare] - // CHECK-FIXES: if (strcmp(A, "a") != 0) - - if (strcmp(A, "a") != 0 || - strcmp(A, "b")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result - // CHECK-FIXES: strcmp(A, "b") != 0) - - if (strcmp(A, "a") == 1) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant - - if (strcmp(A, "a") == -1) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant - - if (strcmp(A, "a") < '0') - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant - - if (strcmp(A, "a") < 0.) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast - - if (!strcmp(A, "a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:8: warning: function 'strcmp' is compared using logical not operator - // CHECK-FIXES: if (strcmp(A, "a") == 0) -} - -void test_structure_patterns() { - if (strcmp(A, "a")) {} - // CHECK-MESSAGES: [[@LINE-1]]:7: warning: function 'strcmp' is called without explicitly comparing result - // CHECK-FIXES: if (strcmp(A, "a") != 0) {} - - while (strcmp(A, "a")) {} - // CHECK-MESSAGES: [[@LINE-1]]:10: warning: function 'strcmp' is called without explicitly comparing result - // CHECK-FIXES: while (strcmp(A, "a") != 0) {} - - for (;strcmp(A, "a");) {} - // CHECK-MESSAGES: [[@LINE-1]]:9: warning: function 'strcmp' is called without explicitly comparing result - // CHECK-FIXES: for (;strcmp(A, "a") != 0;) {} -} - -int test_valid_patterns() { - // The following cases are valid. - if (strcmp(A, "a") < 0) return 0; - if (strcmp(A, "a") == 0) return 0; - if (strcmp(A, "a") <= 0) return 0; - if (strcmp(A, "a") == strcmp(A, "b")) return 0; - return 1; -} - -int wrapper(const char* a, const char* b) { - return strcmp(a, b); -} - -int assignment_wrapper(const char* a, const char* b) { - int cmp = strcmp(a, b); - return cmp; -} - -int condexpr_wrapper(const char* a, const char* b) { - return (a < b) ? strcmp(a, b) : strcmp(b, a); -} Index: clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.cpp @@ -1,337 +0,0 @@ -// RUN: %check_clang_tidy %s misc-suspicious-string-compare %t -- \ -// RUN: -config='{CheckOptions: \ -// RUN: [{key: misc-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \ -// RUN: {key: misc-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \ -// RUN: -- - -typedef __SIZE_TYPE__ size; - -struct locale_t { - void* dummy; -} locale; - -static const char A[] = "abc"; -static const unsigned char U[] = "abc"; -static const unsigned char V[] = "xyz"; -static const wchar_t W[] = L"abc"; - -int strlen(const char *); - -int memcmp(const void *, const void *, size); -int wmemcmp(const wchar_t *, const wchar_t *, size); -int memicmp(const void *, const void *, size); -int _memicmp(const void *, const void *, size); -int _memicmp_l(const void *, const void *, size, locale_t); - -int strcmp(const char *, const char *); -int strncmp(const char *, const char *, size); -int strcasecmp(const char *, const char *); -int strncasecmp(const char *, const char *, size); -int stricmp(const char *, const char *); -int strcmpi(const char *, const char *); -int strnicmp(const char *, const char *, size); -int _stricmp(const char *, const char * ); -int _strnicmp(const char *, const char *, size); -int _stricmp_l(const char *, const char *, locale_t); -int _strnicmp_l(const char *, const char *, size, locale_t); - -int wcscmp(const wchar_t *, const wchar_t *); -int wcsncmp(const wchar_t *, const wchar_t *, size); -int wcscasecmp(const wchar_t *, const wchar_t *); -int wcsicmp(const wchar_t *, const wchar_t *); -int wcsnicmp(const wchar_t *, const wchar_t *, size); -int _wcsicmp(const wchar_t *, const wchar_t *); -int _wcsnicmp(const wchar_t *, const wchar_t *, size); -int _wcsicmp_l(const wchar_t *, const wchar_t *, locale_t); -int _wcsnicmp_l(const wchar_t *, const wchar_t *, size, locale_t); - -int _mbscmp(const unsigned char *, const unsigned char *); -int _mbsncmp(const unsigned char *, const unsigned char *, size); -int _mbsnbcmp(const unsigned char *, const unsigned char *, size); -int _mbsnbicmp(const unsigned char *, const unsigned char *, size); -int _mbsicmp(const unsigned char *, const unsigned char *); -int _mbsnicmp(const unsigned char *, const unsigned char *, size); -int _mbscmp_l(const unsigned char *, const unsigned char *, locale_t); -int _mbsncmp_l(const unsigned char *, const unsigned char *, size, locale_t); -int _mbsicmp_l(const unsigned char *, const unsigned char *, locale_t); -int _mbsnicmp_l(const unsigned char *, const unsigned char *, size, locale_t); -int _mbsnbcmp_l(const unsigned char *, const unsigned char *, size, locale_t); -int _mbsnbicmp_l(const unsigned char *, const unsigned char *, size, locale_t); - -int test_warning_patterns() { - if (strcmp(A, "a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [misc-suspicious-string-compare] - // CHECK-FIXES: if (strcmp(A, "a") != 0) - - if (strcmp(A, "a") == 0 || - strcmp(A, "b")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result - // CHECK-FIXES: strcmp(A, "b") != 0) - - if (strcmp(A, "a") == 1) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant - - if (strcmp(A, "a") == -1) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant - - if (strcmp(A, "a") == true) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant - - if (strcmp(A, "a") < '0') - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant - - if (strcmp(A, "a") < 0.) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast -} - -int test_valid_patterns() { - // The following cases are valid. - if (strcmp(A, "a") < 0) - return 0; - if (strcmp(A, "a") == 0) - return 0; - if (strcmp(A, "a") <= 0) - return 0; - - if (wcscmp(W, L"a") < 0) - return 0; - if (wcscmp(W, L"a") == 0) - return 0; - if (wcscmp(W, L"a") <= 0) - return 0; - - return 1; -} - -int test_implicit_compare_with_functions() { - - if (memcmp(A, "a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memcmp' is called without explicitly comparing result - // CHECK-FIXES: memcmp(A, "a", 1) != 0) - - if (wmemcmp(W, L"a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wmemcmp' is called without explicitly comparing result - // CHECK-FIXES: wmemcmp(W, L"a", 1) != 0) - - if (memicmp(A, "a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memicmp' is called without explicitly comparing result - // CHECK-FIXES: memicmp(A, "a", 1) != 0) - - if (_memicmp(A, "a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp' is called without explicitly comparing result - // CHECK-FIXES: _memicmp(A, "a", 1) != 0) - - if (_memicmp_l(A, "a", 1, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp_l' is called without explicitly comparing result - // CHECK-FIXES: _memicmp_l(A, "a", 1, locale) != 0) - - if (strcmp(A, "a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result - // CHECK-FIXES: strcmp(A, "a") != 0) - - if (strncmp(A, "a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncmp' is called without explicitly comparing result - // CHECK-FIXES: strncmp(A, "a", 1) != 0) - - if (strcasecmp(A, "a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcasecmp' is called without explicitly comparing result - // CHECK-FIXES: strcasecmp(A, "a") != 0) - - if (strncasecmp(A, "a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncasecmp' is called without explicitly comparing result - // CHECK-FIXES: strncasecmp(A, "a", 1) != 0) - - if (stricmp(A, "a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'stricmp' is called without explicitly comparing result - // CHECK-FIXES: stricmp(A, "a") != 0) - - if (strcmpi(A, "a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmpi' is called without explicitly comparing result - // CHECK-FIXES: strcmpi(A, "a") != 0) - - if (_stricmp(A, "a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp' is called without explicitly comparing result - // CHECK-FIXES: _stricmp(A, "a") != 0) - - if (strnicmp(A, "a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strnicmp' is called without explicitly comparing result - // CHECK-FIXES: strnicmp(A, "a", 1) != 0) - - if (_strnicmp(A, "a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp' is called without explicitly comparing result - // CHECK-FIXES: _strnicmp(A, "a", 1) != 0) - - if (_stricmp_l(A, "a", locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp_l' is called without explicitly comparing result - // CHECK-FIXES: _stricmp_l(A, "a", locale) != 0) - - if (_strnicmp_l(A, "a", 1, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp_l' is called without explicitly comparing result - // CHECK-FIXES: _strnicmp_l(A, "a", 1, locale) != 0) - - if (wcscmp(W, L"a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscmp' is called without explicitly comparing result - // CHECK-FIXES: wcscmp(W, L"a") != 0) - - if (wcsncmp(W, L"a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsncmp' is called without explicitly comparing result - // CHECK-FIXES: wcsncmp(W, L"a", 1) != 0) - - if (wcscasecmp(W, L"a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscasecmp' is called without explicitly comparing result - // CHECK-FIXES: wcscasecmp(W, L"a") != 0) - - if (wcsicmp(W, L"a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsicmp' is called without explicitly comparing result - // CHECK-FIXES: wcsicmp(W, L"a") != 0) - - if (_wcsicmp(W, L"a")) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp' is called without explicitly comparing result - // CHECK-FIXES: _wcsicmp(W, L"a") != 0) - - if (_wcsicmp_l(W, L"a", locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp_l' is called without explicitly comparing result - // CHECK-FIXES: _wcsicmp_l(W, L"a", locale) != 0) - - if (wcsnicmp(W, L"a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsnicmp' is called without explicitly comparing result - // CHECK-FIXES: wcsnicmp(W, L"a", 1) != 0) - - if (_wcsnicmp(W, L"a", 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp' is called without explicitly comparing result - // CHECK-FIXES: _wcsnicmp(W, L"a", 1) != 0) - - if (_wcsnicmp_l(W, L"a", 1, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp_l' is called without explicitly comparing result - // CHECK-FIXES: _wcsnicmp_l(W, L"a", 1, locale) != 0) - - if (_mbscmp(U, V)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp' is called without explicitly comparing result - // CHECK-FIXES: _mbscmp(U, V) != 0) - - if (_mbsncmp(U, V, 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp' is called without explicitly comparing result - // CHECK-FIXES: _mbsncmp(U, V, 1) != 0) - - if (_mbsnbcmp(U, V, 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp' is called without explicitly comparing result - // CHECK-FIXES: _mbsnbcmp(U, V, 1) != 0) - - if (_mbsnbicmp(U, V, 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp' is called without explicitly comparing result - // CHECK-FIXES: _mbsnbicmp(U, V, 1) != 0) - - if (_mbsicmp(U, V)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp' is called without explicitly comparing result - // CHECK-FIXES: _mbsicmp(U, V) != 0) - - if (_mbsnicmp(U, V, 1)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp' is called without explicitly comparing result - // CHECK-FIXES: _mbsnicmp(U, V, 1) != 0) - - if (_mbscmp_l(U, V, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp_l' is called without explicitly comparing result - // CHECK-FIXES: _mbscmp_l(U, V, locale) != 0) - - if (_mbsncmp_l(U, V, 1, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp_l' is called without explicitly comparing result - // CHECK-FIXES: _mbsncmp_l(U, V, 1, locale) != 0) - - if (_mbsicmp_l(U, V, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp_l' is called without explicitly comparing result - // CHECK-FIXES: _mbsicmp_l(U, V, locale) != 0) - - if (_mbsnicmp_l(U, V, 1, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp_l' is called without explicitly comparing result - // CHECK-FIXES: _mbsnicmp_l(U, V, 1, locale) != 0) - - if (_mbsnbcmp_l(U, V, 1, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp_l' is called without explicitly comparing result - // CHECK-FIXES: _mbsnbcmp_l(U, V, 1, locale) != 0) - - if (_mbsnbicmp_l(U, V, 1, locale)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp_l' is called without explicitly comparing result - // CHECK-FIXES: _mbsnbicmp_l(U, V, 1, locale) != 0) - - return 1; -} - -int strcmp_wrapper1(const char* a, const char* b) { - return strcmp(a, b); -} - -int strcmp_wrapper2(const char* a, const char* b) { - return (a && b) ? strcmp(a, b) : 0; -} - -#define macro_strncmp(s1, s2, n) \ - (__extension__ (__builtin_constant_p (n) \ - && ((__builtin_constant_p (s1) \ - && strlen (s1) < ((size) (n))) \ - || (__builtin_constant_p (s2) \ - && strlen (s2) < ((size) (n)))) \ - ? strcmp (s1, s2) : strncmp (s1, s2, n))) - -int strncmp_macro(const char* a, const char* b) { - if (macro_strncmp(a, b, 4)) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result - - if (macro_strncmp(a, b, 4) == 2) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant - - if (macro_strncmp(a, b, 4) <= .0) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast - - if (macro_strncmp(a, b, 4) + 0) - return 0; - // CHECK-MESSAGES: [[@LINE-2]]:7: warning: results of function 'strcmp' used by operator '+' - - return 1; -} Index: clang-tools-extra/trunk/test/clang-tidy/misc-swapped-arguments.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-swapped-arguments.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-swapped-arguments.cpp @@ -1,53 +0,0 @@ -// RUN: %check_clang_tidy %s misc-swapped-arguments %t - -void F(int, double); - -int SomeFunction(); - -template -void G(T a, U b) { - F(a, b); // no-warning - F(2.0, 4); -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// CHECK-FIXES: F(4, 2.0) -} - -void foo() { - F(1.0, 3); -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// CHECK-FIXES: F(3, 1.0) - -#define M(x, y) x##y() - - double b = 1.0; - F(b, M(Some, Function)); -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// CHECK-FIXES: F(M(Some, Function), b); - -#define N F(b, SomeFunction()) - - N; -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// In macro, don't emit fixits. -// CHECK-FIXES: #define N F(b, SomeFunction()) - - G(b, 3); - G(3, 1.0); - G(0, 0); - - F(1.0, 1.0); // no-warning - F(3, 1.0); // no-warning - F(true, false); // no-warning - F(0, 'c'); // no-warning - -#define APPLY(f, x, y) f(x, y) - APPLY(F, 1.0, 3); -// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// CHECK-FIXES: APPLY(F, 3, 1.0); - -#define PARAMS 1.0, 3 -#define CALL(P) F(P) - CALL(PARAMS); -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// In macro, don't emit fixits. -} Index: clang-tools-extra/trunk/test/clang-tidy/misc-undelegated-constructor-cxx98.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-undelegated-constructor-cxx98.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-undelegated-constructor-cxx98.cpp @@ -1,23 +0,0 @@ -// RUN: clang-tidy %s -checks=-*,misc-undelegated-constructor -- -std=c++98 | count 0 - -// Note: this test expects no diagnostics, but FileCheck cannot handle that, -// hence the use of | count 0. - -struct Ctor; -Ctor foo(); - -struct Ctor { - Ctor(); - Ctor(int); - Ctor(int, int); - Ctor(Ctor *i) { - Ctor(); - Ctor(0); - Ctor(1, 2); - foo(); - } -}; - -Ctor::Ctor() { - Ctor(1); -} Index: clang-tools-extra/trunk/test/clang-tidy/misc-undelegated-constructor.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-undelegated-constructor.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-undelegated-constructor.cpp @@ -1,54 +0,0 @@ -// RUN: %check_clang_tidy %s misc-undelegated-constructor %t - -struct Ctor; -Ctor foo(); - -struct Ctor { - Ctor(); - Ctor(int); - Ctor(int, int); - Ctor(Ctor *i) { - Ctor(); -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead [misc-undelegated-constructor] - Ctor(0); -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? - Ctor(1, 2); -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? - foo(); - } -}; - -Ctor::Ctor() { - Ctor(1); -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: did you intend to call a delegated constructor? -} - -Ctor::Ctor(int i) : Ctor(i, 1) {} // properly delegated. - -struct Dtor { - Dtor(); - Dtor(int); - Dtor(int, int); - Dtor(Ctor *i) { - Dtor(); -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? - Dtor(0); -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? - Dtor(1, 2); -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? - } - ~Dtor(); -}; - -struct Base {}; -struct Derived : public Base { - Derived() { Base(); } -// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: did you intend to call a delegated constructor? -}; - -template -struct TDerived : public Base { - TDerived() { Base(); } -}; - -TDerived t; Index: clang-tools-extra/trunk/test/clang-tidy/objc-arc-and-properties.m =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/objc-arc-and-properties.m +++ clang-tools-extra/trunk/test/clang-tidy/objc-arc-and-properties.m @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s misc-suspicious-semicolon %t +// RUN: %check_clang_tidy %s bugprone-suspicious-semicolon %t // This test checks if Objective-C 2.0 (@properties) and // Automatic Reference Counting (ARC) are enabled for .m files @@ -16,6 +16,6 @@ void fail(Foo *f) { if(f.shouldDoStuff); [f nop]; - // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: potentially unintended semicolon [misc-suspicious-semicolon] + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: potentially unintended semicolon [bugprone-suspicious-semicolon] // CHECK-FIXES: if(f.shouldDoStuff) [f nop]; } Index: clang-tools-extra/trunk/test/clang-tidy/objc-no-arc-or-properties.m =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/objc-no-arc-or-properties.m +++ clang-tools-extra/trunk/test/clang-tidy/objc-no-arc-or-properties.m @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s misc-suspicious-semicolon %t -- -- -fno-objc-arc -fobjc-abi-version=1 +// RUN: %check_clang_tidy %s bugprone-suspicious-semicolon %t -- -- -fno-objc-arc -fobjc-abi-version=1 // This test ensures check_clang_tidy.py allows disabling Objective-C ARC and // Objective-C 2.0 via passing arguments after -- on the command line. @@ -24,6 +24,6 @@ void fail(Foo *f) { if([f shouldDoStuff]); [f nop]; - // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: potentially unintended semicolon [misc-suspicious-semicolon] + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: potentially unintended semicolon [bugprone-suspicious-semicolon] // CHECK-FIXES: if([f shouldDoStuff]) [f nop]; }