summaryrefslogtreecommitdiffstats
path: root/clang/unittests/Format/FormatTest.cpp
diff options
context:
space:
mode:
authorKrasimir Georgiev <krasimir@google.com>2017-08-30 14:34:57 +0000
committerKrasimir Georgiev <krasimir@google.com>2017-08-30 14:34:57 +0000
commitad47c907670669c7f5af732f25ccf16d40c9f4d4 (patch)
tree3d19120e78857dc8423f00ecff9158ae4ddc2c0b /clang/unittests/Format/FormatTest.cpp
parent24aafa57992c1cd787602fb351e2d1a1be4649eb (diff)
downloadbcm5719-llvm-ad47c907670669c7f5af732f25ccf16d40c9f4d4.tar.gz
bcm5719-llvm-ad47c907670669c7f5af732f25ccf16d40c9f4d4.zip
clang-format: Add preprocessor directive indentation
Summary: This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature. The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want. This adds a new enum config option, `IndentPPDirectives`. Values are: * `PPDIS_None` (in config: `None`): ``` #if FOO #if BAR #include <foo> #endif #endif ``` * `PPDIS_AfterHash` (in config: `AfterHash`): ``` #if FOO # if BAR # include <foo> # endif #endif ``` This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines. Preprocessor indentation also attempts to ignore include guards with the checks: 1. Include guards cover the entire file 2. Include guards don't have `#else` 3. Include guards begin with ``` #ifndef <var> #define <var> ``` This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking. Defects: * This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch. * This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times. * This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line. * Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch. Contributed by @euhlmann! Reviewers: djasper, klimek, krasimir Reviewed By: djasper, krasimir Subscribers: krasimir, mzeren-vmw, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D35955 llvm-svn: 312125
Diffstat (limited to 'clang/unittests/Format/FormatTest.cpp')
-rw-r--r--clang/unittests/Format/FormatTest.cpp179
1 files changed, 177 insertions, 2 deletions
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 1c57f033f46..6db78cc2eb8 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -2312,8 +2312,183 @@ TEST_F(FormatTest, LayoutMacroDefinitionsStatementsSpanningBlocks) {
getLLVMStyleWithColumns(11));
}
-TEST_F(FormatTest, IndentPreprocessorDirectivesAtZero) {
- EXPECT_EQ("{\n {\n#define A\n }\n}", format("{{\n#define A\n}}"));
+TEST_F(FormatTest, IndentPreprocessorDirectives) {
+ FormatStyle Style = getLLVMStyle();
+ Style.IndentPPDirectives = FormatStyle::PPDIS_None;
+ Style.ColumnLimit = 40;
+ verifyFormat("#ifdef _WIN32\n"
+ "#define A 0\n"
+ "#ifdef VAR2\n"
+ "#define B 1\n"
+ "#include <someheader.h>\n"
+ "#define MACRO \\\n"
+ " some_very_long_func_aaaaaaaaaa();\n"
+ "#endif\n"
+ "#else\n"
+ "#define A 1\n"
+ "#endif",
+ Style);
+
+ Style.IndentPPDirectives = FormatStyle::PPDIS_AfterHash;
+ verifyFormat("#ifdef _WIN32\n"
+ "# define A 0\n"
+ "# ifdef VAR2\n"
+ "# define B 1\n"
+ "# include <someheader.h>\n"
+ "# define MACRO \\\n"
+ " some_very_long_func_aaaaaaaaaa();\n"
+ "# endif\n"
+ "#else\n"
+ "# define A 1\n"
+ "#endif",
+ Style);
+ verifyFormat("#if A\n"
+ "# define MACRO \\\n"
+ " void a(int x) { \\\n"
+ " b(); \\\n"
+ " c(); \\\n"
+ " d(); \\\n"
+ " e(); \\\n"
+ " f(); \\\n"
+ " }\n"
+ "#endif",
+ Style);
+ // Comments before include guard.
+ verifyFormat("// file comment\n"
+ "// file comment\n"
+ "#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ Style);
+ // Test with include guards.
+ // EXPECT_EQ is used because verifyFormat() calls messUp() which incorrectly
+ // merges lines.
+ verifyFormat("#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ Style);
+ // Include guards must have a #define with the same variable immediately
+ // after #ifndef.
+ verifyFormat("#ifndef NOT_GUARD\n"
+ "# define FOO\n"
+ "code();\n"
+ "#endif",
+ Style);
+
+ // Include guards must cover the entire file.
+ verifyFormat("code();\n"
+ "code();\n"
+ "#ifndef NOT_GUARD\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#endif",
+ Style);
+ verifyFormat("#ifndef NOT_GUARD\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#endif\n"
+ "code();",
+ Style);
+ // Test with trailing blank lines.
+ verifyFormat("#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif\n",
+ Style);
+ // Include guards don't have #else.
+ verifyFormat("#ifndef NOT_GUARD\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#else\n"
+ "#endif",
+ Style);
+ verifyFormat("#ifndef NOT_GUARD\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#elif FOO\n"
+ "#endif",
+ Style);
+ // FIXME: This doesn't handle the case where there's code between the
+ // #ifndef and #define but all other conditions hold. This is because when
+ // the #define line is parsed, UnwrappedLineParser::Lines doesn't hold the
+ // previous code line yet, so we can't detect it.
+ EXPECT_EQ("#ifndef NOT_GUARD\n"
+ "code();\n"
+ "#define NOT_GUARD\n"
+ "code();\n"
+ "#endif",
+ format("#ifndef NOT_GUARD\n"
+ "code();\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#endif",
+ Style));
+ // FIXME: This doesn't handle cases where legitimate preprocessor lines may
+ // be outside an include guard. Examples are #pragma once and
+ // #pragma GCC diagnostic, or anything else that does not change the meaning
+ // of the file if it's included multiple times.
+ EXPECT_EQ("#ifdef WIN32\n"
+ "# pragma once\n"
+ "#endif\n"
+ "#ifndef HEADER_H\n"
+ "# define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ format("#ifdef WIN32\n"
+ "# pragma once\n"
+ "#endif\n"
+ "#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ Style));
+ // FIXME: This does not detect when there is a single non-preprocessor line
+ // in front of an include-guard-like structure where other conditions hold
+ // because ScopedLineState hides the line.
+ EXPECT_EQ("code();\n"
+ "#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ format("code();\n"
+ "#ifndef HEADER_H\n"
+ "# define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ Style));
+ // FIXME: The comment indent corrector in TokenAnnotator gets thrown off by
+ // preprocessor indentation.
+ EXPECT_EQ("#if 1\n"
+ " // comment\n"
+ "# define A 0\n"
+ "// comment\n"
+ "# define B 0\n"
+ "#endif",
+ format("#if 1\n"
+ "// comment\n"
+ "# define A 0\n"
+ " // comment\n"
+ "# define B 0\n"
+ "#endif",
+ Style));
+ // Test with tabs.
+ Style.UseTab = FormatStyle::UT_Always;
+ Style.IndentWidth = 8;
+ Style.TabWidth = 8;
+ verifyFormat("#ifdef _WIN32\n"
+ "#\tdefine A 0\n"
+ "#\tifdef VAR2\n"
+ "#\t\tdefine B 1\n"
+ "#\t\tinclude <someheader.h>\n"
+ "#\t\tdefine MACRO \\\n"
+ "\t\t\tsome_very_long_func_aaaaaaaaaa();\n"
+ "#\tendif\n"
+ "#else\n"
+ "#\tdefine A 1\n"
+ "#endif",
+ Style);
}
TEST_F(FormatTest, FormatHashIfNotAtStartOfLine) {
OpenPOWER on IntegriCloud