OutputFormatHelper.h
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * C++ Insights, copyright (C) by Andreas Fertig
4  * Distributed under an MIT license. See LICENSE for details
5  *
6  ****************************************************************************/
7 
8 #ifndef OUTPUT_FORMAT_HELPER_H
9 #define OUTPUT_FORMAT_HELPER_H
10 //-----------------------------------------------------------------------------
11 
12 #include <string_view>
13 #include <utility>
14 using namespace std::literals;
15 
16 #include "InsightsOnce.h"
17 #include "InsightsStrCat.h"
18 #include "InsightsStrongTypes.h"
19 //-----------------------------------------------------------------------------
20 
21 namespace clang::insights {
22 //-----------------------------------------------------------------------------
23 
24 /// \brief The C++ Insights formatter.
25 ///
26 /// Most of the code is handed to \ref OutputFormatHelper for easy code formatting.
28 {
29 public:
30  OutputFormatHelper() = default;
31 
32  explicit OutputFormatHelper(const unsigned indent)
33  : mDefaultIndent{indent}
34  {
35  }
36 
37  operator std::string_view() const& { return {mOutput}; }
38 
39  auto size() const { return mOutput.size(); }
40 
41  /// \brief Returns the current position in the output buffer.
42  size_t CurrentPos() const { return mOutput.length(); }
43 
44  /// \brief Insert a string before the position \c atPos
45  void InsertAt(const size_t atPos, std::string_view data) { mOutput.insert(atPos, data); }
46 
47  STRONG_BOOL(SkipIndenting);
48 
49  auto GetIndent() const { return mDefaultIndent; }
50 
51  /// \brief Set the indent level of this class to \c indent.
52  void SetIndent(const unsigned indent, const SkipIndenting skipIndenting = SkipIndenting::No)
53  {
54  mDefaultIndent = indent;
55 
56  if(SkipIndenting::No == skipIndenting) {
57  Indent(mDefaultIndent);
58  }
59  }
60 
61  /// \brief Set the indent level of this class to that of \c rhs.
62  void SetIndent(const OutputFormatHelper& rhs, const SkipIndenting skipIndenting = SkipIndenting::No)
63  {
64  if(&rhs != this) {
65  mDefaultIndent = rhs.mDefaultIndent;
66 
67  if(SkipIndenting::No == skipIndenting) {
68  Indent(mDefaultIndent);
69  }
70  }
71  }
72 
73  /// \brief Check whether the buffer is empty.
74  ///
75  /// This also treats a string of just whitespaces as empty.
76  bool empty() const { return mOutput.empty() or (std::string::npos == mOutput.find_first_not_of(' ', 0)); }
77 
78  /// \brief Returns a reference to the underlying string buffer.
79  std::string& GetString() { return mOutput; }
80 
81  /// \brief Append a single character
82  ///
83  /// Append a single character to the buffer
84  void Append(const char c) { mOutput += c; }
85 
86  void Append(const std::string_view& arg) { mOutput += arg; }
87 
88  /// \brief Append a variable number of data
89  ///
90  /// The \c StrCat function which is used ensures, that a \c StringRef or a char are converted appropriately.
91  void Append(const auto&... args) { details::StrCat(mOutput, args...); }
92 
93  /// \brief Same as \ref Append but adds a newline after the last argument.
94  ///
95  /// Append a single character to the buffer
96  void AppendNewLine(const char c)
97  {
98  mOutput += c;
99  NewLine();
100  }
101 
102  void AppendNewLine(const std::string_view& arg)
103  {
104  mOutput += arg;
105  NewLine();
106  }
107 
108  /// \brief Same as \ref Append but adds a newline after the last argument.
109  void AppendNewLine(const auto&... args)
110  {
111  if constexpr(0 < sizeof...(args)) {
112  details::StrCat(mOutput, args...);
113  }
114 
115  NewLine();
116  }
117 
118  void AppendComment(const std::string_view& arg)
119  {
120  Append("/* "sv);
121  Append(arg);
122  Append(" */"sv);
123  }
124 
125  void AppendCommentNewLine(const std::string_view& arg)
126  {
127  AppendComment(arg);
128  NewLine();
129  }
130 
131  void AppendCommentNewLine(const auto&... args)
132  {
133  if constexpr(0 < sizeof...(args)) {
134  AppendComment(StrCat(args...));
135  }
136 
137  NewLine();
138  }
139 
140  STRONG_BOOL(NameOnly);
141  STRONG_BOOL(GenMissingParamName);
142 
143  /// \brief Append a \c ParamVarDecl array.
144  ///
145  /// The parameter name is always added as well.
146  void AppendParameterList(const ArrayRef<ParmVarDecl*> parameters,
147  const NameOnly nameOnly = NameOnly::No,
148  const GenMissingParamName genMissingParamName = GenMissingParamName::No);
149 
150  /// \brief Increase the current indention by \c SCOPE_INDENT
151  void IncreaseIndent() { mDefaultIndent += SCOPE_INDENT; }
152  /// \brief Decrease the current indention by \c SCOPE_INDENT
154  {
155  if(mDefaultIndent >= SCOPE_INDENT) {
156  mDefaultIndent -= SCOPE_INDENT;
157  }
158  }
159 
160  /// \brief Open a scope by inserting a '{' followed by an indented newline.
161  void OpenScope()
162  {
163  Append('{');
164  IncreaseIndent();
165  NewLine();
166  }
167 
168  STRONG_BOOL(NoNewLineBefore);
169  /// \brief Close a scope by inserting a '}'
170  ///
171  /// With the parameter \c newLineBefore a newline after the brace can be inserted.
172  void CloseScope(const NoNewLineBefore newLineBefore = NoNewLineBefore::No);
173 
174  /// \brief Similiar to \ref CloseScope only this time a ';' is inserted after the brace.
175  void CloseScopeWithSemi(const NoNewLineBefore newLineBefore = NoNewLineBefore::No)
176  {
177  CloseScope(newLineBefore);
178  Append(';');
179  }
180 
181  /// \brief Append a comma if needed.
182  void AppendComma(OnceFalse& needsComma)
183  {
184  if(needsComma) {
185  Append(", "sv);
186  }
187  }
188 
189  /// \brief Append a semicolon and a newline.
190  void AppendSemiNewLine() { AppendNewLine(';'); }
191 
192  /// \brief Append a semicolon and a newline.
193  template<typename... Args>
194  void AppendSemiNewLine(const Args&... args)
195  {
196  if constexpr(0 < sizeof...(args)) {
197  details::StrCat(mOutput, args...);
198  }
199 
200  AppendNewLine(';');
201  }
202 
203  void AppendSemiNewLine(const std::string_view& arg)
204  {
205  mOutput += arg;
206  AppendNewLine(';');
207  }
208 
209  /// \brief Append a argument list to the buffer.
210  ///
211  /// This function takes care of the delimiting ',' between the parameters. The lambda \c lambda is called to each
212  /// argument after the comma was inserted.
213  /// Usage:
214  /// \code
215  /// ForEachArg(parameters, [&](const auto& p) {
216  /// // do something with p
217  /// });
218  /// \endcode
219  inline void ForEachArg(const auto& arguments, /*XXX: invocable*/ auto&& lambda)
220  {
221  for(OnceFalse needsComma{}; const auto& arg : arguments) {
222  if constexpr(std::is_same_v<const TemplateArgument&, decltype(arg)>) {
223  if((TemplateArgument::Pack == arg.getKind()) and (0 == arg.pack_size())) {
224  break;
225  }
226  }
227 
228  AppendComma(needsComma);
229 
230  lambda(arg);
231  }
232  }
233 
234  void InsertIfDefTemplateGuard() { AppendNewLine("#ifdef INSIGHTS_USE_TEMPLATE"sv); }
235  void InsertEndIfTemplateGuard() { AppendNewLine("#endif"sv); }
236 
237 private:
238  static constexpr unsigned SCOPE_INDENT{2};
239  unsigned mDefaultIndent{};
240  std::string mOutput{};
241 
242  void Indent(unsigned count);
243  void NewLine()
244  {
245  mOutput += '\n';
246  Indent(mDefaultIndent);
247  }
248 
249  void RemoveIndent();
250 };
251 //-----------------------------------------------------------------------------
252 
253 } // namespace clang::insights
254 #endif /* OUTPUT_FORMAT_HELPER_H */
The C++ Insights formatter.
void DecreaseIndent()
Decrease the current indention by SCOPE_INDENT.
void OpenScope()
Open a scope by inserting a '{' followed by an indented newline.
void AppendNewLine(const char c)
Same as Append but adds a newline after the last argument.
void ForEachArg(const auto &arguments, auto &&lambda)
Append a argument list to the buffer.
void AppendComma(OnceFalse &needsComma)
Append a comma if needed.
void AppendComment(const std::string_view &arg)
STRONG_BOOL(GenMissingParamName)
void AppendCommentNewLine(const auto &... args)
void Append(const char c)
Append a single character.
OutputFormatHelper(const unsigned indent)
void Append(const std::string_view &arg)
void Append(const auto &... args)
Append a variable number of data.
void SetIndent(const OutputFormatHelper &rhs, const SkipIndenting skipIndenting=SkipIndenting::No)
Set the indent level of this class to that of rhs.
void CloseScopeWithSemi(const NoNewLineBefore newLineBefore=NoNewLineBefore::No)
Similiar to CloseScope only this time a ';' is inserted after the brace.
bool empty() const
Check whether the buffer is empty.
void AppendCommentNewLine(const std::string_view &arg)
void IncreaseIndent()
Increase the current indention by SCOPE_INDENT.
void AppendSemiNewLine(const Args &... args)
Append a semicolon and a newline.
void AppendSemiNewLine(const std::string_view &arg)
void SetIndent(const unsigned indent, const SkipIndenting skipIndenting=SkipIndenting::No)
Set the indent level of this class to indent.
void AppendNewLine(const auto &... args)
Same as Append but adds a newline after the last argument.
std::string & GetString()
Returns a reference to the underlying string buffer.
size_t CurrentPos() const
Returns the current position in the output buffer.
void AppendSemiNewLine()
Append a semicolon and a newline.
void AppendNewLine(const std::string_view &arg)
void InsertAt(const size_t atPos, std::string_view data)
Insert a string before the position atPos.
void StrCat(std::string &ret, const auto &... args)