diff options
author | Eric Liu <ioeric@google.com> | 2018-05-14 20:17:53 +0000 |
---|---|---|
committer | Eric Liu <ioeric@google.com> | 2018-05-14 20:17:53 +0000 |
commit | 7129e63bcce96529291b3ffbe596f7f8588bdcc4 (patch) | |
tree | 30553e4cf06fa6ddb8060b15f7d5d83f5163f5d2 /clang/unittests/Tooling/HeaderIncludesTest.cpp | |
parent | d699da427a4c49bc01c9ee3d031c7885383568f9 (diff) | |
download | bcm5719-llvm-7129e63bcce96529291b3ffbe596f7f8588bdcc4.tar.gz bcm5719-llvm-7129e63bcce96529291b3ffbe596f7f8588bdcc4.zip |
[Tooling] Pull #include manipulation code from clangFormat into libToolingCore.
Summary: Also pull #include related style out of FormatStyle as tooling::IncludeStyle.
Reviewers: ilya-biryukov
Reviewed By: ilya-biryukov
Subscribers: klimek, mgorny, cfe-commits, djasper
Differential Revision: https://reviews.llvm.org/D46496
llvm-svn: 332287
Diffstat (limited to 'clang/unittests/Tooling/HeaderIncludesTest.cpp')
-rw-r--r-- | clang/unittests/Tooling/HeaderIncludesTest.cpp | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/clang/unittests/Tooling/HeaderIncludesTest.cpp b/clang/unittests/Tooling/HeaderIncludesTest.cpp new file mode 100644 index 00000000000..4407221f8ad --- /dev/null +++ b/clang/unittests/Tooling/HeaderIncludesTest.cpp @@ -0,0 +1,527 @@ +//===- unittest/Tooling/CleanupTest.cpp - Include insertion/deletion tests ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Core/HeaderIncludes.h" +#include "../Tooling/ReplacementTest.h" +#include "../Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Tooling/Core/Replacement.h" + +#include "gtest/gtest.h" + +using clang::tooling::ReplacementTest; +using clang::tooling::toReplacements; + +namespace clang { +namespace tooling { +namespace { + +class HeaderIncludesTest : public ::testing::Test { +protected: + std::string insert(llvm::StringRef Code, llvm::StringRef Header) { + HeaderIncludes Includes(FileName, Code, Style); + assert(Header.startswith("\"") || Header.startswith("<")); + auto R = Includes.insert(Header.trim("\"<>"), Header.startswith("<")); + if (!R) + return Code; + auto Result = applyAllReplacements(Code, Replacements(*R)); + EXPECT_TRUE(static_cast<bool>(Result)); + return *Result; + } + + std::string remove(llvm::StringRef Code, llvm::StringRef Header) { + HeaderIncludes Includes(FileName, Code, Style); + assert(Header.startswith("\"") || Header.startswith("<")); + auto Replaces = Includes.remove(Header.trim("\"<>"), Header.startswith("<")); + auto Result = applyAllReplacements(Code, Replaces); + EXPECT_TRUE(static_cast<bool>(Result)); + return *Result; + } + + const std::string FileName = "fix.cpp"; + IncludeStyle Style = format::getLLVMStyle().IncludeStyle; +}; + +TEST_F(HeaderIncludesTest, NoExistingIncludeWithoutDefine) { + std::string Code = "int main() {}"; + std::string Expected = "#include \"a.h\"\n" + "int main() {}"; + EXPECT_EQ(Expected, insert(Code, "\"a.h\"")); +} + +TEST_F(HeaderIncludesTest, NoExistingIncludeWithDefine) { + std::string Code = "#ifndef A_H\n" + "#define A_H\n" + "class A {};\n" + "#define MMM 123\n" + "#endif"; + std::string Expected = "#ifndef A_H\n" + "#define A_H\n" + "#include \"b.h\"\n" + "class A {};\n" + "#define MMM 123\n" + "#endif"; + + EXPECT_EQ(Expected, insert(Code, "\"b.h\"")); +} + +TEST_F(HeaderIncludesTest, InsertBeforeCategoryWithLowerPriority) { + std::string Code = "#ifndef A_H\n" + "#define A_H\n" + "\n" + "\n" + "\n" + "#include <vector>\n" + "class A {};\n" + "#define MMM 123\n" + "#endif"; + std::string Expected = "#ifndef A_H\n" + "#define A_H\n" + "\n" + "\n" + "\n" + "#include \"a.h\"\n" + "#include <vector>\n" + "class A {};\n" + "#define MMM 123\n" + "#endif"; + + EXPECT_EQ(Expected, insert(Code, "\"a.h\"")); +} + +TEST_F(HeaderIncludesTest, InsertAfterMainHeader) { + std::string Code = "#include \"fix.h\"\n" + "\n" + "int main() {}"; + std::string Expected = "#include \"fix.h\"\n" + "#include <a>\n" + "\n" + "int main() {}"; + Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp) + .IncludeStyle; + EXPECT_EQ(Expected, insert(Code, "<a>")); +} + +TEST_F(HeaderIncludesTest, InsertBeforeSystemHeaderLLVM) { + std::string Code = "#include <memory>\n" + "\n" + "int main() {}"; + std::string Expected = "#include \"z.h\"\n" + "#include <memory>\n" + "\n" + "int main() {}"; + EXPECT_EQ(Expected, insert(Code, "\"z.h\"")); +} + +TEST_F(HeaderIncludesTest, InsertAfterSystemHeaderGoogle) { + std::string Code = "#include <memory>\n" + "\n" + "int main() {}"; + std::string Expected = "#include <memory>\n" + "#include \"z.h\"\n" + "\n" + "int main() {}"; + Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp) + .IncludeStyle; + EXPECT_EQ(Expected, insert(Code, "\"z.h\"")); +} + +TEST_F(HeaderIncludesTest, InsertOneIncludeLLVMStyle) { + std::string Code = "#include \"x/fix.h\"\n" + "#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"clang/Format/Format.h\"\n" + "#include <memory>\n"; + std::string Expected = "#include \"x/fix.h\"\n" + "#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"clang/Format/Format.h\"\n" + "#include \"llvm/x/y.h\"\n" + "#include <memory>\n"; + EXPECT_EQ(Expected, insert(Code, "\"llvm/x/y.h\"")); +} + +TEST_F(HeaderIncludesTest, InsertIntoBlockSorted) { + std::string Code = "#include \"x/fix.h\"\n" + "#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include <memory>\n"; + std::string Expected = "#include \"x/fix.h\"\n" + "#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n" + "#include <memory>\n"; + EXPECT_EQ(Expected, insert(Code, "\"b.h\"")); +} + +TEST_F(HeaderIncludesTest, InsertIntoFirstBlockOfSameKind) { + std::string Code = "#include \"x/fix.h\"\n" + "#include \"c.h\"\n" + "#include \"e.h\"\n" + "#include \"f.h\"\n" + "#include <memory>\n" + "#include <vector>\n" + "#include \"m.h\"\n" + "#include \"n.h\"\n"; + std::string Expected = "#include \"x/fix.h\"\n" + "#include \"c.h\"\n" + "#include \"d.h\"\n" + "#include \"e.h\"\n" + "#include \"f.h\"\n" + "#include <memory>\n" + "#include <vector>\n" + "#include \"m.h\"\n" + "#include \"n.h\"\n"; + EXPECT_EQ(Expected, insert(Code, "\"d.h\"")); +} + +TEST_F(HeaderIncludesTest, InsertIntoSystemBlockSorted) { + std::string Code = "#include \"x/fix.h\"\n" + "#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include <a>\n" + "#include <z>\n"; + std::string Expected = "#include \"x/fix.h\"\n" + "#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include <a>\n" + "#include <vector>\n" + "#include <z>\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, InsertNewSystemIncludeGoogleStyle) { + std::string Code = "#include \"x/fix.h\"\n" + "\n" + "#include \"y/a.h\"\n" + "#include \"z/b.h\"\n"; + // FIXME: inserting after the empty line following the main header might be + // preferred. + std::string Expected = "#include \"x/fix.h\"\n" + "#include <vector>\n" + "\n" + "#include \"y/a.h\"\n" + "#include \"z/b.h\"\n"; + Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp) + .IncludeStyle; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, NotConfusedByDefine) { + std::string Code = "void f() {}\n" + "#define A \\\n" + " int i;"; + std::string Expected = "#include <vector>\n" + "void f() {}\n" + "#define A \\\n" + " int i;"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, SkippedTopComment) { + std::string Code = "// comment\n" + "\n" + " // comment\n"; + std::string Expected = "// comment\n" + "\n" + " // comment\n" + "#include <vector>\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, SkippedMixedComments) { + std::string Code = "// comment\n" + "// comment \\\n" + " comment continued\n" + "/*\n" + "* comment\n" + "*/\n"; + std::string Expected = "// comment\n" + "// comment \\\n" + " comment continued\n" + "/*\n" + "* comment\n" + "*/\n" + "#include <vector>\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, MultipleBlockCommentsInOneLine) { + std::string Code = "/*\n" + "* comment\n" + "*/ /* comment\n" + "*/\n" + "\n\n" + "/* c1 */ /*c2 */\n"; + std::string Expected = "/*\n" + "* comment\n" + "*/ /* comment\n" + "*/\n" + "\n\n" + "/* c1 */ /*c2 */\n" + "#include <vector>\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, CodeAfterComments) { + std::string Code = "/*\n" + "* comment\n" + "*/ /* comment\n" + "*/\n" + "\n\n" + "/* c1 */ /*c2 */\n" + "\n" + "int x;\n"; + std::string Expected = "/*\n" + "* comment\n" + "*/ /* comment\n" + "*/\n" + "\n\n" + "/* c1 */ /*c2 */\n" + "\n" + "#include <vector>\n" + "int x;\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, FakeHeaderGuardIfDef) { + std::string Code = "// comment \n" + "#ifdef X\n" + "#define X\n"; + std::string Expected = "// comment \n" + "#include <vector>\n" + "#ifdef X\n" + "#define X\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, RealHeaderGuardAfterComments) { + std::string Code = "// comment \n" + "#ifndef X\n" + "#define X\n" + "int x;\n" + "#define Y 1\n"; + std::string Expected = "// comment \n" + "#ifndef X\n" + "#define X\n" + "#include <vector>\n" + "int x;\n" + "#define Y 1\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, IfNDefWithNoDefine) { + std::string Code = "// comment \n" + "#ifndef X\n" + "int x;\n" + "#define Y 1\n"; + std::string Expected = "// comment \n" + "#include <vector>\n" + "#ifndef X\n" + "int x;\n" + "#define Y 1\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, FakeHeaderGuard) { + std::string Code = "// comment \n" + "#ifndef X\n" + "#define 1\n"; + std::string Expected = "// comment \n" + "#include <vector>\n" + "#ifndef X\n" + "#define 1\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, HeaderGuardWithComment) { + std::string Code = "// comment \n" + "#ifndef X // comment\n" + "// comment\n" + "/* comment\n" + "*/\n" + "/* comment */ #define X\n" + "int x;\n" + "#define Y 1\n"; + std::string Expected = "// comment \n" + "#ifndef X // comment\n" + "// comment\n" + "/* comment\n" + "*/\n" + "/* comment */ #define X\n" + "#include <vector>\n" + "int x;\n" + "#define Y 1\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, EmptyCode) { + std::string Code = ""; + std::string Expected = "#include <vector>\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, NoNewLineAtTheEndOfCode) { + std::string Code = "#include <map>"; + std::string Expected = "#include <map>\n#include <vector>\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, SkipExistingHeaders) { + std::string Code = "#include \"a.h\"\n" + "#include <vector>\n"; + std::string Expected = "#include \"a.h\"\n" + "#include <vector>\n"; + EXPECT_EQ(Expected, insert(Code, "<vector>")); + EXPECT_EQ(Expected, insert(Code, "\"a.h\"")); +} + +TEST_F(HeaderIncludesTest, AddIncludesWithDifferentForms) { + std::string Code = "#include <vector>\n"; + // FIXME: this might not be the best behavior. + std::string Expected = "#include \"vector\"\n" + "#include <vector>\n"; + EXPECT_EQ(Expected, insert(Code, "\"vector\"")); +} + +TEST_F(HeaderIncludesTest, NoInsertionAfterCode) { + std::string Code = "#include \"a.h\"\n" + "void f() {}\n" + "#include \"b.h\"\n"; + std::string Expected = "#include \"a.h\"\n" + "#include \"c.h\"\n" + "void f() {}\n" + "#include \"b.h\"\n"; + EXPECT_EQ(Expected, insert(Code, "\"c.h\"")); +} + +TEST_F(HeaderIncludesTest, NoInsertionInStringLiteral) { + std::string Code = "#include \"a.h\"\n" + "const char[] = R\"(\n" + "#include \"b.h\"\n" + ")\";\n"; + std::string Expected = "#include \"a.h\"\n" + "#include \"c.h\"\n" + "const char[] = R\"(\n" + "#include \"b.h\"\n" + ")\";\n"; + EXPECT_EQ(Expected, insert(Code, "\"c.h\"")); +} + +TEST_F(HeaderIncludesTest, NoInsertionAfterOtherDirective) { + std::string Code = "#include \"a.h\"\n" + "#ifdef X\n" + "#include \"b.h\"\n" + "#endif\n"; + std::string Expected = "#include \"a.h\"\n" + "#include \"c.h\"\n" + "#ifdef X\n" + "#include \"b.h\"\n" + "#endif\n"; + EXPECT_EQ(Expected, insert(Code, "\"c.h\"")); +} + +TEST_F(HeaderIncludesTest, CanInsertAfterLongSystemInclude) { + std::string Code = "#include \"a.h\"\n" + "// comment\n\n" + "#include <a/b/c/d/e.h>\n"; + std::string Expected = "#include \"a.h\"\n" + "// comment\n\n" + "#include <a/b/c/d/e.h>\n" + "#include <x.h>\n"; + EXPECT_EQ(Expected, insert(Code, "<x.h>")); +} + +TEST_F(HeaderIncludesTest, CanInsertAfterComment) { + std::string Code = "#include \"a.h\"\n" + "// Comment\n" + "\n" + "/* Comment */\n" + "// Comment\n" + "\n" + "#include \"b.h\"\n"; + std::string Expected = "#include \"a.h\"\n" + "// Comment\n" + "\n" + "/* Comment */\n" + "// Comment\n" + "\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n"; + EXPECT_EQ(Expected, insert(Code, "\"c.h\"")); +} + +TEST_F(HeaderIncludesTest, LongCommentsInTheBeginningOfFile) { + std::string Code = "// Loooooooooooooooooooooooooong comment\n" + "// Loooooooooooooooooooooooooong comment\n" + "// Loooooooooooooooooooooooooong comment\n" + "#include <string>\n" + "#include <vector>\n" + "\n" + "#include \"a.h\"\n" + "#include \"b.h\"\n"; + std::string Expected = "// Loooooooooooooooooooooooooong comment\n" + "// Loooooooooooooooooooooooooong comment\n" + "// Loooooooooooooooooooooooooong comment\n" + "#include <string>\n" + "#include <vector>\n" + "\n" + "#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"third.h\"\n"; + Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp) + .IncludeStyle; + EXPECT_EQ(Expected, insert(Code, "\"third.h\"")); +} + +TEST_F(HeaderIncludesTest, SimpleDeleteInclude) { + std::string Code = "#include \"abc.h\"\n" + "#include \"xyz.h\" // comment\n" + "int x;\n"; + std::string Expected = "#include \"abc.h\"\n" + "int x;\n"; + EXPECT_EQ(Expected, remove(Code, "\"xyz.h\"")); +} + +TEST_F(HeaderIncludesTest, DeleteQuotedOnly) { + std::string Code = "#include \"abc.h\"\n" + "#include <abc.h>\n" + "int x;\n"; + std::string Expected = "#include <abc.h>\n" + "int x;\n"; + EXPECT_EQ(Expected, remove(Code, "\"abc.h\"")); +} + +TEST_F(HeaderIncludesTest, DeleteAllCode) { + std::string Code = "#include \"xyz.h\"\n"; + std::string Expected = ""; + EXPECT_EQ(Expected, remove(Code, "\"xyz.h\"")); +} + +TEST_F(HeaderIncludesTest, DeleteOnlyIncludesWithSameQuote) { + std::string Code = "#include \"xyz.h\"\n" + "#include \"xyz\"\n" + "#include <xyz.h>\n"; + std::string Expected = "#include \"xyz.h\"\n" + "#include \"xyz\"\n"; + EXPECT_EQ(Expected, remove(Code, "<xyz.h>")); +} + +TEST_F(HeaderIncludesTest, CanDeleteAfterCode) { + std::string Code = "#include \"a.h\"\n" + "void f() {}\n" + "#include \"b.h\"\n"; + std::string Expected = "#include \"a.h\"\n" + "void f() {}\n"; + EXPECT_EQ(Expected, remove(Code, "\"b.h\"")); +} + +} // namespace +} // namespace tooling +} // namespace clang |