Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -156,8 +156,6 @@ protected: OptionsView Options; - /// \brief Returns the main file name of the current translation unit. - StringRef getCurrentMainFile() const { return Context->getCurrentFile(); } }; class ClangTidyCheckFactories; Index: clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tidy/ClangTidyDiagnosticConsumer.h @@ -143,9 +143,6 @@ /// \brief Should be called when starting to process new translation unit. void setCurrentFile(StringRef File); - /// \brief Returns the main file name of the current translation unit. - StringRef getCurrentFile() const { return CurrentFile; } - /// \brief Sets ASTContext for the current translation unit. void setASTContext(ASTContext *Context); Index: clang-tidy/google/AvoidCStyleCastsCheck.cpp =================================================================== --- clang-tidy/google/AvoidCStyleCastsCheck.cpp +++ clang-tidy/google/AvoidCStyleCastsCheck.cpp @@ -93,23 +93,14 @@ if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context) .empty()) return; - // Ignore code in .c files and headers included from them, even if they are - // compiled as C++. - if (getCurrentMainFile().endswith(".c")) - return; - // Ignore code in .c files #included in other files (which shouldn't be done, - // but people still do this for test and other purposes). - SourceManager &SM = *Result.SourceManager; - if (SM.getFilename(SM.getSpellingLoc(CastExpr->getLocStart())).endswith(".c")) - return; // Leave type spelling exactly as it was (unlike // getTypeAsWritten().getAsString() which would spell enum types 'enum X'). - StringRef DestTypeString = - Lexer::getSourceText(CharSourceRange::getTokenRange( - CastExpr->getLParenLoc().getLocWithOffset(1), - CastExpr->getRParenLoc().getLocWithOffset(-1)), - SM, Result.Context->getLangOpts()); + StringRef DestTypeString = Lexer::getSourceText( + CharSourceRange::getTokenRange( + CastExpr->getLParenLoc().getLocWithOffset(1), + CastExpr->getRParenLoc().getLocWithOffset(-1)), + *Result.SourceManager, Result.Context->getLangOpts()); auto diag_builder = diag(CastExpr->getLocStart(), "C-style casts are discouraged. %0"); @@ -122,7 +113,8 @@ if (!isa(SubExpr)) { CastText.push_back('('); diag_builder << FixItHint::CreateInsertion( - Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0, SM, + Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0, + *Result.SourceManager, Result.Context->getLangOpts()), ")"); } Index: clang-tidy/misc/AssertSideEffectCheck.cpp =================================================================== --- clang-tidy/misc/AssertSideEffectCheck.cpp +++ clang-tidy/misc/AssertSideEffectCheck.cpp @@ -55,13 +55,9 @@ if (const auto *CExpr = dyn_cast(E)) { bool Result = CheckFunctionCalls; - if (const auto *FuncDecl = CExpr->getDirectCallee()) { - if (FuncDecl->getDeclName().isIdentifier() && - FuncDecl->getName() == "__builtin_expect") // exceptions come here - Result = false; - else if (const auto *MethodDecl = dyn_cast(FuncDecl)) + if (const auto *FuncDecl = CExpr->getDirectCallee()) + if (const auto *MethodDecl = dyn_cast(FuncDecl)) Result &= !MethodDecl->isConst(); - } return Result; } Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -8,7 +8,6 @@ InaccurateEraseCheck.cpp InefficientAlgorithmCheck.cpp MiscTidyModule.cpp - NoexceptMoveConstructorCheck.cpp StaticAssertCheck.cpp SwappedArgumentsCheck.cpp UndelegatedConstructor.cpp Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -16,7 +16,6 @@ #include "BoolPointerImplicitConversionCheck.h" #include "InaccurateEraseCheck.h" #include "InefficientAlgorithmCheck.h" -#include "NoexceptMoveConstructorCheck.h" #include "StaticAssertCheck.h" #include "SwappedArgumentsCheck.h" #include "UndelegatedConstructor.h" @@ -42,8 +41,6 @@ "misc-inaccurate-erase"); CheckFactories.registerCheck( "misc-inefficient-algorithm"); - CheckFactories.registerCheck( - "misc-noexcept-move-constructor"); CheckFactories.registerCheck( "misc-static-assert"); CheckFactories.registerCheck( Index: clang-tidy/misc/NoexceptMoveConstructorCheck.h =================================================================== --- clang-tidy/misc/NoexceptMoveConstructorCheck.h +++ /dev/null @@ -1,37 +0,0 @@ -//===--- NoexceptMoveConstructorCheck.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_NOEXCEPTMOVECONSTRUCTORCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NOEXCEPTMOVECONSTRUCTORCHECK_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { - -/// \brief The check flags user-defined move constructors and assignment -/// operators not marked with \c noexcept or marked with \c noexcept(expr) where -/// \c expr evaluates to \c false (but is not a \c false literal itself). -/// -/// Move constructors of all the types used with STL containers, for example, -/// need to be declared \c noexcept. Otherwise STL will choose copy constructors -/// instead. The same is valid for move assignment operations. -class NoexceptMoveConstructorCheck : public ClangTidyCheck { -public: - NoexceptMoveConstructorCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NOEXCEPTMOVECONSTRUCTORCHECK_H - Index: clang-tidy/misc/NoexceptMoveConstructorCheck.cpp =================================================================== --- clang-tidy/misc/NoexceptMoveConstructorCheck.cpp +++ /dev/null @@ -1,67 +0,0 @@ -//===--- NoexceptMoveConstructorCheck.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 "NoexceptMoveConstructorCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { - -void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - methodDecl(anyOf(constructorDecl(), hasOverloadedOperatorName("=")), - unless(isImplicit()), unless(isDeleted())) - .bind("decl"), - this); -} - -void NoexceptMoveConstructorCheck::check( - const MatchFinder::MatchResult &Result) { - if (const auto *Decl = Result.Nodes.getNodeAs("decl")) { - StringRef MethodType = "assignment operator"; - if (const auto *Ctor = dyn_cast(Decl)) { - if (!Ctor->isMoveConstructor()) - return; - MethodType = "constructor"; - } else if (!Decl->isMoveAssignmentOperator()) { - return; - } - - const auto *ProtoType = Decl->getType()->getAs(); - switch(ProtoType->getNoexceptSpec(*Result.Context)) { - case FunctionProtoType::NR_NoNoexcept: - diag(Decl->getLocation(), "move %0s should be marked noexcept") - << MethodType; - // FIXME: Add a fixit. - break; - case FunctionProtoType::NR_Throw: - // Don't complain about nothrow(false), but complain on nothrow(expr) - // where expr evaluates to false. - if (const Expr *E = ProtoType->getNoexceptExpr()) { - if (isa(E)) - break; - diag(E->getExprLoc(), - "noexcept specifier on the move %0 evaluates to 'false'") - << MethodType; - } - break; - case FunctionProtoType::NR_Nothrow: - case FunctionProtoType::NR_Dependent: - case FunctionProtoType::NR_BadNoexcept: - break; - } - } -} - -} // namespace tidy -} // namespace clang - Index: clang-tidy/misc/StaticAssertCheck.cpp =================================================================== --- clang-tidy/misc/StaticAssertCheck.cpp +++ clang-tidy/misc/StaticAssertCheck.cpp @@ -39,20 +39,15 @@ anyOf(binaryOperator(hasEitherOperand(IsAlwaysFalseWithCast)), anything())).bind("assertExprRoot"), IsAlwaysFalse); - auto NonConstexprFunctionCall = - callExpr(hasDeclaration(functionDecl(unless(isConstexpr())))); - auto AssertCondition = expr(anyOf( + auto Condition = expr(anyOf( expr(ignoringParenCasts(anyOf( AssertExprRoot, unaryOperator(hasUnaryOperand(ignoringParenCasts(AssertExprRoot)))))), - anything()), unless(findAll(NonConstexprFunctionCall))).bind("condition"); - auto Condition = anyOf(ignoringParenImpCasts(callExpr( - hasDeclaration(functionDecl(hasName("__builtin_expect"))), - hasArgument(0, AssertCondition))), AssertCondition); + anything())); Finder->addMatcher( - stmt(anyOf(conditionalOperator(hasCondition(Condition)), - ifStmt(hasCondition(Condition))), + stmt(anyOf(conditionalOperator(hasCondition(Condition.bind("condition"))), + ifStmt(hasCondition(Condition.bind("condition")))), unless(isInTemplateInstantiation())).bind("condStmt"), this); } Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -10,6 +10,7 @@ ReadabilityTidyModule.cpp RedundantStringCStrCheck.cpp RedundantSmartptrGetCheck.cpp + RedundantVoidArgCheck.cpp ShrinkToFitCheck.cpp SimplifyBooleanExprCheck.cpp Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -17,6 +17,7 @@ #include "NamedParameterCheck.h" #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" +#include "RedundantVoidArgCheck.h" #include "ShrinkToFitCheck.h" #include "SimplifyBooleanExprCheck.h" @@ -41,10 +42,13 @@ "readability-redundant-smartptr-get"); CheckFactories.registerCheck( "readability-redundant-string-cstr"); + CheckFactories.registerCheck( + "readability-redundant-void-arg"); CheckFactories.registerCheck( "readability-shrink-to-fit"); CheckFactories.registerCheck( "readability-simplify-boolean-expr"); + CheckFactories.registerCheck("readability-shrink-to-fit"); } }; Index: clang-tidy/readability/RedundantVoidArgCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantVoidArgCheck.h @@ -0,0 +1,78 @@ +//===--- RedundantVoidArgCheck.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_READABILITY_REDUNDANT_VOID_ARG_CHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_VOID_ARG_CHECK_H + +#include "../ClangTidy.h" +#include "clang/Lex/Token.h" + +#include + +namespace clang { +namespace tidy { +namespace readability { + +/// \brief Find and remove redundant void argument lists. +/// +/// Examples: +/// int foo(void); ==> int foo(); +class RedundantVoidArgCheck : public ClangTidyCheck { +public: + RedundantVoidArgCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + void processFunctionDecl(const ast_matchers::MatchFinder::MatchResult &Result, + const FunctionDecl *Function); + + void processTypedefDecl(const ast_matchers::MatchFinder::MatchResult &Result, + const TypedefDecl *Typedef); + + void processFieldDecl(const ast_matchers::MatchFinder::MatchResult &Result, + const FieldDecl *Member); + + void processVarDecl(const ast_matchers::MatchFinder::MatchResult &Result, + const VarDecl *Var); + + void + processNamedCastExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const CXXNamedCastExpr *NamedCast); + + void + processCStyleCastExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const CStyleCastExpr *CStyleCast); + + void + processFunctionalCast(const ast_matchers::MatchFinder::MatchResult &Result, + const CXXFunctionalCastExpr *FunctionalCast); + + void + processExplicitCastExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const ExplicitCastExpr *ExplicitCast); + + void processLambdaExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const LambdaExpr *Lambda); + + void + removeVoidArgumentTokens(const ast_matchers::MatchFinder::MatchResult &Result, + SourceRange Range, StringRef GrammarLocation); + + void removeVoidToken(Token VoidToken, StringRef Diagnostic); +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_VOID_ARG_CHECK_H Index: clang-tidy/readability/RedundantVoidArgCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantVoidArgCheck.cpp @@ -0,0 +1,283 @@ +//===- RedundantVoidArgCheck.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 "RedundantVoidArgCheck.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { + +namespace { + +// Determine if the given QualType is a nullary function or pointer to same. +bool protoTypeHasNoParms(QualType QT) { + if (auto PT = QT->getAs()) { + QT = PT->getPointeeType(); + } + if (auto *MPT = QT->getAs()) { + QT = MPT->getPointeeType(); + } + if (auto FP = QT->getAs()) { + return FP->getNumParams() == 0; + } + return false; +} + +const char FunctionId[] = "function"; +const char TypedefId[] = "typedef"; +const char FieldId[] = "field"; +const char VarId[] = "var"; +const char NamedCastId[] = "named-cast"; +const char CStyleCastId[] = "c-style-cast"; +const char ExplicitCastId[] = "explicit-cast"; +const char FunctionalCastId[] = "fn-cast"; +const char LambdaId[] = "lambda"; + +} // namespace + +namespace tidy { +namespace readability { + +void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(functionDecl(isExpansionInMainFile(), parameterCountIs(0), + unless(isImplicit()), + unless(isExternC())).bind(FunctionId), + this); + Finder->addMatcher(typedefDecl(isExpansionInMainFile()).bind(TypedefId), + this); + auto ParenFunctionType = parenType(innerType(functionType())); + auto PointerToFunctionType = pointee(ParenFunctionType); + auto FunctionOrMemberPointer = + anyOf(hasType(pointerType(PointerToFunctionType)), + hasType(memberPointerType(PointerToFunctionType))); + Finder->addMatcher( + fieldDecl(isExpansionInMainFile(), FunctionOrMemberPointer).bind(FieldId), + this); + Finder->addMatcher( + varDecl(isExpansionInMainFile(), FunctionOrMemberPointer).bind(VarId), + this); + auto CastDestinationIsFunction = + hasDestinationType(pointsTo(ParenFunctionType)); + Finder->addMatcher( + cStyleCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(CStyleCastId), + this); + Finder->addMatcher( + staticCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(NamedCastId), + this); + Finder->addMatcher( + reinterpretCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(NamedCastId), + this); + Finder->addMatcher(constCastExpr(isExpansionInMainFile(), + CastDestinationIsFunction).bind(NamedCastId), + this); + Finder->addMatcher( + functionalCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(FunctionalCastId), + this); + Finder->addMatcher(lambdaExpr(isExpansionInMainFile()).bind(LambdaId), this); +} + +void RedundantVoidArgCheck::check(const MatchFinder::MatchResult &Result) { + if (!Result.Context->getLangOpts().CPlusPlus) { + return; + } + + const BoundNodes &Nodes = Result.Nodes; + if (const auto *Function = Nodes.getNodeAs(FunctionId)) { + processFunctionDecl(Result, Function); + } else if (const auto *Typedef = Nodes.getNodeAs(TypedefId)) { + processTypedefDecl(Result, Typedef); + } else if (const auto *Member = Nodes.getNodeAs(FieldId)) { + processFieldDecl(Result, Member); + } else if (const auto *Var = Nodes.getNodeAs(VarId)) { + processVarDecl(Result, Var); + } else if (const auto *NamedCast = + Nodes.getNodeAs(NamedCastId)) { + processNamedCastExpr(Result, NamedCast); + } else if (const auto *CStyleCast = + Nodes.getNodeAs(CStyleCastId)) { + processCStyleCastExpr(Result, CStyleCast); + } else if (const auto *FunctionalCast = + Nodes.getNodeAs(FunctionalCastId)) { + processFunctionalCast(Result, FunctionalCast); + } else if (const auto *ExplicitCast = + Nodes.getNodeAs(ExplicitCastId)) { + processExplicitCastExpr(Result, ExplicitCast); + } else if (const auto *Lambda = Nodes.getNodeAs(LambdaId)) { + processLambdaExpr(Result, Lambda); + } +} + +void RedundantVoidArgCheck::processFunctionDecl( + const MatchFinder::MatchResult &Result, const FunctionDecl *Function) { + SourceLocation Start = Function->getLocStart(); + if (Function->isThisDeclarationADefinition()) { + SourceLocation BeforeBody = + Function->getBody()->getLocStart().getLocWithOffset(-1); + removeVoidArgumentTokens(Result, SourceRange(Start, BeforeBody), + "function definition"); + } else { + removeVoidArgumentTokens(Result, Function->getSourceRange(), + "function declaration"); + } +} + +void RedundantVoidArgCheck::removeVoidArgumentTokens( + const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range, + StringRef GrammarLocation) { + std::string DeclText = + Lexer::getSourceText(CharSourceRange::getTokenRange(Range), + *Result.SourceManager, + Result.Context->getLangOpts()).str(); + Lexer PrototypeLexer(Range.getBegin(), Result.Context->getLangOpts(), + DeclText.data(), DeclText.data(), + DeclText.data() + DeclText.size()); + enum TokenState { + NothingYet, + SawLeftParen, + SawVoid, + }; + TokenState State = NothingYet; + Token VoidToken; + Token ProtoToken; + std::string Diagnostic = + ("redundant void argument list in " + GrammarLocation).str(); + + while (!PrototypeLexer.LexFromRawLexer(ProtoToken)) { + switch (State) { + case NothingYet: + if (ProtoToken.is(tok::TokenKind::l_paren)) { + State = SawLeftParen; + } + break; + case SawLeftParen: + if (ProtoToken.is(tok::TokenKind::raw_identifier) && + ProtoToken.getRawIdentifier() == "void") { + State = SawVoid; + VoidToken = ProtoToken; + } else { + State = NothingYet; + } + break; + case SawVoid: + State = NothingYet; + if (ProtoToken.is(tok::TokenKind::r_paren)) { + removeVoidToken(VoidToken, Diagnostic); + } else if (ProtoToken.is(tok::TokenKind::l_paren)) { + State = SawLeftParen; + } + break; + } + } + + if (State == SawVoid && ProtoToken.is(tok::TokenKind::r_paren)) { + removeVoidToken(VoidToken, Diagnostic); + } +} + +void RedundantVoidArgCheck::removeVoidToken(Token VoidToken, + StringRef Diagnostic) { + SourceLocation VoidLoc(VoidToken.getLocation()); + auto VoidRange = + CharSourceRange::getTokenRange(VoidLoc, VoidLoc.getLocWithOffset(3)); + diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidRange); +} + +void RedundantVoidArgCheck::processTypedefDecl( + const MatchFinder::MatchResult &Result, const TypedefDecl *Typedef) { + if (protoTypeHasNoParms(Typedef->getUnderlyingType())) { + removeVoidArgumentTokens(Result, Typedef->getSourceRange(), "typedef"); + } +} + +void RedundantVoidArgCheck::processFieldDecl( + const MatchFinder::MatchResult &Result, const FieldDecl *Member) { + if (protoTypeHasNoParms(Member->getType())) { + removeVoidArgumentTokens(Result, Member->getSourceRange(), + "field declaration"); + } +} + +void RedundantVoidArgCheck::processVarDecl( + const MatchFinder::MatchResult &Result, const VarDecl *Var) { + if (protoTypeHasNoParms(Var->getType())) { + SourceLocation Begin = Var->getLocStart(); + if (Var->hasInit()) { + SourceLocation InitStart = + Result.SourceManager->getExpansionLoc(Var->getInit()->getLocStart()) + .getLocWithOffset(-1); + removeVoidArgumentTokens(Result, SourceRange(Begin, InitStart), + "variable declaration with initializer"); + } else { + removeVoidArgumentTokens(Result, Var->getSourceRange(), + "variable declaration"); + } + } +} + +void RedundantVoidArgCheck::processNamedCastExpr( + const MatchFinder::MatchResult &Result, const CXXNamedCastExpr *NamedCast) { + if (protoTypeHasNoParms(NamedCast->getTypeAsWritten())) { + removeVoidArgumentTokens( + Result, + NamedCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(), + "named cast"); + } +} + +void RedundantVoidArgCheck::processCStyleCastExpr( + const MatchFinder::MatchResult &Result, const CStyleCastExpr *CStyleCast) { + if (protoTypeHasNoParms(CStyleCast->getTypeAsWritten())) { + removeVoidArgumentTokens( + Result, + CStyleCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(), + "C style cast"); + } +} + +void RedundantVoidArgCheck::processFunctionalCast( + const MatchFinder::MatchResult &Result, + const CXXFunctionalCastExpr *FunctionalCast) { + if (protoTypeHasNoParms(FunctionalCast->getTypeAsWritten())) { + removeVoidArgumentTokens( + Result, + FunctionalCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(), + "functional cast"); + } +} + +void RedundantVoidArgCheck::processExplicitCastExpr( + const MatchFinder::MatchResult &Result, + const ExplicitCastExpr *ExplicitCast) { + if (protoTypeHasNoParms(ExplicitCast->getTypeAsWritten())) { + removeVoidArgumentTokens(Result, ExplicitCast->getSourceRange(), + "explicit cast"); + } +} + +void RedundantVoidArgCheck::processLambdaExpr( + const MatchFinder::MatchResult &Result, const LambdaExpr *Lambda) { + if (Lambda->getLambdaClass()->getLambdaCallOperator()->getNumParams() == 0 && + Lambda->hasExplicitParameters()) { + SourceLocation Begin = + Lambda->getIntroducerRange().getEnd().getLocWithOffset(1); + SourceLocation End = Lambda->getBody()->getLocStart().getLocWithOffset(-1); + removeVoidArgumentTokens(Result, SourceRange(Begin, End), + "lambda expression"); + } +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tidy/readability/SimplifyBooleanExprCheck.h =================================================================== --- clang-tidy/readability/SimplifyBooleanExprCheck.h +++ clang-tidy/readability/SimplifyBooleanExprCheck.h @@ -30,25 +30,15 @@ /// `e ? false : true` becomes `!e` /// `if (true) t(); else f();` becomes `t();` /// `if (false) t(); else f();` becomes `f();` -/// `if (e) return true; else return false;` becomes `return e;` -/// `if (e) return false; else return true;` becomes `return !e;` +/// `if (e) return true; else return false;` becomes `return (e);` +/// `if (e) return false; else return true;` becomes `return !(e);` /// `if (e) b = true; else b = false;` becomes `b = e;` -/// `if (e) b = false; else b = true;` becomes `b = !e;` -/// -/// Parenthesis from the resulting expression `e` are removed whenever -/// possible. -/// -/// When a conditional boolean return or assignment appears at the end of a -/// chain of `if`, `else if` statements, the conditional statement is left -/// unchanged unless the option `ChainedConditionalReturn` or -/// `ChainedConditionalAssignment`, respectively, is specified as non-zero. -/// The default value for both options is zero. +/// `if (e) b = false; else b = true;` becomes `b = !(e);` /// class SimplifyBooleanExprCheck : public ClangTidyCheck { public: - SimplifyBooleanExprCheck(StringRef Name, ClangTidyContext *Context); - - void storeOptions(ClangTidyOptions::OptionMap &Options) override; + SimplifyBooleanExprCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; @@ -102,9 +92,6 @@ void replaceWithAssignment(const ast_matchers::MatchFinder::MatchResult &Result, const IfStmt *If, bool Negated = false); - - const bool ChainedConditionalReturn; - const bool ChainedConditionalAssignment; }; } // namespace readability Index: clang-tidy/readability/SimplifyBooleanExprCheck.cpp =================================================================== --- clang-tidy/readability/SimplifyBooleanExprCheck.cpp +++ clang-tidy/readability/SimplifyBooleanExprCheck.cpp @@ -108,25 +108,20 @@ StringRef NegatedOperator = negatedOperator(BinOp); if (!NegatedOperator.empty()) { return (getText(Result, *BinOp->getLHS()) + " " + NegatedOperator + - " " + getText(Result, *BinOp->getRHS())).str(); + " " + getText(Result, *BinOp->getRHS())) + .str(); } } } StringRef Text = getText(Result, *E); return (Negated ? (needsParensAfterUnaryNegation(E) ? "!(" + Text + ")" : "!" + Text) - : Text).str(); + : Text) + .str(); } } // namespace -SimplifyBooleanExprCheck::SimplifyBooleanExprCheck(StringRef Name, - ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - ChainedConditionalReturn(Options.get("ChainedConditionalReturn", 0U)), - ChainedConditionalAssignment( - Options.get("ChainedConditionalAssignment", 0U)) {} - void SimplifyBooleanExprCheck::matchBoolBinOpExpr(MatchFinder *Finder, bool Value, StringRef OperatorName, @@ -204,18 +199,10 @@ void SimplifyBooleanExprCheck::matchIfReturnsBool(MatchFinder *Finder, bool Value, StringRef Id) { - if (ChainedConditionalReturn) { - Finder->addMatcher(ifStmt(isExpansionInMainFile(), - hasThen(ReturnsBool(Value, ThenLiteralId)), - hasElse(ReturnsBool(!Value))).bind(Id), - this); - } else { - Finder->addMatcher(ifStmt(isExpansionInMainFile(), - unless(hasParent(ifStmt())), - hasThen(ReturnsBool(Value, ThenLiteralId)), - hasElse(ReturnsBool(!Value))).bind(Id), - this); - } + Finder->addMatcher(ifStmt(isExpansionInMainFile(), + hasThen(ReturnsBool(Value, ThenLiteralId)), + hasElse(ReturnsBool(!Value))).bind(Id), + this); } void SimplifyBooleanExprCheck::matchIfAssignsBool(MatchFinder *Finder, @@ -233,22 +220,9 @@ hasRHS(boolLiteral(equals(!Value)))); auto Else = anyOf(SimpleElse, compoundStmt(statementCountIs(1), hasAnySubstatement(SimpleElse))); - if (ChainedConditionalAssignment) { - Finder->addMatcher( - ifStmt(isExpansionInMainFile(), hasThen(Then), hasElse(Else)).bind(Id), - this); - } else { - Finder->addMatcher(ifStmt(isExpansionInMainFile(), - unless(hasParent(ifStmt())), hasThen(Then), - hasElse(Else)).bind(Id), - this); - } -} - -void SimplifyBooleanExprCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "ChainedConditionalReturn", ChainedConditionalReturn); - Options.store(Opts, "ChainedConditionalAssignment", - ChainedConditionalAssignment); + Finder->addMatcher( + ifStmt(isExpansionInMainFile(), hasThen(Then), hasElse(Else)).bind(Id), + this); } void SimplifyBooleanExprCheck::registerMatchers(MatchFinder *Finder) { Index: docs/ModernizerUsage.rst =================================================================== --- docs/ModernizerUsage.rst +++ docs/ModernizerUsage.rst @@ -38,9 +38,9 @@ ```` is the directory containing a *compilation databasefile*, a file named ``compile_commands.json``, which provides compiler arguments for building each source file. CMake can generate this file by specifying - ``-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`` when running CMake. Ninja_, since v1.2 - can also generate this file with ``ninja -t compdb``. If the compilation - database cannot be used for any reason, an error is reported. + ``-DCMAKE_EXPORT_COMPILE_COMMANDS`` when running CMake. Ninja_, since v1.2 can + also generate this file with ``ninja -t compdb``. If the compilation database + cannot be used for any reason, an error is reported. This option is ignored if ``--`` is present. Index: docs/clang-modernize.rst =================================================================== --- docs/clang-modernize.rst +++ docs/clang-modernize.rst @@ -51,7 +51,7 @@ A `compilation database`_ contains the command-line arguments for multiple files. If the code you want to transform can be built with CMake, you can generate this database easily by running CMake with the -``-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`` option. The Ninja_ build system, since +``-DCMAKE_EXPORT_COMPILE_COMMANDS`` option. The Ninja_ build system, since v1.2, can create this file too using the *compdb* tool: ``ninja -t compdb``. If you're not already using either of these tools or cannot easily make use of them you might consider looking into Bear_. Index: test/clang-modernize/HeaderReplacements/main.cpp =================================================================== --- test/clang-modernize/HeaderReplacements/main.cpp +++ test/clang-modernize/HeaderReplacements/main.cpp @@ -26,8 +26,6 @@ // COMMON_CPP: {{^common.cpp_.*.yaml$}} // COMMON_CPP-NOT: {{common.cpp_.*.yaml}} -// REQUIRES: shell - #include "common.h" void test_header_replacement() { Index: test/clang-tidy/google-readability-casting.c =================================================================== --- test/clang-tidy/google-readability-casting.c +++ test/clang-tidy/google-readability-casting.c @@ -1,23 +1,9 @@ // RUN: $(dirname %s)/check_clang_tidy.sh %s google-readability-casting %t -- -x c -// The testing script always adds .cpp extension to the input file name, so we -// need to run clang-tidy directly in order to verify handling of .c files: -// RUN: clang-tidy --checks=-*,google-readability-casting %s -- -x c++ | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not='{{warning|error}}:' -// RUN: cp %s %t.main_file.cpp -// RUN: clang-tidy --checks=-*,google-readability-casting -header-filter='.*' %t.main_file.cpp -- -I%S -DTEST_INCLUDE -x c++ | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not='{{warning|error}}:' // REQUIRES: shell -#ifdef TEST_INCLUDE - -#undef TEST_INCLUDE -#include "google-readability-casting.c" - -#else - void f(const char *cpc) { const char *cpc2 = (const char*)cpc; // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant cast to the same type [google-readability-casting] // CHECK-FIXES: const char *cpc2 = cpc; char *pc = (char*)cpc; } - -#endif Index: test/clang-tidy/misc-assert-side-effect.cpp =================================================================== --- test/clang-tidy/misc-assert-side-effect.cpp +++ test/clang-tidy/misc-assert-side-effect.cpp @@ -1,4 +1,4 @@ -// RUN: $(dirname %s)/check_clang_tidy.sh %s misc-assert-side-effect %t -config="{CheckOptions: [{key: misc-assert-side-effect.CheckFunctionCalls, value: 1}, {key: misc-assert-side-effect.AssertMacros, value: 'assert,assert2,my_assert'}]}" -- -fexceptions +// RUN: $(dirname %s)/check_clang_tidy.sh %s misc-assert-side-effect %t -config="{CheckOptions: [{key: misc-assert-side-effect.CheckFunctionCalls, value: 1}, {key: misc-assert-side-effect.AssertMacros, value: 'assert,my_assert'}]}" -- -fexceptions // REQUIRES: shell //===--- assert definition block ------------------------------------------===// @@ -12,10 +12,6 @@ (void)abort() #endif -void print(...); -#define assert2(e) (__builtin_expect(!(e), 0) ? \ - print (#e, __FILE__, __LINE__) : (void)0) - #ifdef NDEBUG #define my_assert(x) 1 #else @@ -92,7 +88,5 @@ assert((throw 1, false)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect - assert2(1 == 2 - 1); - return 0; } Index: test/clang-tidy/misc-noexcept-move-constructor.cpp =================================================================== --- test/clang-tidy/misc-noexcept-move-constructor.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// RUN: $(dirname %s)/check_clang_tidy.sh %s misc-noexcept-move-constructor %t -// REQUIRES: shell - -class A { - A(A &&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [misc-noexcept-move-constructor] - A &operator=(A &&); - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should -}; - -struct B { - static constexpr bool kFalse = false; - B(B &&) noexcept(kFalse); - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [misc-noexcept-move-constructor] -}; - -class OK {}; - -void f() { - OK a; - a = OK(); -} - -class OK1 { - public: - OK1(); - OK1(const OK1 &); - OK1(OK1&&) noexcept; - OK1 &operator=(OK1 &&) noexcept; - void f(); - void g() noexcept; -}; - -class OK2 { - static constexpr bool kTrue = true; - -public: - OK2(OK2 &&) noexcept(true) {} - OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; } -}; - -struct OK3 { - OK3(OK3 &&) noexcept(false) {} - OK3 &operator=(OK3 &&) = delete; -}; Index: test/clang-tidy/misc-static-assert.cpp =================================================================== --- test/clang-tidy/misc-static-assert.cpp +++ test/clang-tidy/misc-static-assert.cpp @@ -10,8 +10,6 @@ abort() #endif -void print(...); - #define ZERO_MACRO 0 #define False false @@ -22,9 +20,6 @@ constexpr bool myfunc(int a, int b) { return a * b == 0; } -typedef __SIZE_TYPE__ size_t; -extern "C" size_t strlen(const char *s); - class A { public: bool method() { return true; } @@ -125,17 +120,5 @@ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be // CHECK-FIXES: {{^ }}static_assert(10==5 , "Report me!"); - assert(strlen("12345") == 5); - // CHECK-FIXES: {{^ }}assert(strlen("12345") == 5); - -#define assert(e) (__builtin_expect(!(e), 0) ? print (#e, __FILE__, __LINE__) : (void)0) - assert(false); - // CHECK-FIXES: {{^ }}assert(false); - - assert(10 == 5 + 5); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be - // CHECK-FIXES: {{^ }}static_assert(10 == 5 + 5, ""); -#undef assert - return 0; } Index: test/clang-tidy/readability-redundant-void-arg.c =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-void-arg.c @@ -0,0 +1,125 @@ +// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-redundant-void-arg %t -- -x c +// REQUIRES: shell + +#include + +extern int i; + +int foo2() { + return 0; +} + +int j = 1; + +int foo(void) { +// CHECK-FIXES: {{^}}int foo(void) {{{$}} + return 0; +} + +typedef unsigned int my_uint; + +typedef void my_void; + +// A function taking void and returning a pointer to function taking void +// and returning int. +int (*returns_fn_void_int(void))(void); +// CHECK-FIXES: {{^}}int (*returns_fn_void_int(void))(void);{{$}} + +typedef int (*returns_fn_void_int_t(void))(void); +// CHECK-FIXES: {{^}}typedef int (*returns_fn_void_int_t(void))(void);{{$}} + +int (*returns_fn_void_int(void))(void) { +// CHECK-FIXES: {{^}}int (*returns_fn_void_int(void))(void) {{{$}} + return NULL; +} + +// A function taking void and returning a pointer to a function taking void +// and returning a pointer to a function taking void and returning void. +void (*(*returns_fn_returns_fn_void_void(void))(void))(void); +// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void(void))(void))(void);{{$}} + +typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void); +// CHECK-FIXES: {{^}}typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void);{{$}} + +void (*(*returns_fn_returns_fn_void_void(void))(void))(void) { +// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void(void))(void))(void) {{{$}} + return NULL; +} + +void bar() { + int i; + int *pi = NULL; + void *pv = (void *) pi; + float f; + float *fi; + double d; + double *pd; +} + +void (*f1)(void); +// CHECK-FIXES: {{^}}void (*f1)(void);{{$}} + +void (*f2)(void) = NULL; +// CHECK-FIXES: {{^}}void (*f2)(void) = NULL;{{$}} + +void (*f3)(void) = bar; +// CHECK-FIXES: {{^}}void (*f3)(void) = bar;{{$}} + +void (*fa)(); + +void (*fb)() = NULL; + +void (*fc)() = bar; + +typedef void (function_ptr)(void); +// CHECK-FIXES: {{^}}typedef void (function_ptr)(void);{{$}} + +// intentionally not LLVM style to check preservation of whitespace +typedef void (function_ptr2) + ( + void + ); +// CHECK-FIXES: {{^}}typedef void (function_ptr2){{$}} +// CHECK-FIXES-NEXT: {{^ \($}} +// CHECK-FIXES-NEXT: {{^ void$}} +// CHECK-FIXES-NEXT: {{^ \);$}} + +// intentionally not LLVM style to check preservation of whitespace +typedef +void +( +* +( +* +returns_fn_returns_fn_void_void_t2 +( +void +) +) +( +void +) +) +( +void +) +; +// CHECK-FIXES: {{^typedef$}} +// CHECK-FIXES-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^\*$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^\*$}} +// CHECK-FIXES-NEXT: {{^returns_fn_returns_fn_void_void_t2$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^;$}} Index: test/clang-tidy/readability-redundant-void-arg.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-void-arg.cpp @@ -0,0 +1,420 @@ +// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-redundant-void-arg %t +// REQUIRES: shell + +#include + +int foo(); + +void bar(); + +void bar2(); + +extern "C" void ecfoo(void); + +extern "C" void ecfoo(void) { +} + +extern int i; + +int j = 1; + +int foo(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list in function definition [readability-redundant-void-arg] +// CHECK-FIXES: {{^}}int foo() {{{$}} + return 0; +} + +typedef unsigned int my_uint; + +typedef void my_void; + +// A function taking void and returning a pointer to function taking void +// and returning int. +int (*returns_fn_void_int(void))(void); +// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function declaration +// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in function declaration +// CHECK-FIXES: {{^}}int (*returns_fn_void_int())();{{$}} + +typedef int (*returns_fn_void_int_t(void))(void); +// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-2]]:44: warning: {{.*}} in typedef +// CHECK-FIXES: {{^}}typedef int (*returns_fn_void_int_t())();{{$}} + +int (*returns_fn_void_int(void))(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function definition +// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}int (*returns_fn_void_int())() {{{$}} + return nullptr; +} + +// A function taking void and returning a pointer to a function taking void +// and returning a pointer to a function taking void and returning void. +void (*(*returns_fn_returns_fn_void_void(void))(void))(void); +// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: {{.*}} in function declaration +// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: {{.*}} in function declaration +// CHECK-MESSAGES: :[[@LINE-3]]:56: warning: {{.*}} in function declaration +// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void())())();{{$}} + +typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void); +// CHECK-MESSAGES: :[[@LINE-1]]:52: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-2]]:59: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-3]]:66: warning: {{.*}} in typedef +// CHECK-FIXES: {{^}}typedef void (*(*returns_fn_returns_fn_void_void_t())())();{{$}} + +void (*(*returns_fn_returns_fn_void_void(void))(void))(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: {{.*}} in function definition +// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: {{.*}} in function definition +// CHECK-MESSAGES: :[[@LINE-3]]:56: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void())())() {{{$}} + return nullptr; +} + +void bar(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}void bar() {{{$}} +} + +void op_fn(int i) { +} + +class gronk { +public: + gronk(); + ~gronk(); + + void foo(); + void bar(); + void bar2 + (); + void operation(int i) { } + +private: + int m_i; + int *m_pi; + float m_f; + float *m_pf; + double m_d; + double *m_pd; + + void (*f1)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in field declaration + // CHECK-FIXES: {{^ }}void (*f1)();{{$}} + + void (*op)(int i); + + void (gronk::*p1)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in field declaration + // CHECK-FIXES: {{^ }}void (gronk::*p1)();{{$}} + + int (gronk::*p_mi); + + void (gronk::*p2)(int); + + void (*(*returns_fn_returns_fn_void_void(void))(void))(void); + // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: {{.*}} in function declaration + // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: {{.*}} in function declaration + // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: {{.*}} in function declaration + // CHECK-FIXES: {{^}} void (*(*returns_fn_returns_fn_void_void())())();{{$}} + + void (*(*(gronk::*returns_fn_returns_fn_void_void_mem)(void))(void))(void); + // CHECK-MESSAGES: :[[@LINE-1]]:58: warning: {{.*}} in field declaration + // CHECK-MESSAGES: :[[@LINE-2]]:65: warning: {{.*}} in field declaration + // CHECK-MESSAGES: :[[@LINE-3]]:72: warning: {{.*}} in field declaration + // CHECK-FIXES: {{^}} void (*(*(gronk::*returns_fn_returns_fn_void_void_mem)())())();{{$}} +}; + +int i; +int *pi; +void *pv = (void *) pi; +float f; +float *fi; +double d; +double *pd; + +void (*f1)(void); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration +// CHECK-FIXES: {{^}}void (*f1)();{{$}} + +void (*f2)(void) = nullptr; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2)() = nullptr;{{$}} + +void (*f2b)(void)(nullptr); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2b)()(nullptr);{{$}} + +void (*f2c)(void){nullptr}; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2c)(){nullptr};{{$}} + +void (*f2d)(void) = NULL; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2d)() = NULL;{{$}} + +void (*f2e)(void)(NULL); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2e)()(NULL);{{$}} + +void (*f2f)(void){NULL}; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2f)(){NULL};{{$}} + +void (*f3)(void) = bar; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f3)() = bar;{{$}} + +void (*o1)(int i); +void (*o2)(int i) = nullptr; +void (*o3)(int i)(nullptr); +void (*o4)(int i){nullptr}; +void (*o5)(int i) = NULL; +void (*o6)(int i)(NULL); +void (*o7)(int i){NULL}; +void (*o8)(int i) = op_fn; + +void (*fa)(); + +void (*fb)() = nullptr; + +void (*fc)() = bar; + +typedef void (function_ptr)(void); +// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: {{.*}} in typedef +// CHECK-FIXES: {{^}}typedef void (function_ptr)();{{$}} + +// intentionally not LLVM style to check preservation of whitesapce +typedef void (function_ptr2) + ( + void + ); +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} in typedef +// CHECK-FIXES: {{^typedef void \(function_ptr2\)$}} +// CHECK-FIXES-NEXT: {{^ \($}} +// CHECK-FIXES-NEXT: {{^ $}} +// CHECK-FIXES-NEXT: {{^ \);$}} + +// intentionally not LLVM style to check preservation of whitesapce +typedef +void +( +* +( +* +returns_fn_returns_fn_void_void_t2 +( +void +) +) +( +void +) +) +( +void +) +; +// CHECK-MESSAGES: :[[@LINE-11]]:1: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-8]]:1: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-5]]:1: warning: {{.*}} in typedef +// CHECK-FIXES: {{^typedef$}} +// CHECK-FIXES-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^\*$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^\*$}} +// CHECK-FIXES-NEXT: {{^returns_fn_returns_fn_void_void_t2$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NOT: {{[^ ]}} +// CHECK-FIXES: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NOT: {{[^ ]}} +// CHECK-FIXES: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NOT: {{[^ ]}} +// CHECK-FIXES: {{^\)$}} +// CHECK-FIXES-NEXT: {{^;$}} + + +void (gronk::*p1)(void); +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration +// CHECK-FIXES: {{^}}void (gronk::*p1)();{{$}} + +void (gronk::*p2)(void) = &gronk::foo; +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (gronk::*p2)() = &gronk::foo;{{$}} + +typedef void (gronk::*member_function_ptr)(void); +// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: {{.*}} in typedef +// CHECK-FIXES: {{^}}typedef void (gronk::*member_function_ptr)();{{$}} + +// intentionally not LLVM style to check preservation of whitesapce +typedef void (gronk::*member_function_ptr2) + ( + void + ); +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} in typedef +// CHECK-FIXES: {{^typedef void \(gronk::\*member_function_ptr2\)$}} +// CHECK-FIXES-NEXT: {{^ \($}} +// CHECK-FIXES-NEXT: {{^ $}} +// CHECK-FIXES-NEXT: {{^ \);$}} + +void gronk::foo() { + void (*f1)(void) = &::bar; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-FIXES: {{^ }}void (*f1)() = &::bar;{{$}} + + void (*f2)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (*f2)();{{$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (*f3) + ( + void + ); + // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (*f3){{$}} + // CHECK-FIXES-NEXT: {{^ \($}} + // CHECK-FIXES-NEXT: {{^ $}} + // CHECK-FIXES-NEXT: {{^ \);$}} +} + +void gronk::bar(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}void gronk::bar() {{{$}} + void (gronk::*p3)(void) = &gronk::foo; + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in variable declaration with initializer + // CHECK-FIXES: {{^ }}void (gronk::*p3)() = &gronk::foo;{{$}} + + void (gronk::*p4)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (gronk::*p4)();{{$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (gronk::*p5) + ( + void + ); + // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (gronk::*p5){{$}} + // CHECK-FIXES-NEXT: {{^ \($}} + // CHECK-FIXES-NExT: {{^ $}} + // CHECK-FIXES-NExT: {{^ \);$}} +} + +// intentionally not LLVM style to check preservation of whitesapce +void gronk::bar2 + ( + void + ) +// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: {{.*}} in function definition +// CHECK-FIXES: {{^void gronk::bar2$}} +// CHECK-FIXES-NEXT: {{^ \($}} +// CHECK-FIXES-NEXT: {{^ $}} +// CHECK-FIXES-NEXT: {{^ \)$}} +{ +} + +gronk::gronk(void) +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}gronk::gronk(){{$}} + : f1(nullptr), + p1(nullptr) { +} + +gronk::~gronk(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}gronk::~gronk() {{{$}} +} + +class nutter { +public: + nutter(); +}; + +nutter::nutter(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}nutter::nutter() {{{$}} + void (*f3)(void) = static_cast(0); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:43: warning: {{.*}} in named cast + // CHECK-FIXES: void (*f3)() = static_cast(0);{{$}} + + void (*f4)(void) = (void (*)(void)) 0; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: {{.*}} in C style cast + // CHECK-FIXES: void (*f4)() = (void (*)()) 0;{{$}} + + void (*f5)(void) = reinterpret_cast(0); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: {{.*}} in named cast + // CHECK-FIXES: void (*f5)() = reinterpret_cast(0);{{$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (*f6)(void) = static_cast(0); + // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in named cast + // CHECK-FIXES: {{^ }}void (*f6)() = static_cast(0);{{$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (*f7)(void) = (void (*) + ( + void + )) 0; + // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in C style cast + // CHECK-FIXES: {{^ }}void (*f7)() = (void (*){{$}} + // CHECK-FIXES-NEXT: {{^ \($}} + // CHECK-FIXES-NEXT: {{^ $}} + // CHECK-FIXES-NEXT: {{^ \)\) 0;$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (*f8)(void) = reinterpret_cast(0); + // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in named cast + // CHECK-FIXES: {{^ }}void (*f8)() = reinterpret_cast\(0\);$}} + + void (*o1)(int) = static_cast(0); + void (*o2)(int) = (void (*)(int)) 0; + void (*o3)(int) = reinterpret_cast(0); +} + +class generator { +public: + int operator()(void) { return 1; } + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: {{.*}} in function definition + // CHECK-FIXES: {{^ }}int operator()() { return 1; }{{$}} +}; + +void test_lambda_functions() { + auto lamb_duh = [](void (*fn)(void)) { (*fn)(); }; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}auto lamb_duh = [](void (*fn)()) { (*fn)(); };{{$}} + + auto lambda_generator = [](void) { return 1; }; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: {{.*}} in lambda expression + // CHECK-FIXES: {{^ }}auto lambda_generator = []() { return 1; };{{$}} + + auto gen2 = []() { return 1; }; + + auto gen3 = []{ return 1; }; + + auto void_returner = [](void) -> void (*)(void) { return f1; }; + // CHECK-MESSAGES: [[@LINE-1]]:27: warning: {{.*}} in lambda expression + // CHECK-MESSAGES: [[@LINE-2]]:45: warning: {{.*}} in lambda expression + // CHECK-FIXES: {{^ }}auto void_returner = []() -> void (*)() { return f1; };{{$}} +} Index: test/clang-tidy/readability-simplify-bool-expr-chained-conditional-assignment.cpp =================================================================== --- test/clang-tidy/readability-simplify-bool-expr-chained-conditional-assignment.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-simplify-boolean-expr %t -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalAssignment", value: 1}]}" -- -// REQUIRES: shell - -void chained_conditional_compound_assignment(int i) { - bool b; - if (i < 0) { - b = true; - } else if (i < 10) { - b = false; - } else if (i > 20) { - b = true; - } else { - b = false; - } - // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: redundant boolean literal in conditional assignment [readability-simplify-boolean-expr] - // CHECK-FIXES: {{^}} } else if (i < 10) {{{$}} - // CHECK-FIXES-NEXT: {{^}} b = false;{{$}} - // CHECK-FIXES-NEXT: {{^}} } else b = i > 20;{{$}} -} - -void chained_conditional_assignment(int i) { - bool b; - if (i < 0) - b = true; - else if (i < 10) - b = false; - else if (i > 20) - b = true; - else - b = false; - // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: {{.*}} in conditional assignment - // CHECK-FIXES: {{^}} else if (i < 10) - // CHECK-FIXES-NEXT: {{^}} b = false; - // CHECK-FIXES-NEXT: {{^}} else b = i > 20; -} Index: test/clang-tidy/readability-simplify-bool-expr-chained-conditional-return.cpp =================================================================== --- test/clang-tidy/readability-simplify-bool-expr-chained-conditional-return.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-simplify-boolean-expr %t -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalReturn", value: 1}]}" -- -// REQUIRES: shell - -bool chained_conditional_compound_return(int i) { - if (i < 0) { - return true; - } else if (i < 10) { - return false; - } else if (i > 20) { - return true; - } else { - return false; - } - // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: redundant boolean literal in conditional return statement [readability-simplify-boolean-expr] - // CHECK-FIXES: {{^}} } else if (i < 10) {{{$}} - // CHECK-FIXES-NEXT: {{^}} return false;{{$}} - // CHECK-FIXES-NEXT: {{^}} } else return i > 20;{{$}} -} - -bool chained_conditional_return(int i) { - if (i < 0) - return true; - else if (i < 10) - return false; - else if (i > 20) - return true; - else - return false; - // CHECK-MESSAGES: :[[@LINE-3]]:12: warning: {{.*}} in conditional return statement - // CHECK-FIXES: {{^}} else if (i < 10) - // CHECK-FIXES-NEXT: {{^}} return false; - // CHECK-FIXES-NEXT: {{^}} else return i > 20; -} Index: test/clang-tidy/readability-simplify-bool-expr.cpp =================================================================== --- test/clang-tidy/readability-simplify-bool-expr.cpp +++ test/clang-tidy/readability-simplify-bool-expr.cpp @@ -541,55 +541,3 @@ } else f = false; } - -// unchanged: chained return statements, but ChainedConditionalReturn not set -bool chained_conditional_compound_return(int i) { - if (i < 0) { - return true; - } else if (i < 10) { - return false; - } else if (i > 20) { - return true; - } else { - return false; - } -} - -// unchanged: chained return statements, but ChainedConditionalReturn not set -bool chained_conditional_return(int i) { - if (i < 0) - return true; - else if (i < 10) - return false; - else if (i > 20) - return true; - else - return false; -} - -// unchanged: chained assignments, but ChainedConditionalAssignment not set -void chained_conditional_compound_assignment(int i) { - bool b; - if (i < 0) { - b = true; - } else if (i < 10) { - b = false; - } else if (i > 20) { - b = true; - } else { - b = false; - } -} - -// unchanged: chained return statements, but ChainedConditionalReturn not set -void chained_conditional_assignment(int i) { - bool b; - if (i < 0) - b = true; - else if (i < 10) - b = false; - else if (i > 20) - b = true; - else - b = false; -} Index: test/lit.cfg =================================================================== --- test/lit.cfg +++ test/lit.cfg @@ -25,21 +25,12 @@ config.environment['PATH'])) config.environment['PATH'] = path -# Choose between lit's internal shell pipeline runner and a real shell. If -# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. -use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") -if use_lit_shell: - # 0 is external, "" is default, and everything else is internal. - execute_external = (use_lit_shell == "0") -else: - # Otherwise we default to internal on Windows and external elsewhere, as - # bash on Windows is usually very slow. - execute_external = (not sys.platform in ['win32']) - # testFormat: The test format to use to interpret tests. # # For now we require '&&' between commands, until they get globally killed and # the test runner updated. +execute_external = (platform.system() != 'Windows' + or lit_config.getBashPath() not in [None, ""]) config.test_format = lit.formats.ShTest(execute_external) # suffixes: A list of file extensions to treat as test files. @@ -177,13 +168,9 @@ config.available_features.add('crash-recovery') # Shell execution -if execute_external: +if platform.system() not in ['Windows'] or lit_config.getBashPath() != '': config.available_features.add('shell') -# Exclude MSYS due to transforming '/' to 'X:/mingwroot/'. -if not platform.system() in ['Windows'] or not execute_external: - config.available_features.add('shell-preserves-root') - # ANSI escape sequences in non-dumb terminal if platform.system() not in ['Windows']: config.available_features.add('ansi-escape-sequences')