clang-format: Add preprocessor directive indentation
This is an implementation for bug 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:
- Include guards cover the entire file
- Include guards don't have #else
- 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.
- 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
Differential Revision: https://reviews.llvm.org/D35955