Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -1469,7 +1469,8 @@ std::inserter(Result, Result.begin())); llvm::Regex IncludeRegex(IncludeRegexPattern); - llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)"); + llvm::Regex IfNDefRegex(R"(^[\t\ ]*#[\t\ ]*ifndef[\t\ ]*([^\\]*)$)"); + llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*([^\\]*)$)"); SmallVector Matches; StringRef FileName = Replaces.begin()->getFilePath(); @@ -1484,7 +1485,9 @@ Priorities.insert(Category.Priority); int FirstIncludeOffset = -1; int Offset = 0; + int AfterFirstIfNDef = 0; int AfterHeaderGuard = 0; + StringRef FirstIfNDefName; SmallVector Lines; Code.split(Lines, '\n'); for (auto Line : Lines) { @@ -1496,10 +1499,15 @@ if (FirstIncludeOffset < 0) FirstIncludeOffset = Offset; } + if (AfterHeaderGuard == 0 && AfterFirstIfNDef > 0 && + AfterFirstIfNDef == Offset && DefineRegex.match(Line, &Matches) && + Matches[1] == FirstIfNDefName) + AfterHeaderGuard = Offset + Line.size() + 1; Offset += Line.size() + 1; - // FIXME: make header guard matching stricter, e.g. consider #ifndef. - if (AfterHeaderGuard == 0 && DefineRegex.match(Line)) - AfterHeaderGuard = Offset; + if (AfterFirstIfNDef == 0 && IfNDefRegex.match(Line, &Matches)) { + FirstIfNDefName = Matches[1]; + AfterFirstIfNDef = Offset; + } } // Populate CategoryEndOfssets: Index: unittests/Format/CleanupTest.cpp =================================================================== --- unittests/Format/CleanupTest.cpp +++ unittests/Format/CleanupTest.cpp @@ -537,6 +537,34 @@ EXPECT_EQ(Expected, formatAndApply(Code, Replaces)); } +TEST_F(CleanUpReplacementsTest, DontJustInsertAfterRandomDefine) { + std::string Code = "#define X 1"; + std::string Expected = "#include \n" + "#define X 1"; + tooling::Replacements Replaces = {createInsertion("#include ")}; + EXPECT_EQ(Expected, apply(Code, Replaces)); +} + +TEST_F(CleanUpReplacementsTest, InsertAfterHeaderGuard) { + std::string Code = "#ifndef X_H\n" + "#define X_H\n"; + std::string Expected = "#ifndef X_H\n" + "#define X_H\n" + "#include \n"; + tooling::Replacements Replaces = {createInsertion("#include ")}; + EXPECT_EQ(Expected, apply(Code, Replaces)); +} + +TEST_F(CleanUpReplacementsTest, DontInsertAfterNonMatchedHeaderGuard) { + std::string Code = "#ifndef X_H\n" + "#define Y_H"; + std::string Expected = "#include \n" + "#ifndef X_H\n" + "#define Y_H"; + tooling::Replacements Replaces = {createInsertion("#include ")}; + EXPECT_EQ(Expected, apply(Code, Replaces)); +} + } // end namespace } // end namespace format } // end namespace clang