diff options
-rw-r--r-- | clang/lib/Format/UnwrappedLineParser.cpp | 64 | ||||
-rw-r--r-- | clang/lib/Format/UnwrappedLineParser.h | 17 | ||||
-rw-r--r-- | clang/unittests/Format/FormatTest.cpp | 138 |
3 files changed, 218 insertions, 1 deletions
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 9ef5d1514d9..aaed97c3020 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -323,6 +323,22 @@ void UnwrappedLineParser::parsePPDirective() { switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) { case tok::pp_define: parsePPDefine(); + return; + case tok::pp_if: + parsePPIf(); + break; + case tok::pp_ifdef: + case tok::pp_ifndef: + parsePPIfdef(); + break; + case tok::pp_else: + parsePPElse(); + break; + case tok::pp_elif: + parsePPElIf(); + break; + case tok::pp_endif: + parsePPEndIf(); break; default: parsePPUnknown(); @@ -330,6 +346,48 @@ void UnwrappedLineParser::parsePPDirective() { } } +void UnwrappedLineParser::pushPPConditional() { + if (!PPStack.empty() && PPStack.back() == PP_Unreachable) + PPStack.push_back(PP_Unreachable); + else + PPStack.push_back(PP_Conditional); +} + +void UnwrappedLineParser::parsePPIf() { + nextToken(); + if ((FormatTok.Tok.isLiteral() && + StringRef(FormatTok.Tok.getLiteralData(), FormatTok.Tok.getLength()) == + "0") || + FormatTok.Tok.is(tok::kw_false)) { + PPStack.push_back(PP_Unreachable); + } else { + pushPPConditional(); + } + parsePPUnknown(); +} + +void UnwrappedLineParser::parsePPIfdef() { + pushPPConditional(); + parsePPUnknown(); +} + +void UnwrappedLineParser::parsePPElse() { + if (!PPStack.empty()) + PPStack.pop_back(); + pushPPConditional(); + parsePPUnknown(); +} + +void UnwrappedLineParser::parsePPElIf() { + parsePPElse(); +} + +void UnwrappedLineParser::parsePPEndIf() { + if (!PPStack.empty()) + PPStack.pop_back(); + parsePPUnknown(); +} + void UnwrappedLineParser::parsePPDefine() { nextToken(); @@ -1020,6 +1078,12 @@ void UnwrappedLineParser::readToken() { flushComments(FormatTok.NewlinesBefore > 0); parsePPDirective(); } + + if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) && + !Line->InPPDirective) { + continue; + } + if (!FormatTok.Tok.is(tok::comment)) return; if (FormatTok.NewlinesBefore > 0 || FormatTok.IsFirst) { diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 4746951dcd7..bf3db1ea03b 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -17,7 +17,6 @@ #define LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H #include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include <list> @@ -140,6 +139,11 @@ private: void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1); void parsePPDirective(); void parsePPDefine(); + void parsePPIf(); + void parsePPIfdef(); + void parsePPElIf(); + void parsePPElse(); + void parsePPEndIf(); void parsePPUnknown(); void parseStructuralElement(); bool tryToParseBracedList(); @@ -167,6 +171,7 @@ private: void flushComments(bool NewlineBeforeNext); void pushToken(const FormatToken &Tok); void calculateBraceTypes(); + void pushPPConditional(); // Represents what type of block a left brace opens. enum LBraceState { @@ -224,6 +229,16 @@ private: // position of the token in the stream (see \c AllTokens). SmallVector<LBraceState, 16> LBraces; + // Represents preprocessor branch type, so we can find matching + // #if/#else/#endif directives. + enum PPBranchKind { + PP_Conditional, // Any #if, #ifdef, #ifndef, #elif, block outside #if 0 + PP_Unreachable // #if 0 or a conditional preprocessor block inside #if 0 + }; + + // Keeps a stack of currently active preprocessor branching directives. + SmallVector<PPBranchKind, 16> PPStack; + friend class ScopedLineState; }; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index f72013a448d..add74661169 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -1035,6 +1035,144 @@ TEST_F(FormatTest, CommentsInStaticInitializers) { "};"); } +TEST_F(FormatTest, IgnoresIf0Contents) { + EXPECT_EQ("#if 0\n" + "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n" + "#endif\n" + "void f() {}", + format("#if 0\n" + "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n" + "#endif\n" + "void f( ) { }")); + EXPECT_EQ("#if false\n" + "void f( ) { }\n" + "#endif\n" + "void g() {}\n", + format("#if false\n" + "void f( ) { }\n" + "#endif\n" + "void g( ) { }\n")); + EXPECT_EQ("enum E {\n" + " One,\n" + " Two,\n" + "#if 0\n" + "Three,\n" + " Four,\n" + "#endif\n" + " Five\n" + "};", + format("enum E {\n" + " One,Two,\n" + "#if 0\n" + "Three,\n" + " Four,\n" + "#endif\n" + " Five};")); + EXPECT_EQ("enum F {\n" + " One,\n" + "#if 1\n" + " Two,\n" + "#if 0\n" + "Three,\n" + " Four,\n" + "#endif\n" + " Five\n" + "#endif\n" + "};", + format("enum F {\n" + "One,\n" + "#if 1\n" + "Two,\n" + "#if 0\n" + "Three,\n" + " Four,\n" + "#endif\n" + "Five\n" + "#endif\n" + "};")); + EXPECT_EQ("enum G {\n" + " One,\n" + "#if 0\n" + "Two,\n" + "#else\n" + " Three,\n" + "#endif\n" + " Four\n" + "};", + format("enum G {\n" + "One,\n" + "#if 0\n" + "Two,\n" + "#else\n" + "Three,\n" + "#endif\n" + "Four\n" + "};")); + EXPECT_EQ("enum H {\n" + " One,\n" + "#if 0\n" + "#ifdef Q\n" + "Two,\n" + "#else\n" + "Three,\n" + "#endif\n" + "#endif\n" + " Four\n" + "};", + format("enum H {\n" + "One,\n" + "#if 0\n" + "#ifdef Q\n" + "Two,\n" + "#else\n" + "Three,\n" + "#endif\n" + "#endif\n" + "Four\n" + "};")); + EXPECT_EQ("enum I {\n" + " One,\n" + "#if /* test */ 0 || 1\n" + "Two,\n" + "Three,\n" + "#endif\n" + " Four\n" + "};", + format("enum I {\n" + "One,\n" + "#if /* test */ 0 || 1\n" + "Two,\n" + "Three,\n" + "#endif\n" + "Four\n" + "};")); + EXPECT_EQ("enum J {\n" + " One,\n" + "#if 0\n" + "#if 0\n" + "Two,\n" + "#else\n" + "Three,\n" + "#endif\n" + "Four,\n" + "#endif\n" + " Five\n" + "};", + format("enum J {\n" + "One,\n" + "#if 0\n" + "#if 0\n" + "Two,\n" + "#else\n" + "Three,\n" + "#endif\n" + "Four,\n" + "#endif\n" + "Five\n" + "};")); + +} + //===----------------------------------------------------------------------===// // Tests for classes, namespaces, etc. //===----------------------------------------------------------------------===// |