Add use-nullptr transform to cpp11-migrate

This transform converts 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.
- Added use-nullptr transform.
- Added C++11 support to the final syntax check. Used ArgumentAdjuster class to
  add -std=c++11 option to the command line options.
- Added tests for use-nullptr transform.
- Added tests that exercises both loop-convert and use-nullptr in the source
  file.

TODO: There's a known bug when using both -loop-convert and -use-nullptr at the
      same time.

Author: Tareq A Siraj <tareq.a.siraj@intel.com>
Reviewers: klimek, gribozavr
llvm-svn: 173178
diff --git a/clang-tools-extra/cpp11-migrate/CMakeLists.txt b/clang-tools-extra/cpp11-migrate/CMakeLists.txt
index d8e2d4b..30e33b4 100644
--- a/clang-tools-extra/cpp11-migrate/CMakeLists.txt
+++ b/clang-tools-extra/cpp11-migrate/CMakeLists.txt
@@ -12,6 +12,9 @@
 file(GLOB_RECURSE LoopConvertSources "LoopConvert/*.cpp")
 list(APPEND Cpp11MigrateSources ${LoopConvertSources})
 
+file(GLOB_RECURSE UseNullptrSources "UseNullptr/*.cpp")
+list(APPEND Cpp11MigrateSources ${UseNullptrSources})
+
 add_clang_executable(cpp11-migrate
   ${Cpp11MigrateSources}
   )
diff --git a/clang-tools-extra/cpp11-migrate/Cpp11Migrate.cpp b/clang-tools-extra/cpp11-migrate/Cpp11Migrate.cpp
index 36e3798..b3804f9 100644
--- a/clang-tools-extra/cpp11-migrate/Cpp11Migrate.cpp
+++ b/clang-tools-extra/cpp11-migrate/Cpp11Migrate.cpp
@@ -49,6 +49,15 @@
                clEnumValEnd),
     cl::init(RL_Reasonable));
 
+class EndSyntaxArgumentsAdjuster : public ArgumentsAdjuster {
+  CommandLineArguments Adjust(const CommandLineArguments &Args) {
+    CommandLineArguments AdjustedArgs = Args;
+    AdjustedArgs.push_back("-fsyntax-only");
+    AdjustedArgs.push_back("-std=c++11");
+    return AdjustedArgs;
+  }
+};
+
 int main(int argc, const char **argv) {
   llvm::sys::PrintStackTraceOnErrorSignal();
   Transforms TransformManager;
@@ -102,6 +111,10 @@
   // Final Syntax check.
   ClangTool EndSyntaxTool(OptionsParser.getCompilations(),
                           OptionsParser.getSourcePathList());
+
+  // Add c++11 support to clang.
+  EndSyntaxTool.setArgumentsAdjuster(new EndSyntaxArgumentsAdjuster);
+
   for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
                                           E = InputFileStates->end();
        I != E; ++I) {
diff --git a/clang-tools-extra/cpp11-migrate/Makefile b/clang-tools-extra/cpp11-migrate/Makefile
index fc17f8b..5b806d4 100644
--- a/clang-tools-extra/cpp11-migrate/Makefile
+++ b/clang-tools-extra/cpp11-migrate/Makefile
@@ -24,6 +24,8 @@
 # transform subdirectories. See below for more on .objdir.
 SOURCES += $(addprefix LoopConvert/,$(notdir $(wildcard $(PROJ_SRC_DIR)/LoopConvert/*.cpp)))
 BUILT_SOURCES = $(ObjDir)/LoopConvert/.objdir
+SOURCES += $(addprefix UseNullptr/,$(notdir $(wildcard $(PROJ_SRC_DIR)/UseNullptr/*.cpp)))
+BUILT_SOURCES += $(ObjDir)/UseNullptr/.objdir
 
 LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
 USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
diff --git a/clang-tools-extra/cpp11-migrate/Transforms.cpp b/clang-tools-extra/cpp11-migrate/Transforms.cpp
index 6fc0923..6b2ab5c 100644
--- a/clang-tools-extra/cpp11-migrate/Transforms.cpp
+++ b/clang-tools-extra/cpp11-migrate/Transforms.cpp
@@ -14,6 +14,7 @@
 
 #include "Transforms.h"
 #include "LoopConvert/LoopConvert.h"
+#include "UseNullptr/UseNullptr.h"
 
 namespace cl = llvm::cl;
 
@@ -40,6 +41,12 @@
         cl::desc("Make use of range-based for loops where possible")),
       &ConstructTransform<LoopConvertTransform>));
 
+  Options.push_back(
+    OptionVec::value_type(
+      new cl::opt<bool>("use-nullptr",
+        cl::desc("Make use of nullptr keyword where possible")),
+      &ConstructTransform<UseNullptrTransform>));
+
   // Add more transform options here.
 }
 
diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp
new file mode 100644
index 0000000..54ea3e8
--- /dev/null
+++ b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp
@@ -0,0 +1,115 @@
+//===-- nullptr-convert/NullptrActions.cpp - Matcher callback -------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file
+///  \brief This file contains the definition of the NullptrFixer class which is
+///  used as an ASTMatcher callback. Also within this file is a helper AST
+///  visitor class used to identify sequences of explicit casts.
+///
+//===----------------------------------------------------------------------===//
+
+#include "NullptrActions.h"
+#include "NullptrMatchers.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+
+
+using namespace clang::ast_matchers;
+using namespace clang::tooling;
+using namespace clang;
+
+/// \brief Looks for a 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 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.
+class CastSequenceVisitor : public RecursiveASTVisitor<CastSequenceVisitor> {
+public:
+  CastSequenceVisitor(tooling::Replacements &R, SourceManager &SM,
+                      unsigned &AcceptedChanges) :
+    Replace(R), SM(SM), AcceptedChanges(AcceptedChanges), FirstCast(0) {}
+
+  // 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<CastExpr>(S);
+
+    if (!C) {
+      ResetFirstCast();
+      return true;
+    } else if (!FirstCast) {
+      FirstCast = C;
+    }
+
+    if (C->getCastKind() == CK_NullToPointer ||
+        C->getCastKind() == CK_NullToMemberPointer) {
+      SourceLocation StartLoc = FirstCast->getLocStart();
+      SourceLocation EndLoc = FirstCast->getLocEnd();
+
+      if (SM.getFileID(StartLoc) == SM.getFileID(EndLoc) &&
+          SM.isFromMainFile(StartLoc) && SM.isFromMainFile(EndLoc)) {
+        CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
+        Replace.insert(tooling::Replacement(SM, Range, "nullptr"));
+        ++AcceptedChanges;
+      }
+      ResetFirstCast();
+    }
+
+    return true;
+  }
+
+private:
+  void ResetFirstCast() { FirstCast = 0; }
+
+private:
+  tooling::Replacements &Replace;
+  SourceManager &SM;
+  unsigned &AcceptedChanges;
+  CastExpr *FirstCast;
+};
+
+
+void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) {
+  SourceManager &SM = *Result.SourceManager;
+
+  const CastExpr *NullCast = Result.Nodes.getNodeAs<CastExpr>(CastSequence);
+  if (NullCast) {
+    // Given 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 Visitor(Replace, SM, AcceptedChanges);
+    Visitor.TraverseStmt(const_cast<CastExpr*>(NullCast));
+  }
+
+  const CastExpr *Cast = Result.Nodes.getNodeAs<CastExpr>(ImplicitCastNode);
+  if (Cast) {
+    SourceLocation StartLoc = Cast->getLocStart();
+    SourceLocation EndLoc = Cast->getLocEnd();
+
+    if (SM.getFileID(StartLoc) != SM.getFileID(EndLoc))
+      return;
+
+    if (StartLoc.isMacroID())
+      StartLoc = SM.getExpansionLoc(StartLoc);
+    if (EndLoc.isMacroID())
+      EndLoc = SM.getExpansionLoc(EndLoc);
+
+    if (!SM.isFromMainFile(StartLoc) || !SM.isFromMainFile(EndLoc))
+      return;
+
+    CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
+    Replace.insert(tooling::Replacement(SM, Range, "nullptr"));
+    ++AcceptedChanges;
+  }
+}
diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h
new file mode 100644
index 0000000..b1086ee
--- /dev/null
+++ b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h
@@ -0,0 +1,40 @@
+//===-- nullptr-convert/NullptrActions.h - Matcher callback ------*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file
+///  \brief This file contains the declaration of the NullptrFixer class which
+///  is used as a ASTMatcher callback.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_NULLPTR_ACTIONS_H
+#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_NULLPTR_ACTIONS_H
+
+#include "Transform.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Refactoring.h"
+
+/// \brief The callback to be used for nullptr migration matchers.
+///
+class NullptrFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
+public:
+  NullptrFixer(clang::tooling::Replacements &Replace,
+               unsigned &AcceptedChanges,
+               RiskLevel) :
+  Replace(Replace),
+  AcceptedChanges(AcceptedChanges) { }
+
+  /// \brief Entry point to the callback called when matches are made.
+  virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result);
+
+private:
+  clang::tooling::Replacements &Replace;
+  unsigned &AcceptedChanges;
+};
+
+#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_NULLPTR_ACTIONS_H
diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.cpp
new file mode 100644
index 0000000..a6522a1
--- /dev/null
+++ b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.cpp
@@ -0,0 +1,53 @@
+//===-- nullptr-convert/Matchers.cpp - Matchers for null casts ------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file
+///  \brief This file contains the definitions for matcher-generating functions
+///  and a custom AST_MATCHER for identifying casts of type CK_NullTo*.
+///
+//===----------------------------------------------------------------------===//
+#include "NullptrMatchers.h"
+#include "clang/AST/ASTContext.h"
+
+using namespace clang::ast_matchers;
+using namespace clang;
+
+const char *ImplicitCastNode = "cast";
+const char *CastSequence = "sequence";
+
+namespace clang {
+namespace ast_matchers {
+/// \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;
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
+
+StatementMatcher makeImplicitCastMatcher() {
+  return implicitCastExpr(allOf(unless(hasAncestor(explicitCastExpr())),
+                                isNullToPointer())).bind(ImplicitCastNode);
+}
+
+StatementMatcher makeCastSequenceMatcher() {
+  return explicitCastExpr(
+            allOf(unless(hasAncestor(explicitCastExpr())),
+                  hasDescendant(implicitCastExpr(isNullToPointer())))
+            ).bind(CastSequence);
+}
diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.h b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.h
new file mode 100644
index 0000000..e6d2317
--- /dev/null
+++ b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.h
@@ -0,0 +1,38 @@
+//===-- nullptr-convert/Matchers.h - Matchers for null casts ---*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file
+///  \brief This file contains the declarations for matcher-generating functions
+///  and names for bound nodes found by AST matchers.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_NULLPTR_MATCHERS_H
+#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_NULLPTR_MATCHERS_H
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+// Names to bind with matched expressions.
+extern const char *ImplicitCastNode;
+extern const char *CastSequence;
+
+/// \brief Create a matcher to find the implicit casts clang inserts
+/// when writing null to a pointer.
+///
+/// However, don't match those implicit casts that have explicit casts as
+/// an ancestor. Explicit casts are handled by makeCastSequenceMatcher().
+clang::ast_matchers::StatementMatcher makeImplicitCastMatcher();
+
+/// \brief Create a matcher that finds the head of a sequence of nested explicit
+/// casts that have an implicit cast to null within.
+///
+/// This matcher is necessary so that an entire sequence of explicit casts can
+/// be replaced instead of just the inner-most implicit cast.
+clang::ast_matchers::StatementMatcher makeCastSequenceMatcher();
+
+#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_NULLPTR_MATCHERS_H
diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp
new file mode 100644
index 0000000..aaf5bf1
--- /dev/null
+++ b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp
@@ -0,0 +1,68 @@
+//===-- LoopConvert/LoopConvert.cpp - C++11 for-loop migration --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the implementation of the UseNullptrTransform
+/// class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "UseNullptr.h"
+#include "NullptrActions.h"
+#include "NullptrMatchers.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+
+using clang::ast_matchers::MatchFinder;
+using namespace clang::tooling;
+using namespace clang;
+
+int UseNullptrTransform::apply(const FileContentsByPath &InputStates,
+                               RiskLevel MaxRisk,
+                               const CompilationDatabase &Database,
+                               const std::vector<std::string> &SourcePaths,
+                               FileContentsByPath &ResultStates) {
+  RefactoringTool UseNullptrTool(Database, SourcePaths);
+
+  for (FileContentsByPath::const_iterator I = InputStates.begin(),
+       E = InputStates.end();
+       I != E; ++I) {
+    UseNullptrTool.mapVirtualFile(I->first, I->second);
+  }
+
+  unsigned AcceptedChanges = 0;
+
+  MatchFinder Finder;
+  NullptrFixer Fixer(UseNullptrTool.getReplacements(),
+                     AcceptedChanges,
+                     MaxRisk);
+
+  Finder.addMatcher(makeImplicitCastMatcher(), &Fixer);
+  Finder.addMatcher(makeCastSequenceMatcher(), &Fixer);
+
+  if (int result = UseNullptrTool.run(newFrontendActionFactory(&Finder))) {
+    llvm::errs() << "Error encountered during translation.\n";
+    return result;
+  }
+
+  RewriterContainer Rewrite(UseNullptrTool.getFiles());
+
+  // FIXME: Do something if some replacements didn't get applied?
+  UseNullptrTool.applyAllReplacements(Rewrite.getRewriter());
+
+  collectResults(Rewrite.getRewriter(), ResultStates);
+
+  if (AcceptedChanges > 0) {
+    setChangesMade();
+  }
+
+  return 0;
+}
diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h
new file mode 100644
index 0000000..c62ed84
--- /dev/null
+++ b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h
@@ -0,0 +1,34 @@
+//===-- LoopConvert/LoopConvert.h - C++11 for-loop migration ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the definition of the UseNullptrTransform
+/// class which is the main interface to the use-nullptr transform
+/// that tries to make use of nullptr where possible.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_NULLPTR_H
+#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_NULLPTR_H
+
+#include "Transform.h"
+#include "llvm/Support/Compiler.h" // For LLVM_OVERRIDE
+
+/// \brief Subclass of Transform that transforms null pointer constants into
+/// C++11's nullptr keyword where possible.
+class UseNullptrTransform : public Transform {
+public:
+  /// \see Transform::run().
+  virtual int apply(const FileContentsByPath &InputStates,
+                    RiskLevel MaxRiskLEvel,
+                    const clang::tooling::CompilationDatabase &Database,
+                    const std::vector<std::string> &SourcePaths,
+                    FileContentsByPath &ResultStates) LLVM_OVERRIDE;
+};
+
+#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_NULLPTR_H