revane added you to the CC list for the revision "C++11 nullptr-convert
standalone tool".
Hi chandlerc, klimek,
This is the initial commit for a standalone tool that converts the usage of
null pointer constants (e.g. NULL, 0, etc.) in legacy C++ code to the new C+11
nullptr keyword. This revision handles only pointer variable declarations and
assignments.
Author: Tareq A. Siraj <[email protected]>
http://llvm-reviews.chandlerc.com/D136
Files:
CMakeLists.txt
nullptr-convert/CMakeLists.txt
nullptr-convert/Makefile
nullptr-convert/Matchers.cpp
nullptr-convert/Matchers.h
nullptr-convert/NullptrActions.cpp
nullptr-convert/NullptrActions.h
nullptr-convert/NullptrConvert.cpp
test/CMakeLists.txt
test/nullptr-convert/basic.cpp
test/nullptr-convert/basic_failing.cpp
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(nullptr-convert)
add_subdirectory(remove-cstr-calls)
add_subdirectory(tool-template)
add_subdirectory(loop-convert)
Index: nullptr-convert/CMakeLists.txt
===================================================================
--- /dev/null
+++ nullptr-convert/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(LLVM_LINK_COMPONENTS support)
+set(LLVM_USED_LIBS clangTooling clangBasic clangAST)
+
+add_clang_executable(nullptr-convert
+ NullptrConvert.cpp
+ Matchers.cpp
+ NullptrActions.cpp
+ )
+set_target_properties(nullptr-convert
+ PROPERTIES
+ COMPILE_FLAGS -std=c++0x
+ )
+target_link_libraries(nullptr-convert
+ clangEdit
+ clangTooling
+ clangBasic
+ clangAST
+ clangASTMatchers
+ )
Index: nullptr-convert/Makefile
===================================================================
--- /dev/null
+++ nullptr-convert/Makefile
@@ -0,0 +1,25 @@
+##===- tools/extra/nullptr-convert/Makefile ----sssss-------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+
+TOOLNAME = nullptr-convert
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangRewriteFrontend.a clangRewriteCore.a clangParse.a \
+ clangSema.a clangAnalysis.a \
+ clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
Index: nullptr-convert/Matchers.cpp
===================================================================
--- /dev/null
+++ nullptr-convert/Matchers.cpp
@@ -0,0 +1,67 @@
+//===----------------- C++11 nullptr migration tool ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the matchers for use in migrating nullptr.
+//
+//===----------------------------------------------------------------------===//
+#include "Matchers.h"
+#include "clang/AST/ASTContext.h"
+
+namespace clang {
+namespace ast_matchers {
+
+/// \brief Matches declarations that are initialized to a null pointer constant.
+///
+/// Given
+/// \code
+/// int *p1 = 0;
+/// int *p2 = NULL;
+/// const int null = 0;
+/// int *p3 = null;
+/// int p4 = NULL;
+/// \endcode
+/// The matcher
+/// \code
+/// varDecl(hasNullInitializer(), hasType(pointerType()))
+/// \endcode
+/// would match the declarations for p1, p2 and p3 but not p4.
+AST_MATCHER(VarDecl, hasNullInitializer) {
+ const Expr *Initializer = Node.getAnyInitializer();
+ return (Initializer != NULL && Initializer->isNullPointerConstant(
+ Node.getASTContext(), Expr::NPC_ValueDependentIsNull)
+ != Expr::NPCK_NotNull);
+}
+
+} // end namespace ast_matchers
+
+namespace nullptr_convert {
+
+const char *AssignToPointer = "assignmentToPointer";
+const char *InitWithNullPointer = "initWithNullPointer";
+
+ast_matchers::DeclarationMatcher makeInitWithNullPointerMatcher() {
+ using namespace clang::ast_matchers;
+
+ return varDecl(hasNullInitializer(), hasType(
+ pointerType())).bind(InitWithNullPointer);
+}
+
+ast_matchers::StatementMatcher makeAssignToPointerMatcher() {
+ // We only match assignments to pointer type here because checking if the
+ // assignment is a null pointer constant requires access to the AST which
+ // is not available in this specific matcher. We check for null pointer
+ // constants in a RecursiveASTVisitor on statements that match here.
+ using namespace clang::ast_matchers;
+
+ return binaryOperator(hasOperatorName("="),
+ hasLHS(hasType(pointerType()))).bind(AssignToPointer);
+}
+
+} // end namespace nullptr_convert
+} // end namespace clang
Index: nullptr-convert/Matchers.h
===================================================================
--- /dev/null
+++ nullptr-convert/Matchers.h
@@ -0,0 +1,35 @@
+//===----------------- C++11 nullptr migration tool ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the matchers for use in migrating nullptr.
+//
+//===----------------------------------------------------------------------===//
+#ifndef __MATCHERS_H__
+#define __MATCHERS_H__
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+namespace clang {
+namespace nullptr_convert {
+
+// Names to bind with matchers.
+extern const char *AssignToPointer;
+extern const char *InitWithNullPointer;
+
+/// \brief The matcher for pointer variable declaration with assignment to
+/// null pointer constants.
+ast_matchers::DeclarationMatcher makeInitWithNullPointerMatcher();
+
+/// \brief The matcher for assignments to pointer types.
+ast_matchers::StatementMatcher makeAssignToPointerMatcher();
+
+} // end namespace nullptr_convert
+} // end namespace clang
+
+#endif //__MATCHERS_H__
Index: nullptr-convert/NullptrActions.cpp
===================================================================
--- /dev/null
+++ nullptr-convert/NullptrActions.cpp
@@ -0,0 +1,100 @@
+//===----------------- C++11 nullptr migration tool ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the callback for use in migrating nullptr.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NullptrActions.h"
+#include "Matchers.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+
+namespace clang {
+namespace nullptr_convert {
+
+/// \brief Discover usages of expressions consisting of null pointer constants
+/// in the right hand side of a binary operator statement.
+class AssignToPtrVisitor : public RecursiveASTVisitor<AssignToPtrVisitor> {
+public:
+ AssignToPtrVisitor(ASTContext &C)
+ : Context(C), NullPtrConstExpr(nullptr) {}
+
+ /// \brief Overridden method for visiting binary operator statements.
+ bool VisitBinaryOperator(BinaryOperator *BOPExpr) {
+ Expr *E = BOPExpr->getRHS();
+ if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)
+ != Expr::NPCK_NotNull) {
+ assert(NullPtrConstExpr == nullptr
+ && "We should at most find 1 null pointer const expression.");
+ NullPtrConstExpr = E;
+ }
+ return true;
+ }
+
+ /// \brief Retrieve the vector of expressions that are null pointer
+ /// expressions.
+ const Expr *getNullPtrConstExpr() const {
+ return NullPtrConstExpr;
+ }
+
+private:
+ ASTContext &Context;
+ Expr *NullPtrConstExpr;
+}; // end class AssignToPtrVisitor
+
+NullptrFixer::NullptrFixer(tooling::Replacements &R, unsigned* AcceptedChanges)
+: Replace(R), AcceptedChanges(AcceptedChanges) {
+}
+
+void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) {
+ ASTContext &Context = *Result.Context;
+
+ // Lambda function for retrieving the source location that returns the
+ // expansion location for macros and the same location otherwise.
+ auto getSourceLoc = [&Context](SourceLocation Loc) -> SourceLocation {
+ if (Loc.isMacroID())
+ return Context.getSourceManager().getExpansionLoc(Loc);
+
+ return Loc;
+ };
+
+ const VarDecl *Declaration
+ = Result.Nodes.getNodeAs<VarDecl>(InitWithNullPointer);
+ if (Declaration) {
+ const Expr *E = Declaration->getInit();
+ SourceLocation ExprLoc = E->getExprLoc();
+
+ CharSourceRange Range(SourceRange(getSourceLoc(ExprLoc)), true);
+ Replace.insert(tooling::Replacement(Context.getSourceManager(), Range,
+ "nullptr"));
+ ++*AcceptedChanges;
+ }
+
+ const Stmt *Statement = Result.Nodes.getNodeAs<Stmt>(AssignToPointer);
+ if (Statement) {
+ AssignToPtrVisitor V(Context);
+ V.TraverseStmt(const_cast<Stmt*>(Statement));
+
+ const Expr* NullExpr = V.getNullPtrConstExpr();
+ // Check if there was a null pointer constant expression in the matched
+ // assignment.
+ if (NullExpr) {
+ CharSourceRange Range(SourceRange(getSourceLoc(NullExpr->getExprLoc())),
+ true);
+ Replace.insert(tooling::Replacement(Context.getSourceManager(), Range,
+ "nullptr"));
+ ++*AcceptedChanges;
+ }
+ }
+}
+
+} // end namespace nullptr_convert
+} // end namespace clang
Index: nullptr-convert/NullptrActions.h
===================================================================
--- /dev/null
+++ nullptr-convert/NullptrActions.h
@@ -0,0 +1,42 @@
+//===----------------- C++11 nullptr migration tool ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the callback for use in migrating nullptr.
+//
+//===----------------------------------------------------------------------===//
+#ifndef __NULLPTR_ACTIONS_H__
+#define __NULLPTR_ACTIONS_H__
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Refactoring.h"
+
+namespace clang {
+namespace nullptr_convert {
+
+/// \brief The callback to be used for nullptr migration matchers.
+///
+/// The callback does extra checking if assignments to pointer types are null
+/// pointer constants.
+class NullptrFixer : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ NullptrFixer(tooling::Replacements &R, unsigned *AccpetedChanges);
+
+ /// \brief The NullptrFixer callback, which determines if pointer variable
+ /// declarations, assignments and function calls are eligible to use nullptr.
+ virtual void run(const ast_matchers::MatchFinder::MatchResult &Result);
+
+private:
+ tooling::Replacements &Replace;
+ unsigned *AcceptedChanges;
+}; // end class NullptrFixer
+
+} // end namespace nullptr_convert
+} // end namespace clang
+
+#endif //__NULLPTR_ACTIONS_H__
Index: nullptr-convert/NullptrConvert.cpp
===================================================================
--- /dev/null
+++ nullptr-convert/NullptrConvert.cpp
@@ -0,0 +1,104 @@
+//===----------------- C++11 nullptr migration tool ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a tool that migrates the usage of null pointer
+// constants (e.g. NULL, 0, etc.) in legacy C++ code and converts them to use
+// the new C++11 nullptr keyword.
+//
+// Usage:
+// nullptr-convert <cmake-output-dir> <file1> <file2> ...
+//
+// Where:
+// <cmake-output-dir> is a CMake build directory containing a file named
+// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+// CMake to get this file).
+//
+// <file1>... specify the paths of files in the CMake source tree, with the
+// same requirements as other tools built on LibTooling.
+//
+// For example, to use nullptr-convert on all files in a subtree of the
+// source tree, use:
+//
+// /path/in/subtree $ find . -name '*.cpp'|
+// xargs nullptr-convert /path/to/build
+//
+//===----------------------------------------------------------------------===//
+
+#include "Matchers.h"
+#include "NullptrActions.h"
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Frontend/FrontendActions.h"
+
+using namespace llvm;
+using namespace clang::tooling;
+
+// Setup the command line options
+static cl::opt<std::string> BuildPath(
+ cl::Positional,
+ cl::desc("<build-path>"));
+
+static cl::list<std::string> SourcePaths(
+ cl::Positional,
+ cl::desc("<source0> [... <sourceN>]"),
+ cl::OneOrMore);
+
+int main(int argc, const char **argv) {
+ llvm::OwningPtr<clang::tooling::CompilationDatabase> Compilations(
+ FixedCompilationDatabase::loadFromCommandLine(argc, argv));
+ cl::ParseCommandLineOptions(argc, argv);
+
+ if (!Compilations) {
+ std::string ErrorMessage;
+ Compilations.reset(!BuildPath.empty() ?
+ CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
+ CompilationDatabase::autoDetectFromSource(SourcePaths[0], ErrorMessage));
+
+ if (!Compilations) {
+ llvm::report_fatal_error(ErrorMessage);
+ }
+ }
+
+ ClangTool SyntaxOnlyTool(*Compilations, SourcePaths);
+ // First, let's check to make sure there are no errors.
+ if (int result = SyntaxOnlyTool.run(
+ newFrontendActionFactory<clang::SyntaxOnlyAction>())) {
+ llvm::report_fatal_error("Error compiling files.\n");
+ return result;
+ }
+
+ RefactoringTool Tool(*Compilations, SourcePaths);
+ unsigned AcceptedChanges = 0;
+ clang::ast_matchers::MatchFinder Finder;
+ clang::nullptr_convert::NullptrFixer Fixer(Tool.getReplacements(),
+ &AcceptedChanges);
+ Finder.addMatcher(clang::nullptr_convert::makeInitWithNullPointerMatcher(),
+ &Fixer);
+ Finder.addMatcher(clang::nullptr_convert::makeAssignToPointerMatcher(),
+ &Fixer);
+
+ if (int result = Tool.run(newFrontendActionFactory(&Finder))) {
+ llvm::errs() << "Error encountered during translation.\n";
+ return result;
+ }
+
+ if (AcceptedChanges > 0) {
+ // Check to see if the changes introduced any new errors.
+ ClangTool EndSyntaxTool(*Compilations, SourcePaths);
+ if (int result = EndSyntaxTool.run(
+ newFrontendActionFactory<clang::SyntaxOnlyAction>())) {
+ llvm::errs() << "Error compiling files after translation.\n";
+ return result;
+ }
+ }
+ return 0;
+}
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -22,7 +22,7 @@
clang clang-headers FileCheck count not
# Individual tools we test.
- remove-cstr-calls loop-convert
+ remove-cstr-calls loop-convert nullptr-convert
)
add_lit_testsuite(check-clang-tools "Running the Clang extra tools' regression tests"
Index: test/nullptr-convert/basic.cpp
===================================================================
--- /dev/null
+++ test/nullptr-convert/basic.cpp
@@ -0,0 +1,60 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: nullptr-convert . %t.cpp -- -std=c++11 -w -I %S
+// RUN: FileCheck -input-file=%t.cpp %s
+// REQUIRES: shell
+
+#include <stddef.h>
+
+const unsigned int g_null = 0;
+
+void test_assignment() {
+ int *p1 = 0;
+ // CHECK: int *p1 = nullptr;
+ p1 = 0;
+ // CHECK: p1 = nullptr;
+
+ int *p2 = NULL;
+ // CHECK: int *p2 = nullptr;
+
+ p2 = p1;
+ // CHECK: p2 = p1;
+
+ const int null = 0;
+ int *p3 = null;
+ // CHECK: int *p3 = nullptr;
+
+ p3 = NULL;
+ // CHECK: p3 = nullptr;
+
+ int *p4 = p3;
+ // CHECK: int *p4 = p3;
+
+ p4 = null;
+ // CHECK: p4 = nullptr;
+
+ int i1 = 0;
+ // CHECK: int i1 = 0;
+
+ int i2 = NULL;
+ // CHECK: int i2 = NULL;
+
+ int i3 = null;
+ // CHECK: int i3 = null;
+
+ int *p5, *p6, *p7;
+ p5 = p6 = p7 = NULL;
+ // CHECK: p5 = p6 = p7 = nullptr;
+}
+
+void test_function_default_param1(void *p = 0);
+// CHECK: void test_function_default_param1(void *p = nullptr);
+
+void test_function_default_param2(void *p = NULL);
+// CHECK: void test_function_default_param2(void *p = nullptr);
+
+void test_function_default_param3(void *p = g_null);
+// CHECK: void test_function_default_param3(void *p = nullptr);
+
+void test_function(int *p) {}
+// CHECK: void test_function(int *p) {}
+
Index: test/nullptr-convert/basic_failing.cpp
===================================================================
--- /dev/null
+++ test/nullptr-convert/basic_failing.cpp
@@ -0,0 +1,69 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: nullptr-convert . %t.cpp -- -std=c++11 -w -I %S
+// RUN: FileCheck -input-file=%t.cpp %s
+// REQUIRES: shell
+// XFAIL: *
+
+#include <stddef.h>
+
+const unsigned int g_null = 0;
+
+void test_function_default_param1(void *p = 0);
+// CHECK: void test_function_default_param1(void *p = nullptr);
+
+void test_function_default_param2(void *p = NULL);
+// CHECK: void test_function_default_param2(void *p = nullptr);
+
+void test_function_default_param3(void *p = g_null);
+// CHECK: void test_function_default_param3(void *p = nullptr);
+
+void test_function(int *p) {}
+// CHECK: void test_function(int *p) {}
+
+void test_function_no_ptr_param(int i) {}
+
+void test_function_call() {
+ test_function(0);
+ // CHECK: test_function(nullptr);
+
+ test_function(NULL);
+ // CHECK: test_function(nullptr);
+
+ test_function(g_null);
+ // CHECK: test_function(nullptr);
+
+ test_function_no_ptr_param(0);
+ // CHECK: test_function_no_ptr_param(0);
+}
+
+char* test_function_return1() {
+ return 0;
+ // CHECK: return nullptr;
+}
+
+void* test_function_return2() {
+ return NULL;
+ // CHECK: return nullptr;
+}
+
+long* test_function_return3() {
+ return g_null;
+ // CHECK: return nullptr;
+}
+
+int test_function_return4() {
+ return 0;
+ // CHECK: return 0;
+}
+
+int test_function_return5() {
+ return NULL;
+ // CHECK: return NULL;
+}
+
+int test_function_return6() {
+ return g_null;
+ // CHECK: return g_null;
+}
+
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits