forked from OSchip/llvm-project
Allow users to specify NULL like macros to be replaced
-use-nullptr only replaced macro named NULL and ignored any user defined macros that behaved like NULL. This patch introduces -user-null-macros command line option to let users specify their custom NULL like macros. - Added a -user-null-macros command line option that takes a comma-separated list of user-defined macros to be replaced when using the -use-nullptr transform. - Added documentation. - Updated testcase to reflect current behavior. - Whitespace fixes. Reviewers: revane, klimek, gribozavr llvm-svn: 178243
This commit is contained in:
parent
0118635979
commit
c2aa348dd0
|
@ -37,7 +37,7 @@ public:
|
|||
typedef TransformVec::const_iterator const_iterator;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
~Transforms();
|
||||
|
||||
/// \brief Create command line options using LLVM's command line library.
|
||||
|
|
|
@ -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")
|
||||
llvm::StringRef OutermostMacroName =
|
||||
GetOutermostMacroName(StartLoc, SM, Result.Context->getLangOpts());
|
||||
|
||||
// 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 (!ReplaceNullMacro)
|
||||
return;
|
||||
|
||||
SourceLocation MacroCallerStartLoc =
|
||||
SM.getImmediateMacroCallerLoc(StartLoc);
|
||||
SourceLocation MacroCallerEndLoc = SM.getImmediateMacroCallerLoc(EndLoc);
|
||||
|
||||
if (MacroCallerStartLoc.isFileID() && MacroCallerEndLoc.isFileID()) {
|
||||
StartLoc = SM.getFileLoc(StartLoc);
|
||||
EndLoc = SM.getFileLoc(EndLoc);
|
||||
} else
|
||||
return;
|
||||
StartLoc = SM.getFileLoc(StartLoc);
|
||||
EndLoc = SM.getFileLoc(EndLoc);
|
||||
}
|
||||
|
||||
AcceptedChanges +=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue