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(); @@ -1487,7 +1488,9 @@ int AfterHeaderGuard = 0; SmallVector Lines; Code.split(Lines, '\n'); - for (auto Line : Lines) { + for (auto I = Lines.begin(), B = Lines.begin(), E = Lines.end(); I != E; + ++I) { + StringRef Line = *I; if (IncludeRegex.match(Line, &Matches)) { StringRef IncludeName = Matches[2]; int Category = Categories.getIncludePriority( @@ -1497,9 +1500,13 @@ FirstIncludeOffset = Offset; } Offset += Line.size() + 1; - // FIXME: make header guard matching stricter, e.g. consider #ifndef. - if (AfterHeaderGuard == 0 && DefineRegex.match(Line)) - AfterHeaderGuard = Offset; + if (FirstIncludeOffset < 0 && AfterHeaderGuard == 0 && I != B && + DefineRegex.match(Line, &Matches)) { + StringRef DefineName = Matches[1]; + if (IfNDefRegex.match(*std::prev(I), &Matches) && + DefineName == Matches[1]) + AfterHeaderGuard = 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