From 71e1a579b2632338631bd1869e88559b7b12754d Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Wed, 19 Aug 2015 20:30:07 +0000 Subject: [PATCH] Revert "[clang-tidy] Add use-nullptr check to clang-tidy." The new test is failing on darwin: http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA_check/10339/ This reverts r245434 and its follow up r245471. llvm-svn: 245493 --- .../clang-tidy/modernize/CMakeLists.txt | 1 - .../modernize/ModernizeTidyModule.cpp | 5 - .../clang-tidy/modernize/UseNullptrCheck.cpp | 472 ------------------ .../clang-tidy/modernize/UseNullptrCheck.h | 34 -- .../modernize-use-nullptr-basic.cpp | 344 ------------- .../test/clang-tidy/modernize-use-nullptr.cpp | 178 ------- 6 files changed, 1034 deletions(-) delete mode 100644 clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp delete mode 100644 clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h delete mode 100644 clang-tools-extra/test/clang-tidy/modernize-use-nullptr-basic.cpp delete mode 100644 clang-tools-extra/test/clang-tidy/modernize-use-nullptr.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index 7dc79f063b31..d2bb2c106565 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -5,7 +5,6 @@ add_clang_library(clangTidyModernizeModule LoopConvertUtils.cpp ModernizeTidyModule.cpp PassByValueCheck.cpp - UseNullptrCheck.cpp LINK_LIBS clangAST diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index fb0a146c8beb..962245b2a081 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -12,7 +12,6 @@ #include "../ClangTidyModuleRegistry.h" #include "LoopConvertCheck.h" #include "PassByValueCheck.h" -#include "UseNullptrCheck.h" using namespace clang::ast_matchers; @@ -25,7 +24,6 @@ public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck("modernize-loop-convert"); CheckFactories.registerCheck("modernize-pass-by-value"); - CheckFactories.registerCheck("modernize-use-nullptr"); } ClangTidyOptions getModuleOptions() override { @@ -33,9 +31,6 @@ public: auto &Opts = Options.CheckOptions; Opts["modernize-loop-convert.MinConfidence"] = "reasonable"; Opts["modernize-pass-by-value.IncludeStyle"] = "llvm"; // Also: "google". - - // Comma-separated list of user-defined macros that behave like NULL. - Opts["modernize-use-nullptr.UserNullMacros"] = ""; return Options; } }; diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp deleted file mode 100644 index c1d8a4078cf2..000000000000 --- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp +++ /dev/null @@ -1,472 +0,0 @@ -//===--- UseNullptrCheck.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 "UseNullptrCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" - -using namespace clang; -using namespace clang::ast_matchers; -using namespace llvm; - -namespace clang { -namespace tidy { -namespace modernize { - -const char CastSequence[] = "sequence"; -const char NullMacroName[] = "NULL"; - -/// \brief Matches cast expressions that have a cast kind of CK_NullToPointer -/// or CK_NullToMemberPointer. -/// -/// Given -/// \code -/// int *p = 0; -/// \endcode -/// implicitCastExpr(isNullToPointer()) matches the implicit cast clang adds -/// around \c 0. -AST_MATCHER(CastExpr, isNullToPointer) { - return Node.getCastKind() == CK_NullToPointer || - Node.getCastKind() == CK_NullToMemberPointer; -} - -AST_MATCHER(Type, sugaredNullptrType) { - const Type *DesugaredType = Node.getUnqualifiedDesugaredType(); - if (const BuiltinType *BT = dyn_cast(DesugaredType)) - return BT->getKind() == BuiltinType::NullPtr; - return false; -} - -/// \brief Create a matcher that finds implicit casts as well as the head of a -/// sequence of zero or more nested explicit casts that have an implicit cast -/// to null within. -/// Finding sequences of explict casts is necessary so that an entire sequence -/// can be replaced instead of just the inner-most implicit cast. -StatementMatcher makeCastSequenceMatcher() { - StatementMatcher ImplicitCastToNull = implicitCastExpr( - isNullToPointer(), - unless(hasSourceExpression(hasType(sugaredNullptrType())))); - - return castExpr(anyOf(ImplicitCastToNull, - explicitCastExpr(hasDescendant(ImplicitCastToNull))), - unless(hasAncestor(explicitCastExpr()))) - .bind(CastSequence); -} - -bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc, - const SourceManager &SM) { - return SM.isWrittenInSameFile(StartLoc, EndLoc); -} - -/// \brief Replaces the provided range with the text "nullptr", but only if -/// the start and end location are both in main file. -/// Returns true if and only if a replacement was made. -void replaceWithNullptr(ClangTidyCheck &Check, SourceManager &SM, - SourceLocation StartLoc, SourceLocation EndLoc) { - CharSourceRange Range(SourceRange(StartLoc, EndLoc), true); - // Add a space if nullptr follows an alphanumeric character. This happens - // whenever there is an c-style explicit cast to nullptr not surrounded by - // parentheses and right beside a return statement. - SourceLocation PreviousLocation = StartLoc.getLocWithOffset(-1); - bool NeedsSpace = isAlphanumeric(*SM.getCharacterData(PreviousLocation)); - Check.diag(Range.getBegin(), "use nullptr") << FixItHint::CreateReplacement( - Range, NeedsSpace ? " nullptr" : "nullptr"); -} - -/// \brief Returns the name of the outermost macro. -/// -/// Given -/// \code -/// #define MY_NULL NULL -/// \endcode -/// If \p Loc points to NULL, this function will return the name MY_NULL. -StringRef getOutermostMacroName(SourceLocation Loc, const SourceManager &SM, - const LangOptions &LO) { - assert(Loc.isMacroID()); - SourceLocation OutermostMacroLoc; - - while (Loc.isMacroID()) { - OutermostMacroLoc = Loc; - Loc = SM.getImmediateMacroCallerLoc(Loc); - } - - return Lexer::getImmediateMacroName(OutermostMacroLoc, SM, LO); -} - -/// \brief RecursiveASTVisitor for ensuring all nodes rooted at a given AST -/// subtree that have file-level source locations corresponding to a macro -/// argument have implicit NullTo(Member)Pointer nodes as ancestors. -class MacroArgUsageVisitor : public RecursiveASTVisitor { -public: - MacroArgUsageVisitor(SourceLocation CastLoc, const SourceManager &SM) - : CastLoc(CastLoc), SM(SM), Visited(false), CastFound(false), - InvalidFound(false) { - assert(CastLoc.isFileID()); - } - - bool TraverseStmt(Stmt *S) { - bool VisitedPreviously = Visited; - - if (!RecursiveASTVisitor::TraverseStmt(S)) - return false; - - // The point at which VisitedPreviously is false and Visited is true is the - // root of a subtree containing nodes whose locations match CastLoc. It's - // at this point we test that the Implicit NullTo(Member)Pointer cast was - // found or not. - if (!VisitedPreviously) { - if (Visited && !CastFound) { - // Found nodes with matching SourceLocations but didn't come across a - // cast. This is an invalid macro arg use. Can stop traversal - // completely now. - InvalidFound = true; - return false; - } - // Reset state as we unwind back up the tree. - CastFound = false; - Visited = false; - } - return true; - } - - bool VisitStmt(Stmt *S) { - if (SM.getFileLoc(S->getLocStart()) != CastLoc) - return true; - Visited = true; - - const ImplicitCastExpr *Cast = dyn_cast(S); - if (Cast && (Cast->getCastKind() == CK_NullToPointer || - Cast->getCastKind() == CK_NullToMemberPointer)) - CastFound = true; - - return true; - } - - bool foundInvalid() const { return InvalidFound; } - -private: - SourceLocation CastLoc; - const SourceManager &SM; - - bool Visited; - bool CastFound; - bool InvalidFound; -}; - -/// \brief Looks for implicit casts as well as sequences of 0 or more explicit -/// casts with an implicit null-to-pointer cast within. -/// -/// The matcher this visitor is used with will find a single implicit cast or a -/// top-most explicit cast (i.e. it has no explicit casts as an ancestor) where -/// an implicit cast is nested within. However, there is no guarantee that only -/// explicit casts exist between the found top-most explicit cast and the -/// possibly more than one nested implicit cast. This visitor finds all cast -/// sequences with an implicit cast to null within and creates a replacement -/// leaving the outermost explicit cast unchanged to avoid introducing -/// ambiguities. -class CastSequenceVisitor : public RecursiveASTVisitor { -public: - CastSequenceVisitor(ASTContext &Context, - ArrayRef UserNullMacros, - ClangTidyCheck &check) - : SM(Context.getSourceManager()), Context(Context), - UserNullMacros(UserNullMacros), Check(check), - FirstSubExpr(nullptr), PruneSubtree(false) {} - - bool TraverseStmt(Stmt *S) { - // Stop traversing down the tree if requested. - if (PruneSubtree) { - PruneSubtree = false; - return true; - } - return RecursiveASTVisitor::TraverseStmt(S); - } - - // Only VisitStmt is overridden as we shouldn't find other base AST types - // within a cast expression. - bool VisitStmt(Stmt *S) { - CastExpr *C = dyn_cast(S); - if (!C) { - FirstSubExpr = nullptr; - return true; - } - if (!FirstSubExpr) - FirstSubExpr = C->getSubExpr()->IgnoreParens(); - - if (C->getCastKind() != CK_NullToPointer && - C->getCastKind() != CK_NullToMemberPointer) { - return true; - } - - SourceLocation StartLoc = FirstSubExpr->getLocStart(); - SourceLocation EndLoc = FirstSubExpr->getLocEnd(); - - // If the location comes from a macro arg expansion, *all* uses of that - // arg must be checked to result in NullTo(Member)Pointer casts. - // - // If the location comes from a macro body expansion, check to see if its - // coming from one of the allowed 'NULL' macros. - if (SM.isMacroArgExpansion(StartLoc) && SM.isMacroArgExpansion(EndLoc)) { - SourceLocation FileLocStart = SM.getFileLoc(StartLoc), - FileLocEnd = SM.getFileLoc(EndLoc); - if (isReplaceableRange(FileLocStart, FileLocEnd, SM) && - allArgUsesValid(C)) { - replaceWithNullptr(Check, SM, FileLocStart, FileLocEnd); - } - return skipSubTree(); - } - - if (SM.isMacroBodyExpansion(StartLoc) && SM.isMacroBodyExpansion(EndLoc)) { - StringRef OutermostMacroName = - getOutermostMacroName(StartLoc, SM, Context.getLangOpts()); - - // Check to see if the user wants to replace the macro being expanded. - if (std::find(UserNullMacros.begin(), UserNullMacros.end(), - OutermostMacroName) == UserNullMacros.end()) { - return skipSubTree(); - } - - StartLoc = SM.getFileLoc(StartLoc); - EndLoc = SM.getFileLoc(EndLoc); - } - - if (!isReplaceableRange(StartLoc, EndLoc, SM)) { - return skipSubTree(); - } - replaceWithNullptr(Check, SM, StartLoc, EndLoc); - - return skipSubTree(); - } - -private: - bool skipSubTree() { - PruneSubtree = true; - return true; - } - - /// \brief Tests that all expansions of a macro arg, one of which expands to - /// result in \p CE, yield NullTo(Member)Pointer casts. - bool allArgUsesValid(const CastExpr *CE) { - SourceLocation CastLoc = CE->getLocStart(); - - // Step 1: Get location of macro arg and location of the macro the arg was - // provided to. - SourceLocation ArgLoc, MacroLoc; - if (!getMacroAndArgLocations(CastLoc, ArgLoc, MacroLoc)) - return false; - - // Step 2: Find the first ancestor that doesn't expand from this macro. - ast_type_traits::DynTypedNode ContainingAncestor; - if (!findContainingAncestor( - ast_type_traits::DynTypedNode::create(*CE), MacroLoc, - ContainingAncestor)) - return false; - - // Step 3: - // Visit children of this containing parent looking for the least-descended - // nodes of the containing parent which are macro arg expansions that expand - // from the given arg location. - // Visitor needs: arg loc - MacroArgUsageVisitor ArgUsageVisitor(SM.getFileLoc(CastLoc), SM); - if (const auto *D = ContainingAncestor.get()) - ArgUsageVisitor.TraverseDecl(const_cast(D)); - else if (const auto *S = ContainingAncestor.get()) - ArgUsageVisitor.TraverseStmt(const_cast(S)); - else - llvm_unreachable("Unhandled ContainingAncestor node type"); - - return !ArgUsageVisitor.foundInvalid(); - } - - /// \brief Given the SourceLocation for a macro arg expansion, finds the - /// non-macro SourceLocation of the macro the arg was passed to and the - /// non-macro SourceLocation of the argument in the arg list to that macro. - /// These results are returned via \c MacroLoc and \c ArgLoc respectively. - /// These values are undefined if the return value is false. - /// - /// \returns false if one of the returned SourceLocations would be a - /// SourceLocation pointing within the definition of another macro. - bool getMacroAndArgLocations(SourceLocation Loc, SourceLocation &ArgLoc, - SourceLocation &MacroLoc) { - assert(Loc.isMacroID() && "Only reasonble to call this on macros"); - - ArgLoc = Loc; - - // Find the location of the immediate macro expansion. - while (true) { - std::pair LocInfo = SM.getDecomposedLoc(ArgLoc); - const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first); - const SrcMgr::ExpansionInfo &Expansion = E->getExpansion(); - - SourceLocation OldArgLoc = ArgLoc; - ArgLoc = Expansion.getExpansionLocStart(); - if (!Expansion.isMacroArgExpansion()) { - if (!MacroLoc.isFileID()) - return false; - - StringRef Name = - Lexer::getImmediateMacroName(OldArgLoc, SM, Context.getLangOpts()); - return std::find(UserNullMacros.begin(), UserNullMacros.end(), Name) != - UserNullMacros.end(); - } - - MacroLoc = SM.getImmediateExpansionRange(ArgLoc).first; - - ArgLoc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second); - if (ArgLoc.isFileID()) - return true; - - // If spelling location resides in the same FileID as macro expansion - // location, it means there is no inner macro. - FileID MacroFID = SM.getFileID(MacroLoc); - if (SM.isInFileID(ArgLoc, MacroFID)) { - // Don't transform this case. If the characters that caused the - // null-conversion come from within a macro, they can't be changed. - return false; - } - } - - llvm_unreachable("getMacroAndArgLocations"); - } - - /// \brief Tests if TestMacroLoc is found while recursively unravelling - /// expansions starting at TestLoc. TestMacroLoc.isFileID() must be true. - /// Implementation is very similar to getMacroAndArgLocations() except in this - /// case, it's not assumed that TestLoc is expanded from a macro argument. - /// While unravelling expansions macro arguments are handled as with - /// getMacroAndArgLocations() but in this function macro body expansions are - /// also handled. - /// - /// False means either: - /// - TestLoc is not from a macro expansion - /// - TestLoc is from a different macro expansion - bool expandsFrom(SourceLocation TestLoc, SourceLocation TestMacroLoc) { - if (TestLoc.isFileID()) { - return false; - } - - SourceLocation Loc = TestLoc, MacroLoc; - - while (true) { - std::pair LocInfo = SM.getDecomposedLoc(Loc); - const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first); - const SrcMgr::ExpansionInfo &Expansion = E->getExpansion(); - - Loc = Expansion.getExpansionLocStart(); - - if (!Expansion.isMacroArgExpansion()) { - if (Loc.isFileID()) { - return Loc == TestMacroLoc; - } - // Since Loc is still a macro ID and it's not an argument expansion, we - // don't need to do the work of handling an argument expansion. Simply - // keep recursively expanding until we hit a FileID or a macro arg - // expansion or a macro arg expansion. - continue; - } - - MacroLoc = SM.getImmediateExpansionRange(Loc).first; - if (MacroLoc.isFileID() && MacroLoc == TestMacroLoc) { - // Match made. - return true; - } - - Loc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second); - if (Loc.isFileID()) { - // If we made it this far without finding a match, there is no match to - // be made. - return false; - } - } - - llvm_unreachable("expandsFrom"); - } - - /// \brief Given a starting point \c Start in the AST, find an ancestor that - /// doesn't expand from the macro called at file location \c MacroLoc. - /// - /// \pre MacroLoc.isFileID() - /// \returns true if such an ancestor was found, false otherwise. - bool findContainingAncestor(ast_type_traits::DynTypedNode Start, - SourceLocation MacroLoc, - ast_type_traits::DynTypedNode &Result) { - // Below we're only following the first parent back up the AST. This should - // be fine since for the statements we care about there should only be one - // parent as far up as we care. If this assumption doesn't hold, need to - // revisit what to do here. - - assert(MacroLoc.isFileID()); - - while (true) { - const auto &Parents = Context.getParents(Start); - if (Parents.empty()) - return false; - assert(Parents.size() == 1 && - "Found an ancestor with more than one parent!"); - - const ast_type_traits::DynTypedNode &Parent = Parents[0]; - - SourceLocation Loc; - if (const auto *D = Parent.get()) - Loc = D->getLocStart(); - else if (const auto *S = Parent.get()) - Loc = S->getLocStart(); - else - llvm_unreachable("Expected to find Decl or Stmt containing ancestor"); - - if (!expandsFrom(Loc, MacroLoc)) { - Result = Parent; - return true; - } - Start = Parent; - } - - llvm_unreachable("findContainingAncestor"); - } - -private: - SourceManager &SM; - ASTContext &Context; - ArrayRef UserNullMacros; - ClangTidyCheck &Check; - Expr *FirstSubExpr; - bool PruneSubtree; -}; - -UseNullptrCheck::UseNullptrCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) { - StringRef UserMacrosStr = Options.get("UserNullMacros", ""); - UserMacrosStr.split(UserNullMacros, ","); - UserNullMacros.push_back(StringRef(NullMacroName)); -} - -void UseNullptrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "UserNullMacros", ""); -} - -void UseNullptrCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(makeCastSequenceMatcher(), this); -} - -void UseNullptrCheck::check(const MatchFinder::MatchResult &Result) { - const auto *NullCast = Result.Nodes.getNodeAs(CastSequence); - assert(NullCast && "Bad Callback. No node provided"); - - // Given an implicit null-ptr cast or an explicit cast with an implicit - // null-to-pointer cast within use CastSequenceVisitor to identify sequences - // of explicit casts that can be converted into 'nullptr'. - CastSequenceVisitor(*Result.Context, UserNullMacros, *this) - .TraverseStmt(const_cast(NullCast)); -} - -} // namespace modernize -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h deleted file mode 100644 index f136da3fba36..000000000000 --- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h +++ /dev/null @@ -1,34 +0,0 @@ -//===--- UseNullptrCheck.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_MODERNIZE_USE_NULLPTR_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NULLPTR_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace modernize { - -class UseNullptrCheck : public ClangTidyCheck { -public: - UseNullptrCheck(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: - SmallVector UserNullMacros; -}; - -} // namespace modernize -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NULLPTR_H diff --git a/clang-tools-extra/test/clang-tidy/modernize-use-nullptr-basic.cpp b/clang-tools-extra/test/clang-tidy/modernize-use-nullptr-basic.cpp deleted file mode 100644 index 28c5ae152135..000000000000 --- a/clang-tools-extra/test/clang-tidy/modernize-use-nullptr-basic.cpp +++ /dev/null @@ -1,344 +0,0 @@ -// RUN: $(dirname %s)/check_clang_tidy.sh %s modernize-use-nullptr %t -- \ -// RUN: -std=c++98 -Wno-non-literal-null-conversion -// REQUIRES: shell - -const unsigned int g_null = 0; -#define NULL 0 - -void test_assignment() { - int *p1 = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr [modernize-use-nullptr] - // CHECK-FIXES: int *p1 = nullptr; - p1 = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr - // CHECK-FIXES: p1 = nullptr; - - int *p2 = NULL; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr - // CHECK-FIXES: int *p2 = nullptr; - - p2 = p1; - // CHECK-FIXES: p2 = p1; - - const int null = 0; - int *p3 = null; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr - // CHECK-FIXES: int *p3 = nullptr; - - p3 = NULL; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr - // CHECK-FIXES: p3 = nullptr; - - int *p4 = p3; - // CHECK-FIXES: int *p4 = p3; - - p4 = null; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr - // CHECK-FIXES: p4 = nullptr; - - int i1 = 0; - - int i2 = NULL; - - int i3 = null; - - int *p5, *p6, *p7; - p5 = p6 = p7 = NULL; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr - // CHECK-FIXES: p5 = p6 = p7 = nullptr; -} - -struct Foo { - Foo(int *p = NULL) : m_p1(p) {} - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr - // CHECK-FIXES: Foo(int *p = nullptr) : m_p1(p) {} - - void bar(int *p = 0) {} - // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use nullptr - // CHECK-FIXES: void bar(int *p = nullptr) {} - - void baz(int i = 0) {} - - int *m_p1; - static int *m_p2; -}; - -int *Foo::m_p2 = NULL; -// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr -// CHECK-FIXES: int *Foo::m_p2 = nullptr; - -template -struct Bar { - Bar(T *p) : m_p(p) { - m_p = static_cast(NULL); - // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr - // CHECK-FIXES: m_p = static_cast(nullptr); - - m_p = static_cast(reinterpret_cast((void*)NULL)); - // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr - // CHECK-FIXES: m_p = static_cast(nullptr); - - m_p = static_cast(p ? p : static_cast(g_null)); - // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: use nullptr - // CHECK-FIXES: m_p = static_cast(p ? p : static_cast(nullptr)); - - T *p2 = static_cast(reinterpret_cast((void*)NULL)); - // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr - // CHECK-FIXES: T *p2 = static_cast(nullptr); - - m_p = NULL; - // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr - // CHECK-FIXES: m_p = nullptr; - - int i = static_cast(0.f); - T *i2 = static_cast(0.f); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr - // CHECK-FIXES: T *i2 = nullptr; - } - - T *m_p; -}; - -struct Baz { - Baz() : i(0) {} - int i; -}; - -void test_cxx_cases() { - Foo f(g_null); - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr - // CHECK-FIXES: Foo f(nullptr); - - f.bar(NULL); - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr - // CHECK-FIXES: f.bar(nullptr); - - f.baz(g_null); - - f.m_p1 = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr - // CHECK-FIXES: f.m_p1 = nullptr; - - Bar b(g_null); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr - // CHECK-FIXES: Bar b(nullptr); - - Baz b2; - int Baz::*memptr(0); - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use nullptr - // CHECK-FIXES: int Baz::*memptr(nullptr); - - memptr = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr - // CHECK-FIXES: memptr = nullptr; -} - -void test_function_default_param1(void *p = 0); -// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr -// CHECK-FIXES: void test_function_default_param1(void *p = nullptr); - -void test_function_default_param2(void *p = NULL); -// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr -// CHECK-FIXES: void test_function_default_param2(void *p = nullptr); - -void test_function_default_param3(void *p = g_null); -// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr -// CHECK-FIXES: void test_function_default_param3(void *p = nullptr); - -void test_function(int *p) {} - -void test_function_no_ptr_param(int i) {} - -void test_function_call() { - test_function(0); - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr - // CHECK-FIXES: test_function(nullptr); - - test_function(NULL); - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr - // CHECK-FIXES: test_function(nullptr); - - test_function(g_null); - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr - // CHECK-FIXES: test_function(nullptr); - - test_function_no_ptr_param(0); -} - -char *test_function_return1() { - return 0; - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr - // CHECK-FIXES: return nullptr; -} - -void *test_function_return2() { - return NULL; - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr - // CHECK-FIXES: return nullptr; -} - -long *test_function_return3() { - return g_null; - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr - // CHECK-FIXES: return nullptr; -} - -int test_function_return4() { - return 0; -} - -int test_function_return5() { - return NULL; -} - -int test_function_return6() { - return g_null; -} - -int *test_function_return_cast1() { - return(int)0; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr - // CHECK-FIXES: return nullptr; -} - -int *test_function_return_cast2() { -#define RET return - RET(int)0; - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use nullptr - // CHECK-FIXES: RET nullptr; -#undef RET -} - -// Test parentheses expressions resulting in a nullptr. -int *test_parentheses_expression1() { - return(0); - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr - // CHECK-FIXES: return(nullptr); -} - -int *test_parentheses_expression2() { - return(int(0.f)); - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr - // CHECK-FIXES: return(nullptr); -} - -int *test_nested_parentheses_expression() { - return((((0)))); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr - // CHECK-FIXES: return((((nullptr)))); -} - -void *test_parentheses_explicit_cast() { - return(static_cast(0)); - // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr - // CHECK-FIXES: return(static_cast(nullptr)); -} - -void *test_parentheses_explicit_cast_sequence1() { - return(static_cast(static_cast((void*)NULL))); - // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr - // CHECK-FIXES: return(static_cast(nullptr)); -} - -void *test_parentheses_explicit_cast_sequence2() { - return(static_cast(reinterpret_cast((float*)int(0.f)))); - // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr - // CHECK-FIXES: return(static_cast(nullptr)); -} - -// Test explicit cast expressions resulting in nullptr. -struct Bam { - Bam(int *a) {} - Bam(float *a) {} - Bam operator=(int *a) { return Bam(a); } - Bam operator=(float *a) { return Bam(a); } -}; - -void ambiguous_function(int *a) {} -void ambiguous_function(float *a) {} -void const_ambiguous_function(const int *p) {} -void const_ambiguous_function(const float *p) {} - -void test_explicit_cast_ambiguous1() { - ambiguous_function((int*)0); - // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use nullptr - // CHECK-FIXES: ambiguous_function((int*)nullptr); -} - -void test_explicit_cast_ambiguous2() { - ambiguous_function((int*)(0)); - // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use nullptr - // CHECK-FIXES: ambiguous_function((int*)nullptr); -} - -void test_explicit_cast_ambiguous3() { - ambiguous_function(static_cast(reinterpret_cast((float*)0))); - // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: use nullptr - // CHECK-FIXES: ambiguous_function(static_cast(nullptr)); -} - -Bam test_explicit_cast_ambiguous4() { - return(((int*)(0))); - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr - // CHECK-FIXES: return(((int*)nullptr)); -} - -void test_explicit_cast_ambiguous5() { - // Test for ambiguous overloaded constructors. - Bam k((int*)(0)); - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use nullptr - // CHECK-FIXES: Bam k((int*)nullptr); - - // Test for ambiguous overloaded operators. - k = (int*)0; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr - // CHECK-FIXES: k = (int*)nullptr; -} - -void test_const_pointers_abiguous() { - const_ambiguous_function((int*)0); - // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use nullptr - // CHECK-FIXES: const_ambiguous_function((int*)nullptr); -} - -// Test where the implicit cast to null is surrounded by another implict cast -// with possible explict casts in-between. -void test_const_pointers() { - const int *const_p1 = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr - // CHECK-FIXES: const int *const_p1 = nullptr; - const int *const_p2 = NULL; - // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr - // CHECK-FIXES: const int *const_p2 = nullptr; - const int *const_p3 = (int)0; - // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr - // CHECK-FIXES: const int *const_p3 = nullptr; - const int *const_p4 = (int)0.0f; - // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr - // CHECK-FIXES: const int *const_p4 = nullptr; - const int *const_p5 = (int*)0; - // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use nullptr - // CHECK-FIXES: const int *const_p5 = (int*)nullptr; - int *t; - const int *const_p6 = static_cast(t ? t : static_cast(0)); - // CHECK-MESSAGES: :[[@LINE-1]]:69: warning: use nullptr - // CHECK-FIXES: const int *const_p6 = static_cast(t ? t : static_cast(nullptr)); -} - - -// FIXME: currently, the check doesn't work as it should with templates. -template -class A { - public: - A(T *p = NULL) {} - - void f() { - Ptr = NULL; - } - T *Ptr; -}; - -template -T *f2(T *a = NULL) { - return a ? a : NULL; -} diff --git a/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.cpp b/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.cpp deleted file mode 100644 index df8f30adf30f..000000000000 --- a/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// RUN: $(dirname %s)/check_clang_tidy.sh %s modernize-use-nullptr %t \ -// RUN: -config="{CheckOptions: [{key: modernize-use-nullptr.UserNullMacros, value: 'MY_NULL'}]}" \ -// RUN: -- -std=c++11 -// REQUIRES: shell - -#define NULL 0 - -namespace std { - -typedef decltype(nullptr) nullptr_t; - -} // namespace std - -// Just to make sure make_null() could have side effects. -void external(); - -std::nullptr_t make_null() { - external(); - return nullptr; -} - -void func() { - void *CallTest = make_null(); - - int var = 1; - void *CommaTest = (var+=2, make_null()); - - int *CastTest = static_cast(make_null()); -} - -void dummy(int*) {} -void side_effect() {} - -#define MACRO_EXPANSION_HAS_NULL \ - void foo() { \ - dummy(0); \ - dummy(NULL); \ - side_effect(); \ - } - -MACRO_EXPANSION_HAS_NULL; -#undef MACRO_EXPANSION_HAS_NULL - - -void test_macro_expansion1() { -#define MACRO_EXPANSION_HAS_NULL \ - dummy(NULL); \ - side_effect(); - - MACRO_EXPANSION_HAS_NULL; - -#undef MACRO_EXPANSION_HAS_NULL -} - -// Test macro expansion with cast sequence, PR15572. -void test_macro_expansion2() { -#define MACRO_EXPANSION_HAS_NULL \ - dummy((int*)0); \ - side_effect(); - - MACRO_EXPANSION_HAS_NULL; - -#undef MACRO_EXPANSION_HAS_NULL -} - -void test_macro_expansion3() { -#define MACRO_EXPANSION_HAS_NULL \ - dummy(NULL); \ - side_effect(); - -#define OUTER_MACRO \ - MACRO_EXPANSION_HAS_NULL; \ - side_effect(); - - OUTER_MACRO; - -#undef OUTER_MACRO -#undef MACRO_EXPANSION_HAS_NULL -} - -void test_macro_expansion4() { -#define MY_NULL NULL - int *p = MY_NULL; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr [modernize-use-nullptr] - // CHECK-FIXES: int *p = nullptr; -#undef MY_NULL -} - -#define IS_EQ(x, y) if (x != y) return; -void test_macro_args() { - int i = 0; - int *Ptr; - - IS_EQ(static_cast(0), Ptr); - // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr - // CHECK-FIXES: IS_EQ(static_cast(nullptr), Ptr); - - IS_EQ(0, Ptr); // literal - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr - // CHECK-FIXES: IS_EQ(nullptr, Ptr); - - IS_EQ(NULL, Ptr); // macro - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr - // CHECK-FIXES: IS_EQ(nullptr, Ptr); - - // These are ok since the null literal is not spelled within a macro. -#define myassert(x) if (!(x)) return; - myassert(0 == Ptr); - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr - // CHECK-FIXES: myassert(nullptr == Ptr); - - myassert(NULL == Ptr); - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr - // CHECK-FIXES: myassert(nullptr == Ptr); - - // These are bad as the null literal is buried in a macro. -#define BLAH(X) myassert(0 == (X)); -#define BLAH2(X) myassert(NULL == (X)); - BLAH(Ptr); - BLAH2(Ptr); - - // Same as above but testing extra macro expansion. -#define EXPECT_NULL(X) IS_EQ(0, X); -#define EXPECT_NULL2(X) IS_EQ(NULL, X); - EXPECT_NULL(Ptr); - EXPECT_NULL2(Ptr); - - // Almost the same as above but now null literal is not in a macro so ok - // to transform. -#define EQUALS_PTR(X) IS_EQ(X, Ptr); - EQUALS_PTR(0); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr - // CHECK-FIXES: EQUALS_PTR(nullptr); - EQUALS_PTR(NULL); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr - // CHECK-FIXES: EQUALS_PTR(nullptr); - - // Same as above but testing extra macro expansion. -#define EQUALS_PTR_I(X) EQUALS_PTR(X) - EQUALS_PTR_I(0); - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr - // CHECK-FIXES: EQUALS_PTR_I(nullptr); - EQUALS_PTR_I(NULL); - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr - // CHECK-FIXES: EQUALS_PTR_I(nullptr); - - // Ok since null literal not within macro. However, now testing macro - // used as arg to another macro. -#define decorate(EXPR) side_effect(); EXPR; - decorate(IS_EQ(NULL, Ptr)); - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr - // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr)); - decorate(IS_EQ(0, Ptr)); - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr - // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr)); - - // This macro causes a NullToPointer cast to happen where 0 is assigned to z - // but the 0 literal cannot be replaced because it is also used as an - // integer in the comparison. -#define INT_AND_PTR_USE(X) do { int *z = X; if (X == 4) break; } while(false) - INT_AND_PTR_USE(0); - - // Both uses of X in this case result in NullToPointer casts so replacement - // is possible. -#define PTR_AND_PTR_USE(X) do { int *z = X; if (X != z) break; } while(false) - PTR_AND_PTR_USE(0); - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr - // CHECK-FIXES: PTR_AND_PTR_USE(nullptr); - PTR_AND_PTR_USE(NULL); - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr - // CHECK-FIXES: PTR_AND_PTR_USE(nullptr); - -#define OPTIONAL_CODE(...) __VA_ARGS__ -#define NOT_NULL dummy(0) -#define CALL(X) X - OPTIONAL_CODE(NOT_NULL); - CALL(NOT_NULL); -}