angelgarcia updated this revision to Diff 32143. angelgarcia added a comment.
Update tests. http://reviews.llvm.org/D12017 Files: clang-tidy/IncludeInserter.cpp clang-tidy/IncludeSorter.cpp clang-tidy/IncludeSorter.h unittests/clang-tidy/IncludeInserterTest.cpp
Index: unittests/clang-tidy/IncludeInserterTest.cpp =================================================================== --- unittests/clang-tidy/IncludeInserterTest.cpp +++ unittests/clang-tidy/IncludeInserterTest.cpp @@ -59,6 +59,13 @@ bool IsAngledInclude() const override { return false; } }; +class CSystemIncludeInserterCheck : public IncludeInserterCheckBase { +public: + using IncludeInserterCheckBase::IncludeInserterCheckBase; + StringRef HeaderToInclude() const override { return "stdlib.h"; } + bool IsAngledInclude() const override { return true; } +}; + class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase { public: using IncludeInserterCheckBase::IncludeInserterCheckBase; @@ -402,6 +409,72 @@ 1)); } +TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) { + const char *PreCode = R"( +#include "path/to/a/header.h" + +void foo() { + int a = 0; +})"; + const char *PostCode = R"( +#include <set> + +#include "path/to/a/header.h" + +void foo() { + int a = 0; +})"; + + EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>( + PreCode, "devtools/cymbal/clang_tidy/tests/" + "insert_includes_test_header.cc", + 1)); +} + +TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) { + const char *PreCode = R"( +#include <set> + +#include "path/to/a/header.h" + +void foo() { + int a = 0; +})"; + const char *PostCode = R"( +#include <stdlib.h> + +#include <set> + +#include "path/to/a/header.h" + +void foo() { + int a = 0; +})"; + + EXPECT_EQ(PostCode, runCheckOnCode<CSystemIncludeInserterCheck>( + PreCode, "devtools/cymbal/clang_tidy/tests/" + "insert_includes_test_header.cc", + 1)); +} + +TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) { + const char *PreCode = R"( +void foo() { + int a = 0; +})"; + const char *PostCode = R"(#include <set> + + +void foo() { + int a = 0; +})"; + + EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>( + PreCode, "devtools/cymbal/clang_tidy/tests/" + "insert_includes_test_header.cc", + 1)); +} + } // namespace } // namespace tidy } // namespace clang Index: clang-tidy/IncludeSorter.h =================================================================== --- clang-tidy/IncludeSorter.h +++ clang-tidy/IncludeSorter.h @@ -21,27 +21,23 @@ // the necessary commands to sort the inclusions according to the precedence // enocded in IncludeKinds. class IncludeSorter { - public: +public: // Supported include styles. - enum IncludeStyle { - IS_LLVM = 0, - IS_Google = 1 - }; + enum IncludeStyle { IS_LLVM = 0, IS_Google = 1 }; // The classifications of inclusions, in the order they should be sorted. enum IncludeKinds { - IK_MainTUInclude = 0, // e.g. #include "foo.h" when editing foo.cc - IK_CSystemInclude = 1, // e.g. #include <stdio.h> - IK_CXXSystemInclude = 2, // e.g. #include <vector> - IK_NonSystemInclude = 3, // e.g. #include "bar.h" - IK_InvalidInclude = 4 // total number of valid IncludeKinds + IK_MainTUInclude = 0, // e.g. #include "foo.h" when editing foo.cc + IK_CSystemInclude = 1, // e.g. #include <stdio.h> + IK_CXXSystemInclude = 2, // e.g. #include <vector> + IK_NonSystemInclude = 3, // e.g. #include "bar.h" + IK_InvalidInclude = 4 // total number of valid IncludeKinds }; // IncludeSorter constructor; takes the FileID and name of the file to be // processed by the sorter. - IncludeSorter(const SourceManager* SourceMgr, - const LangOptions* LangOpts, const FileID FileID, - StringRef FileName, IncludeStyle Style); + IncludeSorter(const SourceManager *SourceMgr, const LangOptions *LangOpts, + const FileID FileID, StringRef FileName, IncludeStyle Style); // Returns the SourceManager-specific file ID for the file being handled by // the sorter. @@ -58,18 +54,17 @@ // Creates a quoted inclusion directive in the right sort order. Returns None // on error or if header inclusion directive for header already exists. - Optional<FixItHint> CreateIncludeInsertion(StringRef FileName, - bool IsAngled); + Optional<FixItHint> CreateIncludeInsertion(StringRef FileName, bool IsAngled); - private: +private: typedef SmallVector<SourceRange, 1> SourceRangeVector; // Creates a fix-it for the given replacements. // Takes the the source location that will be replaced, and the new text. - FixItHint CreateFixIt(SourceRange EditRange, const std::string& NewText); + FixItHint CreateFixIt(SourceRange EditRange, const std::string &NewText); - const SourceManager* SourceMgr; - const LangOptions* LangOpts; + const SourceManager *SourceMgr; + const LangOptions *LangOpts; const IncludeStyle Style; FileID CurrentFileID; // The file name stripped of common suffixes. @@ -82,6 +77,6 @@ SmallVector<std::string, 1> IncludeBucket[IK_InvalidInclude]; }; -} // namespace tidy -} // namespace clang +} // namespace tidy +} // namespace clang #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDESORTER_H Index: clang-tidy/IncludeSorter.cpp =================================================================== --- clang-tidy/IncludeSorter.cpp +++ clang-tidy/IncludeSorter.cpp @@ -111,14 +111,19 @@ Optional<FixItHint> IncludeSorter::CreateIncludeInsertion(StringRef FileName, bool IsAngled) { - if (SourceLocations.empty()) { - return None; - } std::string IncludeStmt = IsAngled ? llvm::Twine("#include <" + FileName + ">\n").str() : llvm::Twine("#include \"" + FileName + "\"\n").str(); + if (SourceLocations.empty()) { + // If there are no includes in this file, add it in the first line. + IncludeStmt.append("\n"); + return FixItHint::CreateInsertion( + SourceMgr->getLocForStartOfFile(CurrentFileID), IncludeStmt); + } + auto IncludeKind = DetermineIncludeKind(CanonicalFile, FileName, IsAngled, Style); + if (!IncludeBucket[IncludeKind].empty()) { for (const std::string &IncludeEntry : IncludeBucket[IncludeKind]) { if (FileName < IncludeEntry) { @@ -136,20 +141,31 @@ IncludeStmt); } IncludeKinds NonEmptyKind = IK_InvalidInclude; - for (int i = IncludeKind - 1; i >= 0; --i) { + for (int i = IK_InvalidInclude - 1; i >= 0; --i) { if (!IncludeBucket[i].empty()) { NonEmptyKind = static_cast<IncludeKinds>(i); - break; + if (NonEmptyKind < IncludeKind) + break; } } if (NonEmptyKind == IK_InvalidInclude) { return llvm::None; } - const std::string &LastInclude = IncludeBucket[NonEmptyKind].back(); - SourceRange LastIncludeLocation = IncludeLocations[LastInclude].back(); + + if (NonEmptyKind < IncludeKind) { + // Create a block after. + const std::string &LastInclude = IncludeBucket[NonEmptyKind].back(); + SourceRange LastIncludeLocation = IncludeLocations[LastInclude].back(); + IncludeStmt = '\n' + IncludeStmt; + return FixItHint::CreateInsertion(LastIncludeLocation.getEnd(), + IncludeStmt); + } + // Create a block before. + const std::string &FirstInclude = IncludeBucket[NonEmptyKind][0]; + SourceRange FirstIncludeLocation = IncludeLocations[FirstInclude].back(); IncludeStmt.append("\n"); - return FixItHint::CreateInsertion( - LastIncludeLocation.getEnd().getLocWithOffset(1), IncludeStmt); + return FixItHint::CreateInsertion(FirstIncludeLocation.getBegin(), + IncludeStmt); } std::vector<FixItHint> IncludeSorter::GetEdits() { Index: clang-tidy/IncludeInserter.cpp =================================================================== --- clang-tidy/IncludeInserter.cpp +++ clang-tidy/IncludeInserter.cpp @@ -26,7 +26,7 @@ StringRef /*SearchPath*/, StringRef /*RelativePath*/, const Module * /*ImportedModule*/) override { Inserter->AddInclude(FileNameRef, IsAngled, HashLocation, - FileNameRange.getEnd()); + FileNameRange.getEnd()); } private: @@ -54,7 +54,14 @@ return llvm::None; } if (IncludeSorterByFile.find(FileID) == IncludeSorterByFile.end()) { - return llvm::None; + // This may happen if there have been no preprocessor directives in this + // file. + IncludeSorterByFile.insert(std::make_pair( + FileID, + llvm::make_unique<IncludeSorter>( + &SourceMgr, &LangOpts, FileID, + SourceMgr.getFilename(SourceMgr.getLocForStartOfFile(FileID)), + Style))); } return IncludeSorterByFile[FileID]->CreateIncludeInsertion(Header, IsAngled); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits