diff options
6 files changed, 102 insertions, 18 deletions
diff --git a/clang-tools-extra/cpp11-migrate/Transforms.h b/clang-tools-extra/cpp11-migrate/Transforms.h index 77fd7465c63..e660ccf9207 100644 --- a/clang-tools-extra/cpp11-migrate/Transforms.h +++ b/clang-tools-extra/cpp11-migrate/Transforms.h @@ -37,7 +37,7 @@ public: typedef TransformVec::const_iterator const_iterator; public: - + ~Transforms(); /// \brief Create command line options using LLVM's command line library. diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp index f0ad46880aa..79b8b5fc1b4 100644 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp +++ b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp @@ -28,6 +28,13 @@ using namespace clang; namespace { +const char *NullMacroName = "NULL"; + +static llvm::cl::opt<std::string> UserNullMacroNames( + "user-null-macros", llvm::cl::desc("Comma-separated list of user-defined " + "macro names that behave like NULL"), + llvm::cl::init("")); + /// \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. @@ -41,6 +48,25 @@ bool ReplaceWithNullptr(tooling::Replacements &Replace, SourceManager &SM, return false; } +/// \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. +llvm::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 clang::Lexer::getImmediateMacroName(OutermostMacroLoc, SM, LO); +} } /// \brief Looks for a sequences of 0 or more explicit casts with an implicit @@ -101,6 +127,16 @@ private: Expr *FirstSubExpr; }; +NullptrFixer::NullptrFixer(clang::tooling::Replacements &Replace, + unsigned &AcceptedChanges, RiskLevel) + : Replace(Replace), AcceptedChanges(AcceptedChanges) { + if (!UserNullMacroNames.empty()) { + llvm::StringRef S = UserNullMacroNames; + S.split(UserNullMacros, ","); + } + UserNullMacros.insert(UserNullMacros.begin(), llvm::StringRef(NullMacroName)); +} + void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) { SourceManager &SM = *Result.SourceManager; @@ -127,20 +163,19 @@ void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) { EndLoc = SM.getFileLoc(EndLoc); } else if (SM.isMacroBodyExpansion(StartLoc) && SM.isMacroBodyExpansion(EndLoc)) { - llvm::StringRef ImmediateMacroName = clang::Lexer::getImmediateMacroName( - StartLoc, SM, Result.Context->getLangOpts()); - if (ImmediateMacroName != "NULL") - return; + llvm::StringRef OutermostMacroName = + GetOutermostMacroName(StartLoc, SM, Result.Context->getLangOpts()); - SourceLocation MacroCallerStartLoc = - SM.getImmediateMacroCallerLoc(StartLoc); - SourceLocation MacroCallerEndLoc = SM.getImmediateMacroCallerLoc(EndLoc); + // Check to see if the user wants to replace the macro being expanded. + bool ReplaceNullMacro = + std::find(UserNullMacros.begin(), UserNullMacros.end(), + OutermostMacroName) != UserNullMacros.end(); - if (MacroCallerStartLoc.isFileID() && MacroCallerEndLoc.isFileID()) { - StartLoc = SM.getFileLoc(StartLoc); - EndLoc = SM.getFileLoc(EndLoc); - } else + if (!ReplaceNullMacro) return; + + StartLoc = SM.getFileLoc(StartLoc); + EndLoc = SM.getFileLoc(EndLoc); } AcceptedChanges += diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h index b1086ee7d06..a79cb301543 100644 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h +++ b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h @@ -25,9 +25,7 @@ class NullptrFixer : public clang::ast_matchers::MatchFinder::MatchCallback { public: NullptrFixer(clang::tooling::Replacements &Replace, unsigned &AcceptedChanges, - RiskLevel) : - Replace(Replace), - AcceptedChanges(AcceptedChanges) { } + RiskLevel); /// \brief Entry point to the callback called when matches are made. virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result); @@ -35,6 +33,7 @@ public: private: clang::tooling::Replacements &Replace; unsigned &AcceptedChanges; + llvm::SmallVector<llvm::StringRef, 1> UserNullMacros; }; #endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_NULLPTR_ACTIONS_H diff --git a/clang-tools-extra/docs/UseNullptrTransform.rst b/clang-tools-extra/docs/UseNullptrTransform.rst index 300caed2637..bc6289c5185 100644 --- a/clang-tools-extra/docs/UseNullptrTransform.rst +++ b/clang-tools-extra/docs/UseNullptrTransform.rst @@ -38,3 +38,45 @@ transforms to: int *ret_ptr() { return nullptr; } + + +User defined macros +=================== + +By default this transform will only replace the ``NULL`` macro and will skip any +user-defined macros that behaves like ``NULL``. The user can use the +:option:`-user-null-macros` option to specify a comma-separated list of macro +names that will be transformed along with ``NULL``. + +Example +------- + +.. code-block:: c++ + + #define MY_NULL (void*)0 + void assignment() { + void *p = MY_NULL; + } + + +using the command-line + +.. code-block:: bash + + cpp11-migrate -use-nullptr -user-null-macros=MY_NULL foo.cpp + + +transforms to: + +.. code-block:: c++ + + #define MY_NULL NULL + void assignment() { + int *p = nullptr; + } + + +Risk +==== + +:option:`-risk` has no effect in this transform. diff --git a/clang-tools-extra/docs/cpp11-migrate.rst b/clang-tools-extra/docs/cpp11-migrate.rst index 9d11f123518..6e787f28e35 100644 --- a/clang-tools-extra/docs/cpp11-migrate.rst +++ b/clang-tools-extra/docs/cpp11-migrate.rst @@ -40,6 +40,12 @@ Command Line Options Makes use of the new C++11 keyword ``nullptr`` where possible. See :doc:`UseNullptrTransform`. +.. option:: -user-null-macros=<string> + + ``<string>`` is a comma-separated list of user-defined macros that behave like + the ``NULL`` macro. The :option:`-use-nullptr` transform will replace these + macros along with ``NULL``. See :doc:`UseNullptrTransform`. + .. option:: -use-auto Replace the type specifier of variable declarations with the ``auto`` type @@ -76,7 +82,7 @@ Command Line Options :ref:`transform documentation <transforms>` for details. .. option:: -final-syntax-check - + After applying the final transform to a file, parse the file to ensure the last transform did not introduce syntax errors. Syntax errors introduced by earlier transforms are already caught when subsequent transforms parse the diff --git a/clang-tools-extra/test/cpp11-migrate/UseNullptr/macros.cpp b/clang-tools-extra/test/cpp11-migrate/UseNullptr/macros.cpp index 7b3c2f0c5b9..28de7458c60 100644 --- a/clang-tools-extra/test/cpp11-migrate/UseNullptr/macros.cpp +++ b/clang-tools-extra/test/cpp11-migrate/UseNullptr/macros.cpp @@ -1,6 +1,9 @@ // RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp // RUN: cpp11-migrate -use-nullptr %t.cpp -- -I %S // RUN: FileCheck -input-file=%t.cpp %s +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t2.cpp +// RUN: cpp11-migrate -use-nullptr -user-null-macros=MY_NULL %t2.cpp -- -I %S +// RUN: FileCheck -check-prefix=USER-SUPPLIED-NULL -input-file=%t2.cpp %s #define NULL 0 // CHECK: #define NULL 0 @@ -56,10 +59,9 @@ void test_macro_expansion2() { void test_macro_expansion3() { #define MY_NULL NULL - // TODO: Eventually we should fix the transform to detect cases like this so - // that we can replace MY_NULL with nullptr. int *p = MY_NULL; // CHECK: int *p = MY_NULL; + // USER-SUPPLIED-NULL: int *p = nullptr; #undef MY_NULL } |

