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

Reply via email to