[clang-tidy] Replace deprecated std::ios_base aliases

This check warns the uses of the deprecated member types of std::ios_base
and replaces those that have a non-deprecated equivalent.

Patch by andobence!

Reviewd by: alexfh

Revision ID: https://reviews.llvm.org/D51332

llvm-svn: 343848
diff --git a/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
new file mode 100644
index 0000000..2e9dad9
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
@@ -0,0 +1,80 @@
+//===--- DeprecatedIosBaseAliasesCheck.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 "DeprecatedIosBaseAliasesCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static const std::array<StringRef, 5> DeprecatedTypes = {
+    "::std::ios_base::io_state",  "::std::ios_base::open_mode",
+    "::std::ios_base::seek_dir",  "::std::ios_base::streamoff",
+    "::std::ios_base::streampos",
+};
+
+static const llvm::StringMap<StringRef> ReplacementTypes = {
+    {"io_state", "iostate"},
+    {"open_mode", "openmode"},
+    {"seek_dir", "seekdir"}};
+
+void DeprecatedIosBaseAliasesCheck::registerMatchers(MatchFinder *Finder) {
+  // Only register the matchers for C++; the functionality currently does not
+  // provide any benefit to other languages, despite being benign.
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  auto IoStateDecl = typedefDecl(hasAnyName(DeprecatedTypes)).bind("TypeDecl");
+  auto IoStateType =
+      qualType(hasDeclaration(IoStateDecl), unless(elaboratedType()));
+
+  Finder->addMatcher(typeLoc(loc(IoStateType)).bind("TypeLoc"), this);
+}
+
+void DeprecatedIosBaseAliasesCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  SourceManager &SM = *Result.SourceManager;
+
+  const auto *Typedef = Result.Nodes.getNodeAs<TypedefDecl>("TypeDecl");
+  StringRef TypeName = Typedef->getName();
+  bool HasReplacement = ReplacementTypes.count(TypeName);
+
+  const auto *TL = Result.Nodes.getNodeAs<TypeLoc>("TypeLoc");
+  SourceLocation IoStateLoc = TL->getBeginLoc();
+
+  // Do not generate fixits for matches depending on template arguments and
+  // macro expansions.
+  bool Fix = HasReplacement && !TL->getType()->isDependentType();
+  if (IoStateLoc.isMacroID()) {
+    IoStateLoc = SM.getSpellingLoc(IoStateLoc);
+    Fix = false;
+  }
+
+  SourceLocation EndLoc = IoStateLoc.getLocWithOffset(TypeName.size() - 1);
+
+  if (HasReplacement) {
+    auto FixName = ReplacementTypes.lookup(TypeName);
+    auto Builder = diag(IoStateLoc, "'std::ios_base::%0' is deprecated; use "
+                                    "'std::ios_base::%1' instead")
+                   << TypeName << FixName;
+
+    if (Fix)
+      Builder << FixItHint::CreateReplacement(SourceRange(IoStateLoc, EndLoc),
+                                              FixName);
+  } else
+    diag(IoStateLoc, "'std::ios_base::%0' is deprecated") << TypeName;
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang