<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Aug 11, 2015 at 1:37 PM, Manuel Klimek via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank" class="cremed">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: klimek<br>
Date: Tue Aug 11 06:37:48 2015<br>
New Revision: 244586<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=244586&view=rev" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project?rev=244586&view=rev</a><br>
Log:<br>
Add an IncludeInserter to clang-tidy.<br>
<br>
Will be used to allow checks to insert includes at the right position.<br>
<br>
Added:<br>
    clang-tools-extra/trunk/clang-tidy/IncludeInserter.cpp<br>
    clang-tools-extra/trunk/clang-tidy/IncludeInserter.h<br>
    clang-tools-extra/trunk/clang-tidy/IncludeSorter.cpp<br>
    clang-tools-extra/trunk/clang-tidy/IncludeSorter.h<br>
    clang-tools-extra/trunk/unittests/clang-tidy/IncludeInserterTest.cpp<br>
Modified:<br>
    clang-tools-extra/trunk/clang-tidy/CMakeLists.txt<br>
    clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt<br>
    clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h<br>
<br>
Modified: clang-tools-extra/trunk/clang-tidy/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/CMakeLists.txt?rev=244586&r1=244585&r2=244586&view=diff" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/CMakeLists.txt?rev=244586&r1=244585&r2=244586&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-tidy/CMakeLists.txt (original)<br>
+++ clang-tools-extra/trunk/clang-tidy/CMakeLists.txt Tue Aug 11 06:37:48 2015<br>
@@ -7,6 +7,8 @@ add_clang_library(clangTidy<br>
   ClangTidyModule.cpp<br>
   ClangTidyDiagnosticConsumer.cpp<br>
   ClangTidyOptions.cpp<br>
+  IncludeInserter.cpp<br>
+  IncludeSorter.cpp<br>
<br>
   DEPENDS<br>
   ClangSACheckers<br>
<br>
Added: clang-tools-extra/trunk/clang-tidy/IncludeInserter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/IncludeInserter.cpp?rev=244586&view=auto" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/IncludeInserter.cpp?rev=244586&view=auto</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-tidy/IncludeInserter.cpp (added)<br>
+++ clang-tools-extra/trunk/clang-tidy/IncludeInserter.cpp Tue Aug 11 06:37:48 2015<br>
@@ -0,0 +1,77 @@<br>
+//===-------- IncludeInserter.cpp - clang-tidy ----------------------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "IncludeInserter.h"<br>
+<br>
+namespace clang {<br>
+namespace tidy {<br>
+<br>
+class IncludeInserterCallback : public PPCallbacks {<br>
+public:<br>
+  explicit IncludeInserterCallback(IncludeInserter *IncludeInserter)<br>
+      : IncludeInserter(IncludeInserter) {}<br>
+  // Implements PPCallbacks::InclusionDerective(). Records the names and source<br>
+  // locations of the inclusions in the main source file being processed.<br>
+  void InclusionDirective(SourceLocation HashLocation,<br>
+                          const Token & /*include_token*/,<br>
+                          StringRef FileNameRef, bool IsAngled,<br>
+                          CharSourceRange FileNameRange,<br>
+                          const FileEntry * /*IncludedFile*/,<br>
+                          StringRef /*SearchPath*/, StringRef /*RelativePath*/,<br>
+                          const Module * /*ImportedModule*/) override {<br>
+    IncludeInserter->AddInclude(FileNameRef, IsAngled, HashLocation,<br>
+                                FileNameRange.getEnd());<br>
+  }<br>
+<br>
+private:<br>
+  IncludeInserter *IncludeInserter;<br>
+};<br>
+<br>
+IncludeInserter::IncludeInserter(const SourceManager &SourceMgr,<br>
+                                 const LangOptions &LangOpts,<br>
+                                 IncludeSorter::IncludeStyle Style)<br>
+    : SourceMgr(SourceMgr), LangOpts(LangOpts), Style(Style) {}<br>
+<br>
+IncludeInserter::~IncludeInserter() {}<br>
+<br>
+std::unique_ptr<PPCallbacks> IncludeInserter::CreatePPCallbacks() {<br>
+  return llvm::make_unique<IncludeInserterCallback>(this);<br>
+}<br>
+<br>
+llvm::Optional<FixItHint><br>
+IncludeInserter::CreateIncludeInsertion(FileID FileID, StringRef Header,<br>
+                                        bool IsAngled) {<br>
+  // We assume the same Header will never be included both angled and not<br>
+  // angled.<br>
+  if (!InsertedHeaders.insert(std::make_pair(FileID, std::set<std::string>()))<br>
+           .second) {<br>
+    return llvm::None;<br>
+  }<br></blockquote><div><br></div><div>WAT? How did you come up with this??? This allows the include inserter to insert at most one header per file.</div><div>Fixed in r245500.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+  if (IncludeSorterByFile.find(FileID) == IncludeSorterByFile.end()) {<br>
+    return llvm::None;<br>
+  }<br>
+  return IncludeSorterByFile[FileID]->CreateIncludeInsertion(Header, IsAngled);<br>
+}<br>
+<br>
+void IncludeInserter::AddInclude(StringRef file_name, bool IsAngled,<br>
+                                 SourceLocation HashLocation,<br>
+                                 SourceLocation end_location) {<br>
+  FileID FileID = SourceMgr.getFileID(HashLocation);<br>
+  if (IncludeSorterByFile.find(FileID) == IncludeSorterByFile.end()) {<br>
+    IncludeSorterByFile.insert(std::make_pair(<br>
+        FileID, llvm::make_unique<IncludeSorter>(<br>
+                    &SourceMgr, &LangOpts, FileID,<br>
+                    SourceMgr.getFilename(HashLocation), Style)));<br>
+  }<br>
+  IncludeSorterByFile[FileID]->AddInclude(file_name, IsAngled, HashLocation,<br>
+                                          end_location);<br>
+}<br>
+<br>
+} // namespace tidy<br>
+} // namespace clang<br>
<br>
Added: clang-tools-extra/trunk/clang-tidy/IncludeInserter.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/IncludeInserter.h?rev=244586&view=auto" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/IncludeInserter.h?rev=244586&view=auto</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-tidy/IncludeInserter.h (added)<br>
+++ clang-tools-extra/trunk/clang-tidy/IncludeInserter.h Tue Aug 11 06:37:48 2015<br>
@@ -0,0 +1,75 @@<br>
+//===---------- IncludeInserter.h - clang-tidy ----------------------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H<br>
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H<br>
+<br>
+#include "IncludeSorter.h"<br>
+#include "clang/Basic/Diagnostic.h"<br>
+#include "clang/Basic/LangOptions.h"<br>
+#include "clang/Basic/SourceManager.h"<br>
+#include "clang/Lex/PPCallbacks.h"<br>
+#include <memory><br>
+#include <string><br>
+<br>
+namespace clang {<br>
+namespace tidy {<br>
+<br>
+// IncludeInserter can be used by ClangTidyChecks in the following fashion:<br>
+// class MyCheck : public ClangTidyCheck {<br>
+//  public:<br>
+//   void registerPPCallbacks(CompilerInstance& Compiler) override {<br>
+//     Inserter.reset(new IncludeInserter(&Compiler.getSourceManager(),<br>
+//                                        &Compiler.getLangOpts()));<br>
+//     Compiler.getPreprocessor().addPPCallbacks(<br>
+//         Inserter->CreatePPCallback());<br>
+//   }<br>
+//<br>
+//   void registerMatchers(ast_matchers::MatchFinder* Finder) override { ... }<br>
+//<br>
+//   void check(const ast_matchers::MatchFinder::MatchResult& Result) override {<br>
+//     ...<br>
+//     Inserter->CreateIncludeInsertion(<br>
+//         Result.SourceManager->getMainFileID(), "path/to/Header.h",<br>
+//         /*IsAngled=*/false);<br>
+//     ...<br>
+//   }<br>
+//<br>
+//  private:<br>
+//   std::unique_ptr<IncludeInserter> Inserter;<br>
+// };<br>
+class IncludeInserter {<br>
+public:<br>
+  IncludeInserter(const SourceManager &SourceMgr, const LangOptions &LangOpts,<br>
+                  IncludeSorter::IncludeStyle Style);<br>
+  ~IncludeInserter();<br>
+<br>
+  // Create PPCallbacks for registration with the compiler's preprocessor.<br>
+  std::unique_ptr<PPCallbacks> CreatePPCallbacks();<br>
+<br>
+  // Creates a Header inclusion directive fixit. Returns None on error or<br>
+  // if inclusion directive already exists.<br>
+  llvm::Optional<FixItHint><br>
+  CreateIncludeInsertion(FileID FileID, llvm::StringRef Header, bool IsAngled);<br>
+<br>
+private:<br>
+  void AddInclude(StringRef file_name, bool IsAngled,<br>
+                  SourceLocation hash_location, SourceLocation end_location);<br>
+<br>
+  llvm::DenseMap<FileID, std::unique_ptr<IncludeSorter>> IncludeSorterByFile;<br>
+  llvm::DenseMap<FileID, std::set<std::string>> InsertedHeaders;<br>
+  const SourceManager &SourceMgr;<br>
+  const LangOptions &LangOpts;<br>
+  const IncludeSorter::IncludeStyle Style;<br>
+  friend class IncludeInserterCallback;<br>
+};<br>
+<br>
+} // namespace tidy<br>
+} // namespace clang<br>
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H<br>
<br>
Added: clang-tools-extra/trunk/clang-tidy/IncludeSorter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/IncludeSorter.cpp?rev=244586&view=auto" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/IncludeSorter.cpp?rev=244586&view=auto</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-tidy/IncludeSorter.cpp (added)<br>
+++ clang-tools-extra/trunk/clang-tidy/IncludeSorter.cpp Tue Aug 11 06:37:48 2015<br>
@@ -0,0 +1,267 @@<br>
+//===---------- IncludeSorter.cpp - clang-tidy ----------------------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "IncludeSorter.h"<br>
+#include "clang/Lex/Lexer.h"<br>
+<br>
+namespace clang {<br>
+namespace tidy {<br>
+<br>
+namespace {<br>
+<br>
+StringRef RemoveFirstSuffix(StringRef Str, ArrayRef<const char *> Suffixes) {<br>
+  for (StringRef Suffix : Suffixes) {<br>
+    if (Str.endswith(Suffix)) {<br>
+      return Str.substr(0, Str.size() - Suffix.size());<br>
+    }<br>
+  }<br>
+  return Str;<br>
+}<br>
+<br>
+StringRef MakeCanonicalName(StringRef Str, IncludeSorter::IncludeStyle Style) {<br>
+  // The list of suffixes to remove from source file names to get the<br>
+  // "canonical" file names.<br>
+  // E.g. tools/sort_includes.cc and tools/sort_includes_test.cc<br>
+  // would both canonicalize to tools/sort_includes and tools/sort_includes.h<br>
+  // (once canonicalized) will match as being the main include file associated<br>
+  // with the source files.<br>
+  if (Style == IncludeSorter::IS_LLVM) {<br>
+    return RemoveFirstSuffix(<br>
+        RemoveFirstSuffix(Str, {".cc", ".cpp", ".c", ".h", ".hpp"}), {"Test"});<br>
+  }<br>
+  return RemoveFirstSuffix(<br>
+      RemoveFirstSuffix(Str, {".cc", ".cpp", ".c", ".h", ".hpp"}),<br>
+      {"_unittest", "_regtest", "_test"});<br>
+}<br>
+<br>
+// Scan to the end of the line and return the offset of the next line.<br>
+size_t FindNextLine(const char *Text) {<br>
+  size_t EOLIndex = std::strcspn(Text, "\n");<br>
+  return Text[EOLIndex] == '\0' ? EOLIndex : EOLIndex + 1;<br>
+}<br>
+<br>
+IncludeSorter::IncludeKinds<br>
+DetermineIncludeKind(StringRef CanonicalFile, StringRef IncludeFile,<br>
+                     bool IsAngled, IncludeSorter::IncludeStyle Style) {<br>
+  // Compute the two "canonical" forms of the include's filename sans extension.<br>
+  // The first form is the include's filename without ".h" or "-inl.h" at the<br>
+  // end. The second form is the first form with "/public/" in the file path<br>
+  // replaced by "/internal/".<br>
+  if (IsAngled) {<br>
+    // If the system include (<foo>) ends with ".h", then it is a normal C-style<br>
+    // include. Otherwise assume it is a C++-style extensionless include.<br>
+    return IncludeFile.endswith(".h") ? IncludeSorter::IK_CSystemInclude<br>
+                                      : IncludeSorter::IK_CXXSystemInclude;<br>
+  }<br>
+  StringRef CanonicalInclude = MakeCanonicalName(IncludeFile, Style);<br>
+  if (CanonicalFile.equals(CanonicalInclude)) {<br>
+    return IncludeSorter::IK_MainTUInclude;<br>
+  }<br>
+  if (Style == IncludeSorter::IS_Google) {<br>
+    std::pair<StringRef, StringRef> Parts = CanonicalInclude.split("/public/");<br>
+    std::string AltCanonicalInclude =<br>
+        Parts.first.str() + "/internal/" + Parts.second.str();<br>
+    std::string ProtoCanonicalInclude =<br>
+        Parts.first.str() + "/proto/" + Parts.second.str();<br>
+<br>
+    // Determine the kind of this inclusion.<br>
+    if (CanonicalFile.equals(AltCanonicalInclude) ||<br>
+        CanonicalFile.equals(ProtoCanonicalInclude)) {<br>
+      return IncludeSorter::IK_MainTUInclude;<br>
+    }<br>
+  }<br>
+  return IncludeSorter::IK_NonSystemInclude;<br>
+}<br>
+<br>
+} // namespace<br>
+<br>
+IncludeSorter::IncludeSorter(const SourceManager *SourceMgr,<br>
+                             const LangOptions *LangOpts, const FileID FileID,<br>
+                             StringRef FileName, IncludeStyle Style)<br>
+    : SourceMgr(SourceMgr), LangOpts(LangOpts), Style(Style),<br>
+      CurrentFileID(FileID), CanonicalFile(MakeCanonicalName(FileName, Style)) {<br>
+}<br>
+<br>
+void IncludeSorter::AddInclude(StringRef FileName, bool IsAngled,<br>
+                               SourceLocation HashLocation,<br>
+                               SourceLocation EndLocation) {<br>
+  int Offset = FindNextLine(SourceMgr->getCharacterData(EndLocation));<br>
+<br>
+  // Record the relevant location information for this inclusion directive.<br>
+  IncludeLocations[FileName].push_back(<br>
+      SourceRange(HashLocation, EndLocation.getLocWithOffset(Offset)));<br>
+  SourceLocations.push_back(IncludeLocations[FileName].back());<br>
+<br>
+  // Stop if this inclusion is a duplicate.<br>
+  if (IncludeLocations[FileName].size() > 1)<br>
+    return;<br>
+<br>
+  // Add the included file's name to the appropriate bucket.<br>
+  IncludeKinds Kind =<br>
+      DetermineIncludeKind(CanonicalFile, FileName, IsAngled, Style);<br>
+  if (Kind != IK_InvalidInclude)<br>
+    IncludeBucket[Kind].push_back(FileName.str());<br>
+}<br>
+<br>
+Optional<FixItHint> IncludeSorter::CreateIncludeInsertion(StringRef FileName,<br>
+                                                          bool IsAngled) {<br>
+  if (SourceLocations.empty()) {<br>
+    return None;<br>
+  }<br>
+  std::string IncludeStmt =<br>
+      IsAngled ? llvm::Twine("#include <" + FileName + ">\n").str()<br>
+               : llvm::Twine("#include \"" + FileName + "\"\n").str();<br>
+  auto IncludeKind =<br>
+      DetermineIncludeKind(CanonicalFile, FileName, IsAngled, Style);<br>
+  if (!IncludeBucket[IncludeKind].empty()) {<br>
+    for (const std::string &IncludeEntry : IncludeBucket[IncludeKind]) {<br>
+      if (FileName < IncludeEntry) {<br>
+        const auto &Location = IncludeLocations[IncludeEntry][0];<br>
+        return FixItHint::CreateInsertion(Location.getBegin(), IncludeStmt);<br>
+      } else if (FileName == IncludeEntry) {<br>
+        return llvm::None;<br>
+      }<br>
+    }<br>
+    // FileName comes after all include entries in bucket, insert it after<br>
+    // last.<br>
+    const std::string &LastInclude = IncludeBucket[IncludeKind].back();<br>
+    SourceRange LastIncludeLocation = IncludeLocations[LastInclude].back();<br>
+    return FixItHint::CreateInsertion(LastIncludeLocation.getEnd(),<br>
+                                      IncludeStmt);<br>
+  }<br>
+  IncludeKinds NonEmptyKind = IK_InvalidInclude;<br>
+  for (int i = IncludeKind - 1; i >= 0; --i) {<br>
+    if (!IncludeBucket[i].empty()) {<br>
+      NonEmptyKind = static_cast<IncludeKinds>(i);<br>
+      break;<br>
+    }<br>
+  }<br>
+  if (NonEmptyKind == IK_InvalidInclude) {<br>
+    return llvm::None;<br>
+  }<br>
+  const std::string &LastInclude = IncludeBucket[NonEmptyKind].back();<br>
+  SourceRange LastIncludeLocation = IncludeLocations[LastInclude].back();<br>
+  IncludeStmt.append("\n");<br>
+  return FixItHint::CreateInsertion(<br>
+      LastIncludeLocation.getEnd().getLocWithOffset(1), IncludeStmt);<br>
+}<br>
+<br>
+std::vector<FixItHint> IncludeSorter::GetEdits() {<br>
+  if (SourceLocations.empty())<br>
+    return {};<br>
+<br>
+  typedef std::map<int, std::pair<SourceRange, std::string>><br>
+      FileLineToSourceEditMap;<br>
+  FileLineToSourceEditMap Edits;<br>
+  auto SourceLocationIterator = SourceLocations.begin();<br>
+  auto SourceLocationIteratorEnd = SourceLocations.end();<br>
+<br>
+  // Compute the Edits that need to be done to each line to add, replace, or<br>
+  // delete inclusions.<br>
+  for (int IncludeKind = 0; IncludeKind < IK_InvalidInclude; ++IncludeKind) {<br>
+    std::sort(IncludeBucket[IncludeKind].begin(),<br>
+              IncludeBucket[IncludeKind].end(),<br>
+              [](const std::string &Left, const std::string &Right) {<br>
+                return llvm::StringRef(Left).compare_lower(Right) < 0;<br>
+              });<br>
+    for (const auto &IncludeEntry : IncludeBucket[IncludeKind]) {<br>
+      auto &Location = IncludeLocations[IncludeEntry];<br>
+      SourceRangeVector::iterator LocationIterator = Location.begin();<br>
+      SourceRangeVector::iterator LocationIteratorEnd = Location.end();<br>
+      SourceRange FirstLocation = *LocationIterator;<br>
+<br>
+      // If the first occurrence of a particular include is on the current<br>
+      // source line we are examining, leave it alone.<br>
+      if (FirstLocation == *SourceLocationIterator)<br>
+        ++LocationIterator;<br>
+<br>
+      // Add the deletion Edits for any (remaining) instances of this inclusion,<br>
+      // and remove their Locations from the source Locations to be processed.<br>
+      for (; LocationIterator != LocationIteratorEnd; ++LocationIterator) {<br>
+        int LineNumber =<br>
+            SourceMgr->getSpellingLineNumber(LocationIterator->getBegin());<br>
+        Edits[LineNumber] = std::make_pair(*LocationIterator, "");<br>
+        SourceLocationIteratorEnd =<br>
+            std::remove(SourceLocationIterator, SourceLocationIteratorEnd,<br>
+                        *LocationIterator);<br>
+      }<br>
+<br>
+      if (FirstLocation == *SourceLocationIterator) {<br>
+        // Do nothing except move to the next source Location (Location of an<br>
+        // inclusion in the original, unchanged source file).<br>
+        ++SourceLocationIterator;<br>
+        continue;<br>
+      }<br>
+<br>
+      // Add (or append to) the replacement text for this line in source file.<br>
+      int LineNumber =<br>
+          SourceMgr->getSpellingLineNumber(SourceLocationIterator->getBegin());<br>
+      if (Edits.find(LineNumber) == Edits.end()) {<br>
+        Edits[LineNumber].first =<br>
+            SourceRange(SourceLocationIterator->getBegin());<br>
+      }<br>
+      StringRef SourceText = Lexer::getSourceText(<br>
+          CharSourceRange::getCharRange(FirstLocation), *SourceMgr, *LangOpts);<br>
+      Edits[LineNumber].second.append(SourceText.data(), SourceText.size());<br>
+    }<br>
+<br>
+    // Clear the bucket.<br>
+    IncludeBucket[IncludeKind].clear();<br>
+  }<br>
+<br>
+  // Go through the single-line Edits and combine them into blocks of Edits.<br>
+  int CurrentEndLine = 0;<br>
+  SourceRange CurrentRange;<br>
+  std::string CurrentText;<br>
+  std::vector<FixItHint> Fixes;<br>
+  for (const auto &LineEdit : Edits) {<br>
+    const SourceRange &EditRange = LineEdit.second.first;<br>
+    // If the current edit is on the next line after the previous edit, add it<br>
+    // to the current block edit.<br>
+    if (LineEdit.first == CurrentEndLine + 1 &&<br>
+        CurrentRange.getBegin() != CurrentRange.getEnd()) {<br>
+      if (EditRange.getBegin() != EditRange.getEnd()) {<br>
+        ++CurrentEndLine;<br>
+        CurrentRange.setEnd(EditRange.getEnd());<br>
+      }<br>
+      CurrentText += LineEdit.second.second;<br>
+      // Otherwise report the current block edit and start a new block.<br>
+    } else {<br>
+      if (CurrentEndLine) {<br>
+        Fixes.push_back(CreateFixIt(CurrentRange, CurrentText));<br>
+      }<br>
+<br>
+      CurrentEndLine = LineEdit.first;<br>
+      CurrentRange = EditRange;<br>
+      CurrentText = LineEdit.second.second;<br>
+    }<br>
+  }<br>
+  // Finally, report the current block edit if there is one.<br>
+  if (CurrentEndLine) {<br>
+    Fixes.push_back(CreateFixIt(CurrentRange, CurrentText));<br>
+  }<br>
+<br>
+  // Reset the remaining internal state.<br>
+  SourceLocations.clear();<br>
+  IncludeLocations.clear();<br>
+  return Fixes;<br>
+}<br>
+<br>
+// Creates a fix-it for the given replacements.<br>
+// Takes the the source location that will be replaced, and the new text.<br>
+FixItHint IncludeSorter::CreateFixIt(SourceRange EditRange,<br>
+                                     const std::string &NewText) {<br>
+  FixItHint Fix;<br>
+  Fix.RemoveRange = CharSourceRange::getCharRange(EditRange);<br>
+  Fix.CodeToInsert = NewText;<br>
+  return Fix;<br>
+}<br>
+<br>
+} // namespace tidy<br>
+} // namespace clang<br>
<br>
Added: clang-tools-extra/trunk/clang-tidy/IncludeSorter.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/IncludeSorter.h?rev=244586&view=auto" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/IncludeSorter.h?rev=244586&view=auto</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-tidy/IncludeSorter.h (added)<br>
+++ clang-tools-extra/trunk/clang-tidy/IncludeSorter.h Tue Aug 11 06:37:48 2015<br>
@@ -0,0 +1,87 @@<br>
+//===------------ IncludeSorter.h - clang-tidy ----------------------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDESORTER_H<br>
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDESORTER_H<br>
+<br>
+#include "ClangTidy.h"<br>
+#include <string><br>
+<br>
+namespace clang {<br>
+namespace tidy {<br>
+<br>
+// Class used by IncludeSorterCallback and IncludeInserterCallback to record the<br>
+// names of the inclusions in a given source file being processed and generate<br>
+// the necessary commands to sort the inclusions according to the precedence<br>
+// enocded in IncludeKinds.<br>
+class IncludeSorter {<br>
+ public:<br>
+  // Supported include styles.<br>
+  enum IncludeStyle {<br>
+    IS_LLVM = 0,<br>
+    IS_Google = 1<br>
+  };<br>
+<br>
+  // The classifications of inclusions, in the order they should be sorted.<br>
+  enum IncludeKinds {<br>
+    IK_MainTUInclude = 0,     // e.g. #include "foo.h" when editing foo.cc<br>
+    IK_CSystemInclude = 1,    // e.g. #include <stdio.h><br>
+    IK_CXXSystemInclude = 2,  // e.g. #include <vector><br>
+    IK_NonSystemInclude = 3,  // e.g. #include "bar.h"<br>
+    IK_InvalidInclude = 4     // total number of valid IncludeKinds<br>
+  };<br>
+<br>
+  // IncludeSorter constructor; takes the FileID and name of the file to be<br>
+  // processed by the sorter.<br>
+  IncludeSorter(const SourceManager* SourceMgr,<br>
+                const LangOptions* LangOpts, const FileID FileID,<br>
+                StringRef FileName, IncludeStyle Style);<br>
+<br>
+  // Returns the SourceManager-specific file ID for the file being handled by<br>
+  // the sorter.<br>
+  const FileID current_FileID() const { return CurrentFileID; }<br>
+<br>
+  // Adds the given #include to the sorter.<br>
+  void AddInclude(StringRef FileName, bool IsAngled,<br>
+                  SourceLocation HashLocation, SourceLocation EndLocation);<br>
+<br>
+  // Returns the edits needed to sort the current set of includes and reset the<br>
+  // internal state (so that different blocks of includes are sorted separately<br>
+  // within the same file).<br>
+  std::vector<FixItHint> GetEdits();<br>
+<br>
+  // Creates a quoted inclusion directive in the right sort order. Returns None<br>
+  // on error or if header inclusion directive for header already exists.<br>
+  Optional<FixItHint> CreateIncludeInsertion(StringRef FileName,<br>
+                                             bool IsAngled);<br>
+<br>
+ private:<br>
+  typedef SmallVector<SourceRange, 1> SourceRangeVector;<br>
+<br>
+  // Creates a fix-it for the given replacements.<br>
+  // Takes the the source location that will be replaced, and the new text.<br>
+  FixItHint CreateFixIt(SourceRange EditRange, const std::string& NewText);<br>
+<br>
+  const SourceManager* SourceMgr;<br>
+  const LangOptions* LangOpts;<br>
+  const IncludeStyle Style;<br>
+  FileID CurrentFileID;<br>
+  // The file name stripped of common suffixes.<br>
+  StringRef CanonicalFile;<br>
+  // Locations of visited include directives.<br>
+  SourceRangeVector SourceLocations;<br>
+  // Mapping from file name to #include locations.<br>
+  llvm::StringMap<SourceRangeVector> IncludeLocations;<br>
+  // Includes sorted into buckets.<br>
+  SmallVector<std::string, 1> IncludeBucket[IK_InvalidInclude];<br>
+};<br>
+<br>
+}  // namespace tidy<br>
+}  // namespace clang<br>
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDESORTER_H<br>
<br>
Modified: clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt?rev=244586&r1=244585&r2=244586&view=diff" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt?rev=244586&r1=244585&r2=244586&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt (original)<br>
+++ clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt Tue Aug 11 06:37:48 2015<br>
@@ -9,6 +9,7 @@ include_directories(${CLANG_LINT_SOURCE_<br>
 add_extra_unittest(ClangTidyTests<br>
   ClangTidyDiagnosticConsumerTest.cpp<br>
   ClangTidyOptionsTest.cpp<br>
+  IncludeInserterTest.cpp<br>
   GoogleModuleTest.cpp<br>
   LLVMModuleTest.cpp<br>
   MiscModuleTest.cpp<br>
<br>
Modified: clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h?rev=244586&r1=244585&r2=244586&view=diff" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h?rev=244586&r1=244585&r2=244586&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h (original)<br>
+++ clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h Tue Aug 11 06:37:48 2015<br>
@@ -17,6 +17,7 @@<br>
 #include "clang/Frontend/FrontendActions.h"<br>
 #include "clang/Tooling/Refactoring.h"<br>
 #include "clang/Tooling/Tooling.h"<br>
+#include <map><br>
<br>
 namespace clang {<br>
 namespace tidy {<br>
@@ -46,7 +47,8 @@ std::string<br>
 runCheckOnCode(StringRef Code, std::vector<ClangTidyError> *Errors = nullptr,<br>
                const Twine &Filename = "input.cc",<br>
                ArrayRef<std::string> ExtraArgs = None,<br>
-               const ClangTidyOptions &ExtraOptions = ClangTidyOptions()) {<br>
+               const ClangTidyOptions &ExtraOptions = ClangTidyOptions(),<br>
+               std::map<StringRef, StringRef> PathsToContent = {}) {<br>
   ClangTidyOptions Options = ExtraOptions;<br>
   Options.Checks = "*";<br>
   ClangTidyContext Context(llvm::make_unique<DefaultOptionsProvider>(<br>
@@ -60,6 +62,7 @@ runCheckOnCode(StringRef Code, std::vect<br>
   std::vector<std::string> ArgCXX11(1, "clang-tidy");<br>
   ArgCXX11.push_back("-fsyntax-only");<br>
   ArgCXX11.push_back("-std=c++11");<br>
+  ArgCXX11.push_back("-Iinclude");<br>
   ArgCXX11.insert(ArgCXX11.end(), ExtraArgs.begin(), ExtraArgs.end());<br>
   ArgCXX11.push_back(Filename.str());<br>
   llvm::IntrusiveRefCntPtr<FileManager> Files(<br>
@@ -67,6 +70,10 @@ runCheckOnCode(StringRef Code, std::vect<br>
   tooling::ToolInvocation Invocation(<br>
       ArgCXX11, new TestClangTidyAction(Check, Finder, Context), Files.get());<br>
   Invocation.mapVirtualFile(Filename.str(), Code);<br>
+  for (const auto & FileContent : PathsToContent) {<br>
+    Invocation.mapVirtualFile(Twine("include/" + FileContent.first).str(),<br>
+                              FileContent.second);<br>
+  }<br>
   Invocation.setDiagnosticConsumer(&DiagConsumer);<br>
   if (!Invocation.run())<br>
     return "";<br>
<br>
Added: clang-tools-extra/trunk/unittests/clang-tidy/IncludeInserterTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/IncludeInserterTest.cpp?rev=244586&view=auto" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/IncludeInserterTest.cpp?rev=244586&view=auto</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/unittests/clang-tidy/IncludeInserterTest.cpp (added)<br>
+++ clang-tools-extra/trunk/unittests/clang-tidy/IncludeInserterTest.cpp Tue Aug 11 06:37:48 2015<br>
@@ -0,0 +1,407 @@<br>
+//===---- IncludeInserterTest.cpp - clang-tidy ----------------------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "../clang-tidy/IncludeInserter.h"<br>
+#include "clang/Lex/Preprocessor.h"<br>
+#include "clang/Frontend/CompilerInstance.h"<br>
+#include "ClangTidyTest.h"<br>
+#include "gtest/gtest.h"<br>
+<br>
+namespace clang {<br>
+namespace tidy {<br>
+namespace {<br>
+<br>
+class IncludeInserterCheckBase : public ClangTidyCheck {<br>
+public:<br>
+  using ClangTidyCheck::ClangTidyCheck;<br>
+  void registerPPCallbacks(CompilerInstance &Compiler) override {<br>
+    Inserter.reset(new IncludeInserter(Compiler.getSourceManager(),<br>
+                                       Compiler.getLangOpts(),<br>
+                                       IncludeSorter::IS_Google));<br>
+    Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());<br>
+  }<br>
+<br>
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override {<br>
+    Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this);<br>
+  }<br>
+<br>
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override {<br>
+    auto Fixit =<br>
+        Inserter->CreateIncludeInsertion(Result.SourceManager->getMainFileID(),<br>
+                                         HeaderToInclude(), IsAngledInclude());<br>
+    if (Fixit) {<br>
+      diag(Result.Nodes.getStmtAs<DeclStmt>("stmt")->getLocStart(), "foo, bar")<br>
+          << *Fixit;<br>
+    }<br>
+    // Second include should yield no Fixit.<br>
+    Fixit =<br>
+        Inserter->CreateIncludeInsertion(Result.SourceManager->getMainFileID(),<br>
+                                         HeaderToInclude(), IsAngledInclude());<br>
+    EXPECT_FALSE(Fixit);<br>
+  }<br>
+<br>
+  virtual StringRef HeaderToInclude() const = 0;<br>
+  virtual bool IsAngledInclude() const = 0;<br>
+<br>
+  std::unique_ptr<IncludeInserter> Inserter;<br>
+};<br>
+<br>
+class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {<br>
+public:<br>
+  using IncludeInserterCheckBase::IncludeInserterCheckBase;<br>
+  StringRef HeaderToInclude() const override { return "path/to/header.h"; }<br>
+  bool IsAngledInclude() const override { return false; }<br>
+};<br>
+<br>
+class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {<br>
+public:<br>
+  using IncludeInserterCheckBase::IncludeInserterCheckBase;<br>
+  StringRef HeaderToInclude() const override { return "set"; }<br>
+  bool IsAngledInclude() const override { return true; }<br>
+};<br>
+<br>
+template <typename Check><br>
+std::string runCheckOnCode(StringRef Code, StringRef Filename,<br>
+                           size_t NumWarningsExpected) {<br>
+  std::vector<ClangTidyError> Errors;<br>
+  return test::runCheckOnCode<Check>(Code, &Errors, Filename, None,<br>
+                                     ClangTidyOptions(),<br>
+                                     {// Main file include<br>
+                                      {"devtools/cymbal/clang_tidy/tests/"<br>
+                                       "insert_includes_test_header.h",<br>
+                                       "\n"},<br>
+                                      // Non system headers<br>
+                                      {"path/to/a/header.h", "\n"},<br>
+                                      {"path/to/z/header.h", "\n"},<br>
+                                      {"path/to/header.h", "\n"},<br>
+                                      // Fake system headers.<br>
+                                      {"stdlib.h", "\n"},<br>
+                                      {"unistd.h", "\n"},<br>
+                                      {"list", "\n"},<br>
+                                      {"map", "\n"},<br>
+                                      {"set", "\n"},<br>
+                                      {"vector", "\n"}});<br>
+  EXPECT_EQ(NumWarningsExpected, Errors.size());<br></blockquote><div><br></div><div>I am curious, how often has this fired during development? Being after the return and all ...</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/a/header.h"<br>
+#include "path/to/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_input2.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/z/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/header.h"<br>
+#include "path/to/z/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_input2.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/a/header.h"<br>
+#include "path/to/z/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/a/header.h"<br>
+#include "path/to/header.h"<br>
+#include "path/to/z/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_input2.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/a/header.h"<br>
+#include "path/to/header.h"<br>
+#include "path/to/z/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  EXPECT_EQ(PreCode, runCheckOnCode<NonSystemHeaderInserterCheck>(<br>
+                         PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                  "insert_includes_test_input2.cc",<br>
+                         0));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_header.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include "path/to/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_header.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <list><br>
+#include <map><br>
+#include <set><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_header.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <vector><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <set><br>
+#include <vector><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_header.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <map><br>
+#include <vector><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <map><br>
+#include <set><br>
+#include <vector><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_header.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <set><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_header.cc",<br>
+                          1));<br>
+}<br>
+<br>
+TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {<br>
+  const char *PreCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <stdlib.h><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+  const char *PostCode = R"(<br>
+#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"<br>
+<br>
+#include <stdlib.h><br>
+<br>
+#include <set><br>
+<br>
+#include "path/to/a/header.h"<br>
+<br>
+void foo() {<br>
+  int a = 0;<br>
+})";<br>
+<br>
+  EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(<br>
+                          PreCode, "devtools/cymbal/clang_tidy/tests/"<br>
+                                   "insert_includes_test_header.cc",<br>
+                          1));<br>
+}<br>
+<br>
+} // namespace<br>
+} // namespace tidy<br>
+} // namespace clang<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" class="cremed">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank" class="cremed">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>