fbl/unique_ptr.h --> std <memory>

Change-Id: Ieb4150ffecfd86e30045bef8aaa4e05e33933df0
diff --git a/clang-tools-extra/clang-tidy/zircon/CMakeLists.txt b/clang-tools-extra/clang-tidy/zircon/CMakeLists.txt
index 56b6278..3ebc5db 100644
--- a/clang-tools-extra/clang-tidy/zircon/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/zircon/CMakeLists.txt
@@ -2,6 +2,7 @@
 
 add_clang_library(clangTidyZirconModule
   FblAtomicCheck.cpp
+  FblMemoryCheck.cpp
   FblMoveCheck.cpp
   FblLimitsCheck.cpp
   FblOptionalCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/zircon/FblMemoryCheck.cpp b/clang-tools-extra/clang-tidy/zircon/FblMemoryCheck.cpp
new file mode 100644
index 0000000..493f616
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/zircon/FblMemoryCheck.cpp
@@ -0,0 +1,152 @@
+//===--- FblMemoryCheck.cpp - clang-tidy ----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FblMemoryCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/Optional.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace zircon {
+
+class FblMemoryPPCallbacks : public PPCallbacks {
+public:
+  explicit FblMemoryPPCallbacks(FblMemoryCheck &Check, SourceManager &SM)
+      : Check(Check), SM(SM) {}
+
+  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+                          StringRef FileName, bool IsAngled,
+                          CharSourceRange FilenameRange, const FileEntry *File,
+                          StringRef SearchPath, StringRef RelativePath,
+                          const Module *Imported,
+                          SrcMgr::CharacteristicKind FileType) override;
+  void EndOfMainFile() override;
+
+private:
+  bool found = false;
+  CharSourceRange IncludeRange;
+
+  FblMemoryCheck &Check;
+  SourceManager &SM;
+};
+
+void FblMemoryPPCallbacks::InclusionDirective(
+    SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+    bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
+    StringRef SearchPath, StringRef RelativePath, const Module *Imported,
+    SrcMgr::CharacteristicKind FileType) {
+  if (FileName == "fbl/unique_ptr.h") {
+    unsigned End = std::strcspn(SM.getCharacterData(HashLoc), "\n") + 1;
+    IncludeRange =
+        CharSourceRange::getCharRange(HashLoc, HashLoc.getLocWithOffset(End));
+    found = true;
+  }
+}
+
+void FblMemoryPPCallbacks::EndOfMainFile() {
+  // Any instance of <fbl/unique_ptr.h> should be removed, since the decls in it
+  // will be replaced in this check and <memory> added.
+  if (found) {
+    if (!SM.isInMainFile(IncludeRange.getBegin())) {
+      Check.diag(IncludeRange.getBegin(),
+                 "including fbl/unique_ptr.h is deprecated, transitively "
+                 "included from %0")
+          << SM.getFilename(IncludeRange.getBegin())
+          << FixItHint::CreateRemoval(IncludeRange);
+      return;
+    }
+    Check.diag(IncludeRange.getBegin(),
+               "including fbl/unique_ptr.h is deprecated")
+        << FixItHint::CreateRemoval(IncludeRange);
+  }
+}
+
+void FblMemoryCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      valueDecl(hasType(cxxRecordDecl(
+                    allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
+                          hasName("unique_ptr")))))
+          .bind("unique_ptr"),
+      this);
+  Finder->addMatcher(
+      declRefExpr(hasDeclaration(functionDecl(
+                      allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
+                            hasName("make_unique")))))
+          .bind("make_unique"),
+      this);
+}
+
+void FblMemoryCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+  Inserter = llvm::make_unique<utils::IncludeInserter>(
+      Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
+  Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+  Compiler.getPreprocessor().addPPCallbacks(
+      llvm::make_unique<FblMemoryPPCallbacks>(*this,
+                                              Compiler.getSourceManager()));
+}
+
+void FblMemoryCheck::check(const MatchFinder::MatchResult &Result) {
+  SourceManager &SM = *Result.SourceManager;
+  SourceLocation Start;
+  SourceLocation End;
+  std::string Name;
+  if (const auto *V = Result.Nodes.getNodeAs<ValueDecl>("unique_ptr")) {
+    Start = V->getBeginLoc();
+    End = V->getEndLoc();
+    Name = "unique_ptr";
+  } else if (const auto *V =
+                 Result.Nodes.getNodeAs<DeclRefExpr>("make_unique")) {
+    Start = V->getBeginLoc();
+    End = V->getEndLoc();
+    Name = "make_unique";
+  }
+
+  // If it's a macro, we want to extract information about the macro instead of
+  // the expr.
+  if (Start.isMacroID()) {
+    Start = SM.getSpellingLoc(Start);
+    End = SM.getSpellingLoc(End);
+  }
+
+  bool Invalid = false;
+  StringRef Statement = Lexer::getSourceText(
+      CharSourceRange::getCharRange(Start, End), SM, getLangOpts(), &Invalid);
+  if (Invalid || !Statement.startswith("fbl"))
+    return;
+
+  size_t LAngle = Statement.find("<");
+  if (LAngle != std::string::npos)
+    End = Start.getLocWithOffset(LAngle - 1);
+
+  DiagnosticBuilder Diag =
+      diag(Start, "use of fbl::%0 is deprecated, use "
+                  "std::%1 instead")
+      << Name << Name
+      << FixItHint::CreateReplacement(SourceRange(Start, End), "std::" + Name);
+
+  // Add in the <unique_ptr> header, since we know this file uses it.
+  if (llvm::Optional<FixItHint> IncludeFixit =
+          Inserter->CreateIncludeInsertion(SM.getFileID(Start), "memory",
+                                           /*IsAngled=*/true)) {
+    Diag << *IncludeFixit;
+  }
+}
+
+void FblMemoryCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IncludeStyle", IncludeStyle);
+}
+
+} // namespace zircon
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/zircon/FblMemoryCheck.h b/clang-tools-extra/clang-tidy/zircon/FblMemoryCheck.h
new file mode 100644
index 0000000..cc16c42
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/zircon/FblMemoryCheck.h
@@ -0,0 +1,46 @@
+//===--- FblMemoryCheck.h - clang-tidy ------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_FBLMEMORYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_FBLMEMORYCHECK_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang {
+namespace tidy {
+namespace zircon {
+
+/// Replace instances of fbl::numeric_limits with std::numeric_limits, removes
+/// <fbl/limits.h> includes and adds <limits> include if std::numeric_limits is
+/// used.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/zircon-fbl-limits.html
+class FblMemoryCheck : public ClangTidyCheck {
+public:
+  FblMemoryCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context),
+        IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+            Options.getLocalOrGlobal("IncludeStyle", "google"))) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void registerPPCallbacks(clang::CompilerInstance &Compiler) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  std::unique_ptr<utils::IncludeInserter> Inserter;
+  const utils::IncludeSorter::IncludeStyle IncludeStyle;
+};
+
+} // namespace zircon
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_FBLMEMORYCHECK_H
diff --git a/clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp b/clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp
index c89774e..4e5c845 100644
--- a/clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp
@@ -11,6 +11,7 @@
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
 #include "FblAtomicCheck.h"
+#include "FblMemoryCheck.h"
 #include "FblMoveCheck.h"
 #include "FblLimitsCheck.h"
 #include "FblOptionalCheck.h"
@@ -29,6 +30,8 @@
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
     CheckFactories.registerCheck<FblAtomicCheck>(
         "zircon-fbl-atomic");
+    CheckFactories.registerCheck<FblMemoryCheck>(
+        "zircon-fbl-memory");
     CheckFactories.registerCheck<FblMoveCheck>(
         "zircon-fbl-move");
     CheckFactories.registerCheck<FblLimitsCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 7b6b1e1..91cd062 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -67,6 +67,11 @@
 Improvements to clang-tidy
 --------------------------
 
+- New :doc:`zircon-fbl-memory
+  <clang-tidy/checks/zircon-fbl-memory>` check.
+
+  FIXME: add release notes.
+
 - New :doc:`zircon-fbl-atomic
   <clang-tidy/checks/zircon-fbl-atomic>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index ad1c59f..3328779 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -260,6 +260,7 @@
    readability-uppercase-literal-suffix
    zircon-fbl-atomic
    zircon-fbl-limits
+   zircon-fbl-memory
    zircon-fbl-move
    zircon-fbl-optional
    zircon-fbl-type-traits
diff --git a/clang-tools-extra/docs/clang-tidy/checks/zircon-fbl-memory.rst b/clang-tools-extra/docs/clang-tidy/checks/zircon-fbl-memory.rst
new file mode 100644
index 0000000..9fdeb3b
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/zircon-fbl-memory.rst
@@ -0,0 +1,6 @@
+.. title:: clang-tidy - zircon-fbl-memory
+
+zircon-fbl-memory
+=================
+
+FIXME: Describe what patterns does the check detect and why. Give examples.
diff --git a/clang-tools-extra/test/clang-tidy/Inputs/zircon/fbl/unique_ptr.h b/clang-tools-extra/test/clang-tidy/Inputs/zircon/fbl/unique_ptr.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/Inputs/zircon/fbl/unique_ptr.h
diff --git a/clang-tools-extra/test/clang-tidy/Inputs/zircon/transitive.h b/clang-tools-extra/test/clang-tidy/Inputs/zircon/transitive.h
index fe6529d..cf3ca62 100644
--- a/clang-tools-extra/test/clang-tidy/Inputs/zircon/transitive.h
+++ b/clang-tools-extra/test/clang-tidy/Inputs/zircon/transitive.h
@@ -3,3 +3,4 @@
 #include <fbl/optional.h>
 #include <fbl/type_support.h>
 #include <fbl/atomic.h>
+#include <fbl/unique_ptr.h>
diff --git a/clang-tools-extra/test/clang-tidy/zircon-fbl-memory-transitive.cpp b/clang-tools-extra/test/clang-tidy/zircon-fbl-memory-transitive.cpp
new file mode 100644
index 0000000..c41afd8
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/zircon-fbl-memory-transitive.cpp
@@ -0,0 +1,11 @@
+// RUN: rm -rf %T/Unique
+// RUN: mkdir %T/Unique
+// RUN: cp -r %S/Inputs/zircon %T/Unique/zircon
+// RUN: %check_clang_tidy %s zircon-fbl-memory %t -- -header-filter=.* -- -std=c++11 -I %T/Unique/zircon
+// RUN: FileCheck -input-file=%T/Unique/zircon/transitive.h %s -check-prefix=CHECK-FIXES
+// RUN: rm -rf %T/Unique
+
+// transitive.h includes <fbl/unique_ptr.h>
+#include "transitive.h"
+// CHECK-NOTES: :6:1: warning: including fbl/unique_ptr.h is deprecated, transitively included from {{.*}}.
+// CHECK-FIXES-NOT: #include <fbl/unique_ptr.h>
diff --git a/clang-tools-extra/test/clang-tidy/zircon-fbl-memory.cpp b/clang-tools-extra/test/clang-tidy/zircon-fbl-memory.cpp
new file mode 100644
index 0000000..f6b9d1e
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/zircon-fbl-memory.cpp
@@ -0,0 +1,115 @@
+// RUN: %check_clang_tidy %s zircon-fbl-memory %t -- -- -isystem %S/Inputs/zircon
+
+#include <fbl/unique_ptr.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: including fbl/unique_ptr.h is deprecated
+// CHECK-FIXES-NOT: #include <fbl/unique_ptr.h>
+// CHECK-FIXES: #include <memory>
+
+namespace fbl {
+
+template <typename T>
+class unique_ptr {
+public:
+	explicit unique_ptr(T* t) { }
+};
+
+template <typename T>
+class unique_ptr<T[]> {
+public:
+	explicit unique_ptr(T* t) { }
+};
+
+template <typename T>
+struct unique_type {
+    using single = unique_ptr<T>;
+};
+
+template <typename T>
+struct unique_type<T[]> {
+    using incomplete_array = unique_ptr<T[]>;
+};
+
+template <typename T> struct remove_extent { using type = T; };
+
+template <typename T> struct remove_extent<T[]> { using type = T; };
+
+// Constructs a new object and assigns it to a unique_ptr.
+template <typename T, typename... Args>
+typename unique_type<T>::single make_unique(Args &&... args) {
+  return unique_ptr<T>(new T());
+}
+
+template <typename T, typename... Args>
+typename unique_type<T>::incomplete_array make_unique(int size) {
+  using single_type = typename remove_extent<T>::type;
+  return unique_ptr<single_type[]>(new single_type[size]());
+}
+
+} // namespace fbl
+
+namespace std {
+template <class T>
+struct default_delete {};
+
+template <class T> struct default_delete<T[]> {};
+
+template <class T, class D = default_delete<T> > class unique_ptr {
+public:
+  explicit unique_ptr(T *t) {}
+};
+
+template <class T, class D> class unique_ptr<T[], D> {
+public:
+  explicit unique_ptr(T *t) {}
+};
+
+template <class _Tp> struct __unique_if {
+  typedef unique_ptr<_Tp> __unique_single;
+};
+
+template <class _Tp> struct __unique_if<_Tp[]> {
+  typedef unique_ptr<_Tp[]> __unique_array_unknown_bound;
+};
+
+template<class _Tp, int _Np>
+struct __unique_if<_Tp[_Np]>
+{
+    typedef void __unique_array_known_bound;
+};
+
+template <class _Tp> struct remove_extent
+    {typedef _Tp type;};
+template <class _Tp> struct remove_extent<_Tp[]>
+    {typedef _Tp type;};
+template <class _Tp, int _Np> struct remove_extent<_Tp[_Np]>
+    {typedef _Tp type;};
+
+template<class _Tp, class... _Args>
+typename __unique_if<_Tp>::__unique_single
+make_unique(_Args&&... __args)
+{
+    return unique_ptr<_Tp>(new _Tp());
+}
+
+template<class _Tp>
+typename __unique_if<_Tp>::__unique_array_unknown_bound
+make_unique(int __n)
+{
+    typedef typename remove_extent<_Tp>::type _Up;
+    return unique_ptr<_Tp>(new _Up[__n]());
+}
+
+} // namespace std
+
+int main() {
+  fbl::unique_ptr<int> a = fbl::make_unique<int>();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of fbl::unique_ptr is deprecated, use std::unique_ptr instead
+  // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of fbl::make_unique is deprecated, use std::make_unique instead
+  // CHECK-FIXES: std::unique_ptr<int> a = std::make_unique<int>();
+  std::unique_ptr<int> b = std::make_unique<int>();
+
+  auto c = fbl::make_unique<int>();
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of fbl::make_unique is deprecated, use std::make_unique instead
+  // CHECK-FIXES: auto d = std::make_unique<int>();
+  auto d = std::make_unique<int>();
+}