1// ASBeautifier.cpp
2// Copyright (c) 2018 by Jim Pattee <jimp03@email.com>.
3// This code is licensed under the MIT License.
4// License.md describes the conditions under which this software may be distributed.
5
6//-----------------------------------------------------------------------------
7// headers
8//-----------------------------------------------------------------------------
9
10#include "astyle.h"
11
12#include <algorithm>
13
14//-----------------------------------------------------------------------------
15// astyle namespace
16//-----------------------------------------------------------------------------
17
18namespace astyle {
19//
20// this must be global
21static int g_preprocessorCppExternCBrace;
22
23//-----------------------------------------------------------------------------
24// ASBeautifier class
25//-----------------------------------------------------------------------------
26
27/**
28 * ASBeautifier's constructor
29 * This constructor is called only once for each source file.
30 * The cloned ASBeautifier objects are created with the copy constructor.
31 */
32ASBeautifier::ASBeautifier()
33{
34 waitingBeautifierStack = nullptr;
35 activeBeautifierStack = nullptr;
36 waitingBeautifierStackLengthStack = nullptr;
37 activeBeautifierStackLengthStack = nullptr;
38
39 headerStack = nullptr;
40 tempStacks = nullptr;
41 parenDepthStack = nullptr;
42 blockStatementStack = nullptr;
43 parenStatementStack = nullptr;
44 braceBlockStateStack = nullptr;
45 continuationIndentStack = nullptr;
46 continuationIndentStackSizeStack = nullptr;
47 parenIndentStack = nullptr;
48 preprocIndentStack = nullptr;
49 sourceIterator = nullptr;
50 isModeManuallySet = false;
51 shouldForceTabIndentation = false;
52 setSpaceIndentation(4);
53 setContinuationIndentation(1);
54 setMinConditionalIndentOption(MINCOND_TWO);
55 setMaxContinuationIndentLength(40);
56 classInitializerIndents = 1;
57 tabLength = 0;
58 setClassIndent(false);
59 setModifierIndent(false);
60 setSwitchIndent(false);
61 setCaseIndent(false);
62 setBlockIndent(false);
63 setBraceIndent(false);
64 setBraceIndentVtk(false);
65 setNamespaceIndent(false);
66 setAfterParenIndent(false);
67 setLabelIndent(false);
68 setEmptyLineFill(false);
69 setCStyle();
70 setPreprocDefineIndent(false);
71 setPreprocConditionalIndent(false);
72 setAlignMethodColon(false);
73
74 // initialize ASBeautifier member vectors
75 beautifierFileType = 9; // reset to an invalid type
76 headers = new vector<const string*>;
77 nonParenHeaders = new vector<const string*>;
78 assignmentOperators = new vector<const string*>;
79 nonAssignmentOperators = new vector<const string*>;
80 preBlockStatements = new vector<const string*>;
81 preCommandHeaders = new vector<const string*>;
82 indentableHeaders = new vector<const string*>;
83}
84
85/**
86 * ASBeautifier's copy constructor
87 * Copy the vector objects to vectors in the new ASBeautifier
88 * object so the new object can be destroyed without deleting
89 * the vector objects in the copied vector.
90 * This is the reason a copy constructor is needed.
91 *
92 * Must explicitly call the base class copy constructor.
93 */
94ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other)
95{
96 // these don't need to copy the stack
97 waitingBeautifierStack = nullptr;
98 activeBeautifierStack = nullptr;
99 waitingBeautifierStackLengthStack = nullptr;
100 activeBeautifierStackLengthStack = nullptr;
101
102 // vector '=' operator performs a DEEP copy of all elements in the vector
103
104 headerStack = new vector<const string*>;
105 *headerStack = *other.headerStack;
106
107 tempStacks = copyTempStacks(other);
108
109 parenDepthStack = new vector<int>;
110 *parenDepthStack = *other.parenDepthStack;
111
112 blockStatementStack = new vector<bool>;
113 *blockStatementStack = *other.blockStatementStack;
114
115 parenStatementStack = new vector<bool>;
116 *parenStatementStack = *other.parenStatementStack;
117
118 braceBlockStateStack = new vector<bool>;
119 *braceBlockStateStack = *other.braceBlockStateStack;
120
121 continuationIndentStack = new vector<int>;
122 *continuationIndentStack = *other.continuationIndentStack;
123
124 continuationIndentStackSizeStack = new vector<size_t>;
125 *continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack;
126
127 parenIndentStack = new vector<int>;
128 *parenIndentStack = *other.parenIndentStack;
129
130 preprocIndentStack = new vector<pair<int, int> >;
131 *preprocIndentStack = *other.preprocIndentStack;
132
133 // Copy the pointers to vectors.
134 // This is ok because the original ASBeautifier object
135 // is not deleted until end of job.
136 beautifierFileType = other.beautifierFileType;
137 headers = other.headers;
138 nonParenHeaders = other.nonParenHeaders;
139 assignmentOperators = other.assignmentOperators;
140 nonAssignmentOperators = other.nonAssignmentOperators;
141 preBlockStatements = other.preBlockStatements;
142 preCommandHeaders = other.preCommandHeaders;
143 indentableHeaders = other.indentableHeaders;
144
145 // protected variables
146 // variables set by ASFormatter
147 // must also be updated in activeBeautifierStack
148 inLineNumber = other.inLineNumber;
149 runInIndentContinuation = other.runInIndentContinuation;
150 nonInStatementBrace = other.nonInStatementBrace;
151 objCColonAlignSubsequent = other.objCColonAlignSubsequent;
152 lineCommentNoBeautify = other.lineCommentNoBeautify;
153 isElseHeaderIndent = other.isElseHeaderIndent;
154 isCaseHeaderCommentIndent = other.isCaseHeaderCommentIndent;
155 isNonInStatementArray = other.isNonInStatementArray;
156 isSharpAccessor = other.isSharpAccessor;
157 isSharpDelegate = other.isSharpDelegate;
158 isInExternC = other.isInExternC;
159 isInBeautifySQL = other.isInBeautifySQL;
160 isInIndentableStruct = other.isInIndentableStruct;
161 isInIndentablePreproc = other.isInIndentablePreproc;
162
163 // private variables
164 sourceIterator = other.sourceIterator;
165 currentHeader = other.currentHeader;
166 previousLastLineHeader = other.previousLastLineHeader;
167 probationHeader = other.probationHeader;
168 lastLineHeader = other.lastLineHeader;
169 indentString = other.indentString;
170 verbatimDelimiter = other.verbatimDelimiter;
171 isInQuote = other.isInQuote;
172 isInVerbatimQuote = other.isInVerbatimQuote;
173 haveLineContinuationChar = other.haveLineContinuationChar;
174 isInAsm = other.isInAsm;
175 isInAsmOneLine = other.isInAsmOneLine;
176 isInAsmBlock = other.isInAsmBlock;
177 isInComment = other.isInComment;
178 isInPreprocessorComment = other.isInPreprocessorComment;
179 isInRunInComment = other.isInRunInComment;
180 isInCase = other.isInCase;
181 isInQuestion = other.isInQuestion;
182 isContinuation = other.isContinuation;
183 isInHeader = other.isInHeader;
184 isInTemplate = other.isInTemplate;
185 isInDefine = other.isInDefine;
186 isInDefineDefinition = other.isInDefineDefinition;
187 classIndent = other.classIndent;
188 isIndentModeOff = other.isIndentModeOff;
189 isInClassHeader = other.isInClassHeader;
190 isInClassHeaderTab = other.isInClassHeaderTab;
191 isInClassInitializer = other.isInClassInitializer;
192 isInClass = other.isInClass;
193 isInObjCMethodDefinition = other.isInObjCMethodDefinition;
194 isInObjCMethodCall = other.isInObjCMethodCall;
195 isInObjCMethodCallFirst = other.isInObjCMethodCallFirst;
196 isImmediatelyPostObjCMethodDefinition = other.isImmediatelyPostObjCMethodDefinition;
197 isImmediatelyPostObjCMethodCall = other.isImmediatelyPostObjCMethodCall;
198 isInIndentablePreprocBlock = other.isInIndentablePreprocBlock;
199 isInObjCInterface = other.isInObjCInterface;
200 isInEnum = other.isInEnum;
201 isInEnumTypeID = other.isInEnumTypeID;
202 isInLet = other.isInLet;
203 isInTrailingReturnType = other.isInTrailingReturnType;
204 modifierIndent = other.modifierIndent;
205 switchIndent = other.switchIndent;
206 caseIndent = other.caseIndent;
207 namespaceIndent = other.namespaceIndent;
208 braceIndent = other.braceIndent;
209 braceIndentVtk = other.braceIndentVtk;
210 blockIndent = other.blockIndent;
211 shouldIndentAfterParen = other.shouldIndentAfterParen;
212 labelIndent = other.labelIndent;
213 isInConditional = other.isInConditional;
214 isModeManuallySet = other.isModeManuallySet;
215 shouldForceTabIndentation = other.shouldForceTabIndentation;
216 emptyLineFill = other.emptyLineFill;
217 lineOpensWithLineComment = other.lineOpensWithLineComment;
218 lineOpensWithComment = other.lineOpensWithComment;
219 lineStartsInComment = other.lineStartsInComment;
220 backslashEndsPrevLine = other.backslashEndsPrevLine;
221 blockCommentNoIndent = other.blockCommentNoIndent;
222 blockCommentNoBeautify = other.blockCommentNoBeautify;
223 previousLineProbationTab = other.previousLineProbationTab;
224 lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace;
225 lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace;
226 lineBeginsWithComma = other.lineBeginsWithComma;
227 lineIsCommentOnly = other.lineIsCommentOnly;
228 lineIsLineCommentOnly = other.lineIsLineCommentOnly;
229 shouldIndentBracedLine = other.shouldIndentBracedLine;
230 isInSwitch = other.isInSwitch;
231 foundPreCommandHeader = other.foundPreCommandHeader;
232 foundPreCommandMacro = other.foundPreCommandMacro;
233 shouldAlignMethodColon = other.shouldAlignMethodColon;
234 shouldIndentPreprocDefine = other.shouldIndentPreprocDefine;
235 shouldIndentPreprocConditional = other.shouldIndentPreprocConditional;
236 indentCount = other.indentCount;
237 spaceIndentCount = other.spaceIndentCount;
238 spaceIndentObjCMethodAlignment = other.spaceIndentObjCMethodAlignment;
239 bracePosObjCMethodAlignment = other.bracePosObjCMethodAlignment;
240 colonIndentObjCMethodAlignment = other.colonIndentObjCMethodAlignment;
241 lineOpeningBlocksNum = other.lineOpeningBlocksNum;
242 lineClosingBlocksNum = other.lineClosingBlocksNum;
243 fileType = other.fileType;
244 minConditionalOption = other.minConditionalOption;
245 minConditionalIndent = other.minConditionalIndent;
246 parenDepth = other.parenDepth;
247 indentLength = other.indentLength;
248 tabLength = other.tabLength;
249 continuationIndent = other.continuationIndent;
250 blockTabCount = other.blockTabCount;
251 maxContinuationIndent = other.maxContinuationIndent;
252 classInitializerIndents = other.classInitializerIndents;
253 templateDepth = other.templateDepth;
254 squareBracketCount = other.squareBracketCount;
255 prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount;
256 prevFinalLineIndentCount = other.prevFinalLineIndentCount;
257 defineIndentCount = other.defineIndentCount;
258 preprocBlockIndent = other.preprocBlockIndent;
259 quoteChar = other.quoteChar;
260 prevNonSpaceCh = other.prevNonSpaceCh;
261 currentNonSpaceCh = other.currentNonSpaceCh;
262 currentNonLegalCh = other.currentNonLegalCh;
263 prevNonLegalCh = other.prevNonLegalCh;
264}
265
266/**
267 * ASBeautifier's destructor
268 */
269ASBeautifier::~ASBeautifier()
270{
271 deleteBeautifierContainer(waitingBeautifierStack);
272 deleteBeautifierContainer(activeBeautifierStack);
273 deleteContainer(waitingBeautifierStackLengthStack);
274 deleteContainer(activeBeautifierStackLengthStack);
275 deleteContainer(headerStack);
276 deleteTempStacksContainer(tempStacks);
277 deleteContainer(parenDepthStack);
278 deleteContainer(blockStatementStack);
279 deleteContainer(parenStatementStack);
280 deleteContainer(braceBlockStateStack);
281 deleteContainer(continuationIndentStack);
282 deleteContainer(continuationIndentStackSizeStack);
283 deleteContainer(parenIndentStack);
284 deleteContainer(preprocIndentStack);
285}
286
287/**
288 * initialize the ASBeautifier.
289 *
290 * This init() should be called every time a ABeautifier object is to start
291 * beautifying a NEW source file.
292 * It is called only when a new ASFormatter object is created.
293 * init() receives a pointer to a ASSourceIterator object that will be
294 * used to iterate through the source code.
295 *
296 * @param iter a pointer to the ASSourceIterator or ASStreamIterator object.
297 */
298void ASBeautifier::init(ASSourceIterator* iter)
299{
300 sourceIterator = iter;
301 initVectors();
302 ASBase::init(getFileType());
303 g_preprocessorCppExternCBrace = 0;
304
305 initContainer(waitingBeautifierStack, new vector<ASBeautifier*>);
306 initContainer(activeBeautifierStack, new vector<ASBeautifier*>);
307
308 initContainer(waitingBeautifierStackLengthStack, new vector<size_t>);
309 initContainer(activeBeautifierStackLengthStack, new vector<size_t>);
310
311 initContainer(headerStack, new vector<const string*>);
312
313 initTempStacksContainer(tempStacks, new vector<vector<const string*>*>);
314 tempStacks->emplace_back(new vector<const string*>);
315
316 initContainer(parenDepthStack, new vector<int>);
317 initContainer(blockStatementStack, new vector<bool>);
318 initContainer(parenStatementStack, new vector<bool>);
319 initContainer(braceBlockStateStack, new vector<bool>);
320 // do not use emplace_back on vector<bool> until supported by macOS
321 braceBlockStateStack->push_back(true);
322 initContainer(continuationIndentStack, new vector<int>);
323 initContainer(continuationIndentStackSizeStack, new vector<size_t>);
324 continuationIndentStackSizeStack->emplace_back(0);
325 initContainer(parenIndentStack, new vector<int>);
326 initContainer(preprocIndentStack, new vector<pair<int, int> >);
327
328 previousLastLineHeader = nullptr;
329 currentHeader = nullptr;
330
331 isInQuote = false;
332 isInVerbatimQuote = false;
333 haveLineContinuationChar = false;
334 isInAsm = false;
335 isInAsmOneLine = false;
336 isInAsmBlock = false;
337 isInComment = false;
338 isInPreprocessorComment = false;
339 isInRunInComment = false;
340 isContinuation = false;
341 isInCase = false;
342 isInQuestion = false;
343 isIndentModeOff = false;
344 isInClassHeader = false;
345 isInClassHeaderTab = false;
346 isInClassInitializer = false;
347 isInClass = false;
348 isInObjCMethodDefinition = false;
349 isInObjCMethodCall = false;
350 isInObjCMethodCallFirst = false;
351 isImmediatelyPostObjCMethodDefinition = false;
352 isImmediatelyPostObjCMethodCall = false;
353 isInIndentablePreprocBlock = false;
354 isInObjCInterface = false;
355 isInEnum = false;
356 isInEnumTypeID = false;
357 isInLet = false;
358 isInHeader = false;
359 isInTemplate = false;
360 isInConditional = false;
361 isInTrailingReturnType = false;
362
363 indentCount = 0;
364 spaceIndentCount = 0;
365 spaceIndentObjCMethodAlignment = 0;
366 bracePosObjCMethodAlignment = 0;
367 colonIndentObjCMethodAlignment = 0;
368 lineOpeningBlocksNum = 0;
369 lineClosingBlocksNum = 0;
370 templateDepth = 0;
371 squareBracketCount = 0;
372 parenDepth = 0;
373 blockTabCount = 0;
374 prevFinalLineSpaceIndentCount = 0;
375 prevFinalLineIndentCount = 0;
376 defineIndentCount = 0;
377 preprocBlockIndent = 0;
378 prevNonSpaceCh = '{';
379 currentNonSpaceCh = '{';
380 prevNonLegalCh = '{';
381 currentNonLegalCh = '{';
382 quoteChar = ' ';
383 probationHeader = nullptr;
384 lastLineHeader = nullptr;
385 backslashEndsPrevLine = false;
386 lineOpensWithLineComment = false;
387 lineOpensWithComment = false;
388 lineStartsInComment = false;
389 isInDefine = false;
390 isInDefineDefinition = false;
391 lineCommentNoBeautify = false;
392 isElseHeaderIndent = false;
393 isCaseHeaderCommentIndent = false;
394 blockCommentNoIndent = false;
395 blockCommentNoBeautify = false;
396 previousLineProbationTab = false;
397 lineBeginsWithOpenBrace = false;
398 lineBeginsWithCloseBrace = false;
399 lineBeginsWithComma = false;
400 lineIsCommentOnly = false;
401 lineIsLineCommentOnly = false;
402 shouldIndentBracedLine = true;
403 isInSwitch = false;
404 foundPreCommandHeader = false;
405 foundPreCommandMacro = false;
406
407 isNonInStatementArray = false;
408 isSharpAccessor = false;
409 isSharpDelegate = false;
410 isInExternC = false;
411 isInBeautifySQL = false;
412 isInIndentableStruct = false;
413 isInIndentablePreproc = false;
414 inLineNumber = 0;
415 runInIndentContinuation = 0;
416 nonInStatementBrace = 0;
417 objCColonAlignSubsequent = 0;
418}
419
420/*
421 * initialize the vectors
422 */
423void ASBeautifier::initVectors()
424{
425 if (fileType == beautifierFileType) // don't build unless necessary
426 return;
427
428 beautifierFileType = fileType;
429
430 headers->clear();
431 nonParenHeaders->clear();
432 assignmentOperators->clear();
433 nonAssignmentOperators->clear();
434 preBlockStatements->clear();
435 preCommandHeaders->clear();
436 indentableHeaders->clear();
437
438 ASResource::buildHeaders(headers, fileType, true);
439 ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
440 ASResource::buildAssignmentOperators(assignmentOperators);
441 ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
442 ASResource::buildPreBlockStatements(preBlockStatements, fileType);
443 ASResource::buildPreCommandHeaders(preCommandHeaders, fileType);
444 ASResource::buildIndentableHeaders(indentableHeaders);
445}
446
447/**
448 * beautify a line of source code.
449 * every line of source code in a source code file should be sent
450 * one after the other to the beautify method.
451 *
452 * @return the indented line.
453 * @param originalLine the original unindented line.
454 */
455string ASBeautifier::beautify(const string& originalLine)
456{
457 string line;
458 bool isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
459
460 currentHeader = nullptr;
461 lastLineHeader = nullptr;
462 blockCommentNoBeautify = blockCommentNoIndent;
463 isInClass = false;
464 isInSwitch = false;
465 lineBeginsWithOpenBrace = false;
466 lineBeginsWithCloseBrace = false;
467 lineBeginsWithComma = false;
468 lineIsCommentOnly = false;
469 lineIsLineCommentOnly = false;
470 shouldIndentBracedLine = true;
471 isInAsmOneLine = false;
472 lineOpensWithLineComment = false;
473 lineOpensWithComment = false;
474 lineStartsInComment = isInComment;
475 previousLineProbationTab = false;
476 lineOpeningBlocksNum = 0;
477 lineClosingBlocksNum = 0;
478 if (isImmediatelyPostObjCMethodDefinition)
479 clearObjCMethodDefinitionAlignment();
480 if (isImmediatelyPostObjCMethodCall)
481 {
482 isImmediatelyPostObjCMethodCall = false;
483 isInObjCMethodCall = false;
484 objCColonAlignSubsequent = 0;
485 }
486
487 // handle and remove white spaces around the line:
488 // If not in comment, first find out size of white space before line,
489 // so that possible comments starting in the line continue in
490 // relation to the preliminary white-space.
491 if (isInQuoteContinuation)
492 {
493 // trim a single space added by ASFormatter, otherwise leave it alone
494 if (!(originalLine.length() == 1 && originalLine[0] == ' '))
495 line = originalLine;
496 }
497 else if (isInComment || isInBeautifySQL)
498 {
499 // trim the end of comment and SQL lines
500 line = originalLine;
501 size_t trimEnd = line.find_last_not_of(" \t");
502 if (trimEnd == string::npos)
503 trimEnd = 0;
504 else
505 trimEnd++;
506 if (trimEnd < line.length())
507 line.erase(trimEnd);
508 // does a brace open the line
509 size_t firstChar = line.find_first_not_of(" \t");
510 if (firstChar != string::npos)
511 {
512 if (line[firstChar] == '{')
513 lineBeginsWithOpenBrace = true;
514 else if (line[firstChar] == '}')
515 lineBeginsWithCloseBrace = true;
516 else if (line[firstChar] == ',')
517 lineBeginsWithComma = true;
518 }
519 }
520 else
521 {
522 line = trim(originalLine);
523 if (line.length() > 0)
524 {
525 if (line[0] == '{')
526 lineBeginsWithOpenBrace = true;
527 else if (line[0] == '}')
528 lineBeginsWithCloseBrace = true;
529 else if (line[0] == ',')
530 lineBeginsWithComma = true;
531 else if (line.compare(0, 2, "//") == 0)
532 lineIsLineCommentOnly = true;
533 else if (line.compare(0, 2, "/*") == 0)
534 {
535 if (line.find("*/", 2) != string::npos)
536 lineIsCommentOnly = true;
537 }
538 }
539
540 isInRunInComment = false;
541 size_t j = line.find_first_not_of(" \t{");
542 if (j != string::npos && line.compare(j, 2, "//") == 0)
543 lineOpensWithLineComment = true;
544 if (j != string::npos && line.compare(j, 2, "/*") == 0)
545 {
546 lineOpensWithComment = true;
547 size_t k = line.find_first_not_of(" \t");
548 if (k != string::npos && line.compare(k, 1, "{") == 0)
549 isInRunInComment = true;
550 }
551 }
552
553 // When indent is OFF the lines must still be processed by ASBeautifier.
554 // Otherwise the lines immediately following may not be indented correctly.
555 if ((lineIsLineCommentOnly || lineIsCommentOnly)
556 && line.find("*INDENT-OFF*", 0) != string::npos)
557 isIndentModeOff = true;
558
559 if (line.length() == 0)
560 {
561 if (backslashEndsPrevLine)
562 {
563 backslashEndsPrevLine = false;
564 // check if this line ends a multi-line #define
565 // if so, remove the #define's cloned beautifier from the active
566 // beautifier stack and delete it.
567 if (isInDefineDefinition && !isInDefine)
568 {
569 isInDefineDefinition = false;
570 if (!activeBeautifierStack->empty())
571 {
572 ASBeautifier* defineBeautifier = activeBeautifierStack->back();
573 activeBeautifierStack->pop_back();
574 delete defineBeautifier;
575 }
576 }
577 }
578 if (emptyLineFill && !isInQuoteContinuation)
579 {
580 if (isInIndentablePreprocBlock)
581 return preLineWS(preprocBlockIndent, 0);
582 if (!headerStack->empty() || isInEnum)
583 return preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount);
584 // must fall thru here
585 }
586 else
587 return line;
588 }
589
590 // handle preprocessor commands
591 if (isInIndentablePreprocBlock
592 && line.length() > 0
593 && line[0] != '#')
594 {
595 string indentedLine;
596 if (isInClassHeaderTab || isInClassInitializer)
597 {
598 // parsing is turned off in ASFormatter by indent-off
599 // the originalLine will probably never be returned here
600 indentedLine = preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount) + line;
601 return getIndentedLineReturn(indentedLine, originalLine);
602 }
603 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
604 return getIndentedLineReturn(indentedLine, originalLine);
605 }
606
607 if (!isInComment
608 && !isInQuoteContinuation
609 && line.length() > 0
610 && ((line[0] == '#' && !isIndentedPreprocessor(line, 0))
611 || backslashEndsPrevLine))
612 {
613 if (line[0] == '#' && !isInDefine)
614 {
615 string preproc = extractPreprocessorStatement(line);
616 processPreprocessor(preproc, line);
617 if (isInIndentablePreprocBlock || isInIndentablePreproc)
618 {
619 string indentedLine;
620 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
621 {
622 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
623 preprocBlockIndent += 1;
624 isInIndentablePreprocBlock = true;
625 }
626 else if (preproc == "else" || preproc == "elif")
627 {
628 indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line;
629 }
630 else if (preproc == "endif")
631 {
632 preprocBlockIndent -= 1;
633 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
634 if (preprocBlockIndent == 0)
635 isInIndentablePreprocBlock = false;
636 }
637 else
638 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
639 return getIndentedLineReturn(indentedLine, originalLine);
640 }
641 if (shouldIndentPreprocConditional && preproc.length() > 0)
642 {
643 string indentedLine;
644 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
645 {
646 pair<int, int> entry; // indentCount, spaceIndentCount
647 if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
648 entry = activeBeautifierStack->back()->computePreprocessorIndent();
649 else
650 entry = computePreprocessorIndent();
651 preprocIndentStack->emplace_back(entry);
652 indentedLine = preLineWS(preprocIndentStack->back().first,
653 preprocIndentStack->back().second) + line;
654 return getIndentedLineReturn(indentedLine, originalLine);
655 }
656 if (preproc == "else" || preproc == "elif")
657 {
658 if (!preprocIndentStack->empty()) // if no entry don't indent
659 {
660 indentedLine = preLineWS(preprocIndentStack->back().first,
661 preprocIndentStack->back().second) + line;
662 return getIndentedLineReturn(indentedLine, originalLine);
663 }
664 }
665 else if (preproc == "endif")
666 {
667 if (!preprocIndentStack->empty()) // if no entry don't indent
668 {
669 indentedLine = preLineWS(preprocIndentStack->back().first,
670 preprocIndentStack->back().second) + line;
671 preprocIndentStack->pop_back();
672 return getIndentedLineReturn(indentedLine, originalLine);
673 }
674 }
675 }
676 }
677
678 // check if the last char is a backslash
679 if (line.length() > 0)
680 backslashEndsPrevLine = (line[line.length() - 1] == '\\');
681 // comments within the definition line can be continued without the backslash
682 if (isInPreprocessorUnterminatedComment(line))
683 backslashEndsPrevLine = true;
684
685 // check if this line ends a multi-line #define
686 // if so, use the #define's cloned beautifier for the line's indentation
687 // and then remove it from the active beautifier stack and delete it.
688 if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
689 {
690 isInDefineDefinition = false;
691 // this could happen with invalid input
692 if (activeBeautifierStack->empty())
693 return originalLine;
694 ASBeautifier* defineBeautifier = activeBeautifierStack->back();
695 activeBeautifierStack->pop_back();
696
697 string indentedLine = defineBeautifier->beautify(line);
698 delete defineBeautifier;
699 return getIndentedLineReturn(indentedLine, originalLine);
700 }
701
702 // unless this is a multi-line #define, return this precompiler line as is.
703 if (!isInDefine && !isInDefineDefinition)
704 return originalLine;
705 }
706
707 // if there exists any worker beautifier in the activeBeautifierStack,
708 // then use it instead of me to indent the current line.
709 // variables set by ASFormatter must be updated.
710 if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
711 {
712 activeBeautifierStack->back()->inLineNumber = inLineNumber;
713 activeBeautifierStack->back()->runInIndentContinuation = runInIndentContinuation;
714 activeBeautifierStack->back()->nonInStatementBrace = nonInStatementBrace;
715 activeBeautifierStack->back()->objCColonAlignSubsequent = objCColonAlignSubsequent;
716 activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
717 activeBeautifierStack->back()->isElseHeaderIndent = isElseHeaderIndent;
718 activeBeautifierStack->back()->isCaseHeaderCommentIndent = isCaseHeaderCommentIndent;
719 activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
720 activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
721 activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
722 activeBeautifierStack->back()->isInExternC = isInExternC;
723 activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL;
724 activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct;
725 activeBeautifierStack->back()->isInIndentablePreproc = isInIndentablePreproc;
726 // must return originalLine not the trimmed line
727 return activeBeautifierStack->back()->beautify(originalLine);
728 }
729
730 // Flag an indented header in case this line is a one-line block.
731 // The header in the header stack will be deleted by a one-line block.
732 bool isInExtraHeaderIndent = false;
733 if (!headerStack->empty()
734 && lineBeginsWithOpenBrace
735 && (headerStack->back() != &AS_OPEN_BRACE
736 || probationHeader != nullptr))
737 isInExtraHeaderIndent = true;
738
739 size_t iPrelim = headerStack->size();
740
741 // calculate preliminary indentation based on headerStack and data from past lines
742 computePreliminaryIndentation();
743
744 // parse characters in the current line.
745 parseCurrentLine(line);
746
747 // handle special cases of indentation
748 adjustParsedLineIndentation(iPrelim, isInExtraHeaderIndent);
749
750 if (isInObjCMethodDefinition)
751 adjustObjCMethodDefinitionIndentation(line);
752
753 if (isInObjCMethodCall)
754 adjustObjCMethodCallIndentation(line);
755
756 if (isInDefine)
757 {
758 if (line.length() > 0 && line[0] == '#')
759 {
760 // the 'define' does not have to be attached to the '#'
761 string preproc = trim(line.substr(1));
762 if (preproc.compare(0, 6, "define") == 0)
763 {
764 if (!continuationIndentStack->empty()
765 && continuationIndentStack->back() > 0)
766 {
767 defineIndentCount = indentCount;
768 }
769 else
770 {
771 defineIndentCount = indentCount - 1;
772 --indentCount;
773 }
774 }
775 }
776
777 indentCount -= defineIndentCount;
778 }
779
780 if (indentCount < 0)
781 indentCount = 0;
782
783 if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation)
784 indentCount = spaceIndentCount = 0;
785
786 // finally, insert indentations into beginning of line
787
788 string indentedLine = preLineWS(indentCount, spaceIndentCount) + line;
789 indentedLine = getIndentedLineReturn(indentedLine, originalLine);
790
791 prevFinalLineSpaceIndentCount = spaceIndentCount;
792 prevFinalLineIndentCount = indentCount;
793
794 if (lastLineHeader != nullptr)
795 previousLastLineHeader = lastLineHeader;
796
797 if ((lineIsLineCommentOnly || lineIsCommentOnly)
798 && line.find("*INDENT-ON*", 0) != string::npos)
799 isIndentModeOff = false;
800
801 return indentedLine;
802}
803
804/**
805 * set indentation style to C/C++.
806 */
807void ASBeautifier::setCStyle()
808{
809 fileType = C_TYPE;
810}
811
812/**
813 * set indentation style to Java.
814 */
815void ASBeautifier::setJavaStyle()
816{
817 fileType = JAVA_TYPE;
818}
819
820/**
821 * set indentation style to C#.
822 */
823void ASBeautifier::setSharpStyle()
824{
825 fileType = SHARP_TYPE;
826}
827
828/**
829 * set mode manually set flag
830 */
831void ASBeautifier::setModeManuallySet(bool state)
832{
833 isModeManuallySet = state;
834}
835
836/**
837 * set tabLength equal to indentLength.
838 * This is done when tabLength is not explicitly set by
839 * "indent=force-tab-x"
840 *
841 */
842void ASBeautifier::setDefaultTabLength()
843{
844 tabLength = indentLength;
845}
846
847/**
848 * indent using a different tab setting for indent=force-tab
849 *
850 * @param length number of spaces per tab.
851 */
852void ASBeautifier::setForceTabXIndentation(int length)
853{
854 // set tabLength instead of indentLength
855 indentString = "\t";
856 tabLength = length;
857 shouldForceTabIndentation = true;
858}
859
860/**
861 * indent using one tab per indentation
862 */
863void ASBeautifier::setTabIndentation(int length, bool forceTabs)
864{
865 indentString = "\t";
866 indentLength = length;
867 shouldForceTabIndentation = forceTabs;
868}
869
870/**
871 * indent using a number of spaces per indentation.
872 *
873 * @param length number of spaces per indent.
874 */
875void ASBeautifier::setSpaceIndentation(int length)
876{
877 indentString = string(length, ' ');
878 indentLength = length;
879}
880
881/**
882* indent continuation lines using a number of indents.
883*
884* @param indent number of indents per line.
885*/
886void ASBeautifier::setContinuationIndentation(int indent)
887{
888 continuationIndent = indent;
889}
890
891/**
892 * set the maximum indentation between two lines in a multi-line statement.
893 *
894 * @param max maximum indentation length.
895 */
896void ASBeautifier::setMaxContinuationIndentLength(int max)
897{
898 maxContinuationIndent = max;
899}
900
901// retained for compatibility with release 2.06
902// "MaxInStatementIndent" has been changed to "MaxContinuationIndent" in 3.0
903// it is referenced only by the old "MaxInStatementIndent" options
904void ASBeautifier::setMaxInStatementIndentLength(int max)
905{
906 setMaxContinuationIndentLength(max);
907}
908
909/**
910 * set the minimum conditional indentation option.
911 *
912 * @param min minimal indentation option.
913 */
914void ASBeautifier::setMinConditionalIndentOption(int min)
915{
916 minConditionalOption = min;
917}
918
919/**
920 * set minConditionalIndent from the minConditionalOption.
921 */
922void ASBeautifier::setMinConditionalIndentLength()
923{
924 if (minConditionalOption == MINCOND_ZERO)
925 minConditionalIndent = 0;
926 else if (minConditionalOption == MINCOND_ONE)
927 minConditionalIndent = indentLength;
928 else if (minConditionalOption == MINCOND_ONEHALF)
929 minConditionalIndent = indentLength / 2;
930 // minConditionalOption = INDENT_TWO
931 else
932 minConditionalIndent = indentLength * 2;
933}
934
935/**
936 * set the state of the brace indent option. If true, braces will
937 * be indented one additional indent.
938 *
939 * @param state state of option.
940 */
941void ASBeautifier::setBraceIndent(bool state)
942{
943 braceIndent = state;
944}
945
946/**
947* set the state of the brace indent VTK option. If true, braces will
948* be indented one additional indent, except for the opening brace.
949*
950* @param state state of option.
951*/
952void ASBeautifier::setBraceIndentVtk(bool state)
953{
954 // need to set both of these
955 setBraceIndent(state);
956 braceIndentVtk = state;
957}
958
959/**
960 * set the state of the block indentation option. If true, entire blocks
961 * will be indented one additional indent, similar to the GNU indent style.
962 *
963 * @param state state of option.
964 */
965void ASBeautifier::setBlockIndent(bool state)
966{
967 blockIndent = state;
968}
969
970/**
971 * set the state of the class indentation option. If true, C++ class
972 * definitions will be indented one additional indent.
973 *
974 * @param state state of option.
975 */
976void ASBeautifier::setClassIndent(bool state)
977{
978 classIndent = state;
979}
980
981/**
982 * set the state of the modifier indentation option. If true, C++ class
983 * access modifiers will be indented one-half an indent.
984 *
985 * @param state state of option.
986 */
987void ASBeautifier::setModifierIndent(bool state)
988{
989 modifierIndent = state;
990}
991
992/**
993 * set the state of the switch indentation option. If true, blocks of 'switch'
994 * statements will be indented one additional indent.
995 *
996 * @param state state of option.
997 */
998void ASBeautifier::setSwitchIndent(bool state)
999{
1000 switchIndent = state;
1001}
1002
1003/**
1004 * set the state of the case indentation option. If true, lines of 'case'
1005 * statements will be indented one additional indent.
1006 *
1007 * @param state state of option.
1008 */
1009void ASBeautifier::setCaseIndent(bool state)
1010{
1011 caseIndent = state;
1012}
1013
1014/**
1015 * set the state of the namespace indentation option.
1016 * If true, blocks of 'namespace' statements will be indented one
1017 * additional indent. Otherwise, NO indentation will be added.
1018 *
1019 * @param state state of option.
1020 */
1021void ASBeautifier::setNamespaceIndent(bool state)
1022{
1023 namespaceIndent = state;
1024}
1025
1026/**
1027* set the state of the indent after parens option.
1028*
1029* @param state state of option.
1030*/
1031void ASBeautifier::setAfterParenIndent(bool state)
1032{
1033 shouldIndentAfterParen = state;
1034}
1035
1036/**
1037 * set the state of the label indentation option.
1038 * If true, labels will be indented one indent LESS than the
1039 * current indentation level.
1040 * If false, labels will be flushed to the left with NO
1041 * indent at all.
1042 *
1043 * @param state state of option.
1044 */
1045void ASBeautifier::setLabelIndent(bool state)
1046{
1047 labelIndent = state;
1048}
1049
1050/**
1051 * set the state of the preprocessor indentation option.
1052 * If true, multi-line #define statements will be indented.
1053 *
1054 * @param state state of option.
1055 */
1056void ASBeautifier::setPreprocDefineIndent(bool state)
1057{
1058 shouldIndentPreprocDefine = state;
1059}
1060
1061void ASBeautifier::setPreprocConditionalIndent(bool state)
1062{
1063 shouldIndentPreprocConditional = state;
1064}
1065
1066/**
1067 * set the state of the empty line fill option.
1068 * If true, empty lines will be filled with the whitespace.
1069 * of their previous lines.
1070 * If false, these lines will remain empty.
1071 *
1072 * @param state state of option.
1073 */
1074void ASBeautifier::setEmptyLineFill(bool state)
1075{
1076 emptyLineFill = state;
1077}
1078
1079void ASBeautifier::setAlignMethodColon(bool state)
1080{
1081 shouldAlignMethodColon = state;
1082}
1083
1084/**
1085 * get the file type.
1086 */
1087int ASBeautifier::getFileType() const
1088{
1089 return fileType;
1090}
1091
1092/**
1093 * get the number of spaces per indent
1094 *
1095 * @return value of indentLength option.
1096 */
1097int ASBeautifier::getIndentLength() const
1098{
1099 return indentLength;
1100}
1101
1102/**
1103 * get the char used for indentation, space or tab
1104 *
1105 * @return the char used for indentation.
1106 */
1107string ASBeautifier::getIndentString() const
1108{
1109 return indentString;
1110}
1111
1112/**
1113 * get mode manually set flag
1114 */
1115bool ASBeautifier::getModeManuallySet() const
1116{
1117 return isModeManuallySet;
1118}
1119
1120/**
1121 * get the state of the force tab indentation option.
1122 *
1123 * @return state of force tab indentation.
1124 */
1125bool ASBeautifier::getForceTabIndentation() const
1126{
1127 return shouldForceTabIndentation;
1128}
1129
1130/**
1131* Get the state of the Objective-C align method colon option.
1132*
1133* @return state of shouldAlignMethodColon option.
1134*/
1135bool ASBeautifier::getAlignMethodColon() const
1136{
1137 return shouldAlignMethodColon;
1138}
1139
1140/**
1141 * get the state of the block indentation option.
1142 *
1143 * @return state of blockIndent option.
1144 */
1145bool ASBeautifier::getBlockIndent() const
1146{
1147 return blockIndent;
1148}
1149
1150/**
1151 * get the state of the brace indentation option.
1152 *
1153 * @return state of braceIndent option.
1154 */
1155bool ASBeautifier::getBraceIndent() const
1156{
1157 return braceIndent;
1158}
1159
1160/**
1161* Get the state of the namespace indentation option. If true, blocks
1162* of the 'namespace' statement will be indented one additional indent.
1163*
1164* @return state of namespaceIndent option.
1165*/
1166bool ASBeautifier::getNamespaceIndent() const
1167{
1168 return namespaceIndent;
1169}
1170
1171/**
1172 * Get the state of the class indentation option. If true, blocks of
1173 * the 'class' statement will be indented one additional indent.
1174 *
1175 * @return state of classIndent option.
1176 */
1177bool ASBeautifier::getClassIndent() const
1178{
1179 return classIndent;
1180}
1181
1182/**
1183 * Get the state of the class access modifier indentation option.
1184 * If true, the class access modifiers will be indented one-half indent.
1185 *
1186 * @return state of modifierIndent option.
1187 */
1188bool ASBeautifier::getModifierIndent() const
1189{
1190 return modifierIndent;
1191}
1192
1193/**
1194 * get the state of the switch indentation option. If true, blocks of
1195 * the 'switch' statement will be indented one additional indent.
1196 *
1197 * @return state of switchIndent option.
1198 */
1199bool ASBeautifier::getSwitchIndent() const
1200{
1201 return switchIndent;
1202}
1203
1204/**
1205 * get the state of the case indentation option. If true, lines of 'case'
1206 * statements will be indented one additional indent.
1207 *
1208 * @return state of caseIndent option.
1209 */
1210bool ASBeautifier::getCaseIndent() const
1211{
1212 return caseIndent;
1213}
1214
1215/**
1216 * get the state of the empty line fill option.
1217 * If true, empty lines will be filled with the whitespace.
1218 * of their previous lines.
1219 * If false, these lines will remain empty.
1220 *
1221 * @return state of emptyLineFill option.
1222 */
1223bool ASBeautifier::getEmptyLineFill() const
1224{
1225 return emptyLineFill;
1226}
1227
1228/**
1229 * get the state of the preprocessor indentation option.
1230 * If true, preprocessor "define" lines will be indented.
1231 * If false, preprocessor "define" lines will be unchanged.
1232 *
1233 * @return state of shouldIndentPreprocDefine option.
1234 */
1235bool ASBeautifier::getPreprocDefineIndent() const
1236{
1237 return shouldIndentPreprocDefine;
1238}
1239
1240/**
1241 * get the length of the tab indentation option.
1242 *
1243 * @return length of tab indent option.
1244 */
1245int ASBeautifier::getTabLength() const
1246{
1247 return tabLength;
1248}
1249
1250const string& ASBeautifier::getIndentedLineReturn(const string& newLine, const string& originalLine) const
1251{
1252 if (isIndentModeOff)
1253 return originalLine;
1254 return newLine;
1255}
1256
1257string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCount) const
1258{
1259 if (shouldForceTabIndentation)
1260 {
1261 if (tabLength != indentLength)
1262 {
1263 // adjust for different tab length
1264 int indentCountOrig = lineIndentCount;
1265 int spaceIndentCountOrig = lineSpaceIndentCount;
1266 lineIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) / tabLength;
1267 lineSpaceIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) % tabLength;
1268 }
1269 else
1270 {
1271 lineIndentCount += lineSpaceIndentCount / indentLength;
1272 lineSpaceIndentCount = lineSpaceIndentCount % indentLength;
1273 }
1274 }
1275
1276 string ws;
1277 for (int i = 0; i < lineIndentCount; i++)
1278 ws += indentString;
1279 while ((lineSpaceIndentCount--) > 0)
1280 ws += string(" ");
1281 return ws;
1282}
1283
1284/**
1285 * register a continuation indent.
1286 */
1287void ASBeautifier::registerContinuationIndent(const string& line, int i, int spaceIndentCount_,
1288 int tabIncrementIn, int minIndent, bool updateParenStack)
1289{
1290 assert(i >= -1);
1291 int remainingCharNum = line.length() - i;
1292 int nextNonWSChar = getNextProgramCharDistance(line, i);
1293
1294 // if indent is around the last char in the line OR indent-after-paren is requested,
1295 // indent with the continuation indent
1296 if (nextNonWSChar == remainingCharNum || shouldIndentAfterParen)
1297 {
1298 int previousIndent = spaceIndentCount_;
1299 if (!continuationIndentStack->empty())
1300 previousIndent = continuationIndentStack->back();
1301 int currIndent = continuationIndent * indentLength + previousIndent;
1302 if (currIndent > maxContinuationIndent && line[i] != '{')
1303 currIndent = indentLength * 2 + spaceIndentCount_;
1304 continuationIndentStack->emplace_back(currIndent);
1305 if (updateParenStack)
1306 parenIndentStack->emplace_back(previousIndent);
1307 return;
1308 }
1309
1310 if (updateParenStack)
1311 {
1312 parenIndentStack->emplace_back(i + spaceIndentCount_ - runInIndentContinuation);
1313 if (parenIndentStack->back() < 0)
1314 parenIndentStack->back() = 0;
1315 }
1316
1317 int tabIncrement = tabIncrementIn;
1318
1319 // check for following tabs
1320 for (int j = i + 1; j < (i + nextNonWSChar); j++)
1321 {
1322 if (line[j] == '\t')
1323 tabIncrement += convertTabToSpaces(j, tabIncrement);
1324 }
1325
1326 int continuationIndentCount = i + nextNonWSChar + spaceIndentCount_ + tabIncrement;
1327
1328 // check for run-in statement
1329 if (i > 0 && line[0] == '{')
1330 continuationIndentCount -= indentLength;
1331
1332 if (continuationIndentCount < minIndent)
1333 continuationIndentCount = minIndent + spaceIndentCount_;
1334
1335 // this is not done for an in-statement array
1336 if (continuationIndentCount > maxContinuationIndent
1337 && !(prevNonLegalCh == '=' && currentNonLegalCh == '{'))
1338 continuationIndentCount = indentLength * 2 + spaceIndentCount_;
1339
1340 if (!continuationIndentStack->empty()
1341 && continuationIndentCount < continuationIndentStack->back())
1342 continuationIndentCount = continuationIndentStack->back();
1343
1344 // the block opener is not indented for a NonInStatementArray
1345 if ((isNonInStatementArray && i >= 0 && line[i] == '{')
1346 && !isInEnum && !braceBlockStateStack->empty() && braceBlockStateStack->back())
1347 continuationIndentCount = 0;
1348
1349 continuationIndentStack->emplace_back(continuationIndentCount);
1350}
1351
1352/**
1353* Register a continuation indent for a class header or a class initializer colon.
1354*/
1355void ASBeautifier::registerContinuationIndentColon(const string& line, int i, int tabIncrementIn)
1356{
1357 assert(line[i] == ':');
1358 assert(isInClassInitializer || isInClassHeaderTab);
1359
1360 // register indent at first word after the colon
1361 size_t firstChar = line.find_first_not_of(" \t");
1362 if (firstChar == (size_t) i) // firstChar is ':'
1363 {
1364 size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);
1365 if (firstWord != string::npos)
1366 {
1367 int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn;
1368 continuationIndentStack->emplace_back(continuationIndentCount);
1369 isContinuation = true;
1370 }
1371 }
1372}
1373
1374/**
1375 * Compute indentation for a preprocessor #if statement.
1376 * This may be called for the activeBeautiferStack
1377 * instead of the active ASBeautifier object.
1378 */
1379pair<int, int> ASBeautifier::computePreprocessorIndent()
1380{
1381 computePreliminaryIndentation();
1382 pair<int, int> entry(indentCount, spaceIndentCount);
1383 if (!headerStack->empty()
1384 && entry.first > 0
1385 && (headerStack->back() == &AS_IF
1386 || headerStack->back() == &AS_ELSE
1387 || headerStack->back() == &AS_FOR
1388 || headerStack->back() == &AS_WHILE))
1389 --entry.first;
1390 return entry;
1391}
1392
1393/**
1394 * get distance to the next non-white space, non-comment character in the line.
1395 * if no such character exists, return the length remaining to the end of the line.
1396 */
1397int ASBeautifier::getNextProgramCharDistance(const string& line, int i) const
1398{
1399 bool inComment = false;
1400 int remainingCharNum = line.length() - i;
1401 int charDistance;
1402 char ch = ' ';
1403
1404 for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
1405 {
1406 ch = line[i + charDistance];
1407 if (inComment)
1408 {
1409 if (line.compare(i + charDistance, 2, "*/") == 0)
1410 {
1411 charDistance++;
1412 inComment = false;
1413 }
1414 continue;
1415 }
1416 if (isWhiteSpace(ch))
1417 continue;
1418 if (ch == '/')
1419 {
1420 if (line.compare(i + charDistance, 2, "//") == 0)
1421 return remainingCharNum;
1422 if (line.compare(i + charDistance, 2, "/*") == 0)
1423 {
1424 charDistance++;
1425 inComment = true;
1426 }
1427 }
1428 else
1429 return charDistance;
1430 }
1431
1432 return charDistance;
1433}
1434
1435/**
1436 * find the index number of a string element in a container of strings
1437 *
1438 * @return the index number of element in the container. -1 if element not found.
1439 * @param container a vector of strings.
1440 * @param element the element to find .
1441 */
1442int ASBeautifier::indexOf(const vector<const string*>& container, const string* element) const
1443{
1444 vector<const string*>::const_iterator where;
1445
1446 where = find(container.begin(), container.end(), element);
1447 if (where == container.end())
1448 return -1;
1449 return (int) (where - container.begin());
1450}
1451
1452/**
1453 * convert tabs to spaces.
1454 * i is the position of the character to convert to spaces.
1455 * tabIncrementIn is the increment that must be added for tab indent characters
1456 * to get the correct column for the current tab.
1457 */
1458int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const
1459{
1460 int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength);
1461 return tabToSpacesAdjustment;
1462}
1463
1464/**
1465 * trim removes the white space surrounding a line.
1466 *
1467 * @return the trimmed line.
1468 * @param str the line to trim.
1469 */
1470string ASBeautifier::trim(const string& str) const
1471{
1472 int start = 0;
1473 int end = str.length() - 1;
1474
1475 while (start < end && isWhiteSpace(str[start]))
1476 start++;
1477
1478 while (start <= end && isWhiteSpace(str[end]))
1479 end--;
1480
1481 // don't trim if it ends in a continuation
1482 if (end > -1 && str[end] == '\\')
1483 end = str.length() - 1;
1484
1485 string returnStr(str, start, end + 1 - start);
1486 return returnStr;
1487}
1488
1489/**
1490 * rtrim removes the white space from the end of a line.
1491 *
1492 * @return the trimmed line.
1493 * @param str the line to trim.
1494 */
1495string ASBeautifier::rtrim(const string& str) const
1496{
1497 size_t len = str.length();
1498 size_t end = str.find_last_not_of(" \t");
1499 if (end == string::npos
1500 || end == len - 1)
1501 return str;
1502 string returnStr(str, 0, end + 1);
1503 return returnStr;
1504}
1505
1506/**
1507 * Copy tempStacks for the copy constructor.
1508 * The value of the vectors must also be copied.
1509 */
1510vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier& other) const
1511{
1512 vector<vector<const string*>*>* tempStacksNew = new vector<vector<const string*>*>;
1513 vector<vector<const string*>*>::iterator iter;
1514 for (iter = other.tempStacks->begin();
1515 iter != other.tempStacks->end();
1516 ++iter)
1517 {
1518 vector<const string*>* newVec = new vector<const string*>;
1519 *newVec = **iter;
1520 tempStacksNew->emplace_back(newVec);
1521 }
1522 return tempStacksNew;
1523}
1524
1525/**
1526 * delete a member vectors to eliminate memory leak reporting
1527 */
1528void ASBeautifier::deleteBeautifierVectors()
1529{
1530 beautifierFileType = 9; // reset to an invalid type
1531 delete headers;
1532 delete nonParenHeaders;
1533 delete preBlockStatements;
1534 delete preCommandHeaders;
1535 delete assignmentOperators;
1536 delete nonAssignmentOperators;
1537 delete indentableHeaders;
1538}
1539
1540/**
1541 * delete a vector object
1542 * T is the type of vector
1543 * used for all vectors except tempStacks
1544 */
1545template<typename T>
1546void ASBeautifier::deleteContainer(T& container)
1547{
1548 if (container != nullptr)
1549 {
1550 container->clear();
1551 delete (container);
1552 container = nullptr;
1553 }
1554}
1555
1556/**
1557 * Delete the ASBeautifier vector object.
1558 * This is a vector of pointers to ASBeautifier objects allocated with the 'new' operator.
1559 * Therefore the ASBeautifier objects have to be deleted in addition to the
1560 * ASBeautifier pointer entries.
1561 */
1562void ASBeautifier::deleteBeautifierContainer(vector<ASBeautifier*>*& container)
1563{
1564 if (container != nullptr)
1565 {
1566 vector<ASBeautifier*>::iterator iter = container->begin();
1567 while (iter < container->end())
1568 {
1569 delete *iter;
1570 ++iter;
1571 }
1572 container->clear();
1573 delete (container);
1574 container = nullptr;
1575 }
1576}
1577
1578/**
1579 * Delete the tempStacks vector object.
1580 * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
1581 * Therefore the strings have to be deleted in addition to the tempStacks entries.
1582 */
1583void ASBeautifier::deleteTempStacksContainer(vector<vector<const string*>*>*& container)
1584{
1585 if (container != nullptr)
1586 {
1587 vector<vector<const string*>*>::iterator iter = container->begin();
1588 while (iter < container->end())
1589 {
1590 delete *iter;
1591 ++iter;
1592 }
1593 container->clear();
1594 delete (container);
1595 container = nullptr;
1596 }
1597}
1598
1599/**
1600 * initialize a vector object
1601 * T is the type of vector used for all vectors
1602 */
1603template<typename T>
1604void ASBeautifier::initContainer(T& container, T value)
1605{
1606 // since the ASFormatter object is never deleted,
1607 // the existing vectors must be deleted before creating new ones
1608 if (container != nullptr)
1609 deleteContainer(container);
1610 container = value;
1611}
1612
1613/**
1614 * Initialize the tempStacks vector object.
1615 * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
1616 * Any residual entries are deleted before the vector is initialized.
1617 */
1618void ASBeautifier::initTempStacksContainer(vector<vector<const string*>*>*& container,
1619 vector<vector<const string*>*>* value)
1620{
1621 if (container != nullptr)
1622 deleteTempStacksContainer(container);
1623 container = value;
1624}
1625
1626/**
1627 * Determine if an assignment statement ends with a comma
1628 * that is not in a function argument. It ends with a
1629 * comma if a comma is the last char on the line.
1630 *
1631 * @return true if line ends with a comma, otherwise false.
1632 */
1633bool ASBeautifier::statementEndsWithComma(const string& line, int index) const
1634{
1635 assert(line[index] == '=');
1636
1637 bool isInComment_ = false;
1638 bool isInQuote_ = false;
1639 int parenCount = 0;
1640 size_t lineLength = line.length();
1641 size_t i = 0;
1642 char quoteChar_ = ' ';
1643
1644 for (i = index + 1; i < lineLength; ++i)
1645 {
1646 char ch = line[i];
1647
1648 if (isInComment_)
1649 {
1650 if (line.compare(i, 2, "*/") == 0)
1651 {
1652 isInComment_ = false;
1653 ++i;
1654 }
1655 continue;
1656 }
1657
1658 if (ch == '\\')
1659 {
1660 ++i;
1661 continue;
1662 }
1663
1664 if (isInQuote_)
1665 {
1666 if (ch == quoteChar_)
1667 isInQuote_ = false;
1668 continue;
1669 }
1670
1671 if (ch == '"'
1672 || (ch == '\'' && !isDigitSeparator(line, i)))
1673 {
1674 isInQuote_ = true;
1675 quoteChar_ = ch;
1676 continue;
1677 }
1678
1679 if (line.compare(i, 2, "//") == 0)
1680 break;
1681
1682 if (line.compare(i, 2, "/*") == 0)
1683 {
1684 if (isLineEndComment(line, i))
1685 break;
1686 isInComment_ = true;
1687 ++i;
1688 continue;
1689 }
1690
1691 if (ch == '(')
1692 parenCount++;
1693 if (ch == ')')
1694 parenCount--;
1695 }
1696 if (isInComment_
1697 || isInQuote_
1698 || parenCount > 0)
1699 return false;
1700
1701 size_t lastChar = line.find_last_not_of(" \t", i - 1);
1702
1703 if (lastChar == string::npos || line[lastChar] != ',')
1704 return false;
1705
1706 return true;
1707}
1708
1709/**
1710 * check if current comment is a line-end comment
1711 *
1712 * @return is before a line-end comment.
1713 */
1714bool ASBeautifier::isLineEndComment(const string& line, int startPos) const
1715{
1716 assert(line.compare(startPos, 2, "/*") == 0);
1717
1718 // comment must be closed on this line with nothing after it
1719 size_t endNum = line.find("*/", startPos + 2);
1720 if (endNum != string::npos)
1721 {
1722 size_t nextChar = line.find_first_not_of(" \t", endNum + 2);
1723 if (nextChar == string::npos)
1724 return true;
1725 }
1726 return false;
1727}
1728
1729/**
1730 * get the previous word index for an assignment operator
1731 *
1732 * @return is the index to the previous word (the in statement indent).
1733 */
1734int ASBeautifier::getContinuationIndentAssign(const string& line, size_t currPos) const
1735{
1736 assert(line[currPos] == '=');
1737
1738 if (currPos == 0)
1739 return 0;
1740
1741 // get the last legal word (may be a number)
1742 size_t end = line.find_last_not_of(" \t", currPos - 1);
1743 if (end == string::npos || !isLegalNameChar(line[end]))
1744 return 0;
1745
1746 int start; // start of the previous word
1747 for (start = end; start > -1; start--)
1748 {
1749 if (!isLegalNameChar(line[start]))
1750 break;
1751 }
1752 start++;
1753
1754 return start;
1755}
1756
1757/**
1758 * get the continuation indent for a comma
1759 *
1760 * @return is the indent to the second word on the line (the in statement indent).
1761 */
1762int ASBeautifier::getContinuationIndentComma(const string& line, size_t currPos) const
1763{
1764 assert(line[currPos] == ',');
1765
1766 // get first word on a line
1767 size_t indent = line.find_first_not_of(" \t");
1768 if (indent == string::npos || !isLegalNameChar(line[indent]))
1769 return 0;
1770
1771 // bypass first word
1772 for (; indent < currPos; indent++)
1773 {
1774 if (!isLegalNameChar(line[indent]))
1775 break;
1776 }
1777 indent++;
1778 if (indent >= currPos || indent < 4)
1779 return 0;
1780
1781 // point to second word or assignment operator
1782 indent = line.find_first_not_of(" \t", indent);
1783 if (indent == string::npos || indent >= currPos)
1784 return 0;
1785
1786 return indent;
1787}
1788
1789/**
1790 * get the next word on a line
1791 * the argument 'currPos' must point to the current position.
1792 *
1793 * @return is the next word or an empty string if none found.
1794 */
1795string ASBeautifier::getNextWord(const string& line, size_t currPos) const
1796{
1797 size_t lineLength = line.length();
1798 // get the last legal word (may be a number)
1799 if (currPos == lineLength - 1)
1800 return string();
1801
1802 size_t start = line.find_first_not_of(" \t", currPos + 1);
1803 if (start == string::npos || !isLegalNameChar(line[start]))
1804 return string();
1805
1806 size_t end; // end of the current word
1807 for (end = start + 1; end <= lineLength; end++)
1808 {
1809 if (!isLegalNameChar(line[end]) || line[end] == '.')
1810 break;
1811 }
1812
1813 return line.substr(start, end - start);
1814}
1815
1816/**
1817 * Check if a preprocessor directive is always indented.
1818 * C# "region" and "endregion" are always indented.
1819 * C/C++ "pragma omp" is always indented.
1820 *
1821 * @return is true or false.
1822 */
1823bool ASBeautifier::isIndentedPreprocessor(const string& line, size_t currPos) const
1824{
1825 assert(line[0] == '#');
1826 string nextWord = getNextWord(line, currPos);
1827 if (nextWord == "region" || nextWord == "endregion")
1828 return true;
1829 // is it #pragma omp
1830 if (nextWord == "pragma")
1831 {
1832 // find pragma
1833 size_t start = line.find("pragma");
1834 if (start == string::npos || !isLegalNameChar(line[start]))
1835 return false;
1836 // bypass pragma
1837 for (; start < line.length(); start++)
1838 {
1839 if (!isLegalNameChar(line[start]))
1840 break;
1841 }
1842 start++;
1843 if (start >= line.length())
1844 return false;
1845 // point to start of second word
1846 start = line.find_first_not_of(" \t", start);
1847 if (start == string::npos)
1848 return false;
1849 // point to end of second word
1850 size_t end;
1851 for (end = start; end < line.length(); end++)
1852 {
1853 if (!isLegalNameChar(line[end]))
1854 break;
1855 }
1856 // check for "pragma omp"
1857 string word = line.substr(start, end - start);
1858 if (word == "omp" || word == "region" || word == "endregion")
1859 return true;
1860 }
1861 return false;
1862}
1863
1864/**
1865 * Check if a preprocessor directive is checking for __cplusplus defined.
1866 *
1867 * @return is true or false.
1868 */
1869bool ASBeautifier::isPreprocessorConditionalCplusplus(const string& line) const
1870{
1871 string preproc = trim(line.substr(1));
1872 if (preproc.compare(0, 5, "ifdef") == 0 && getNextWord(preproc, 4) == "__cplusplus")
1873 return true;
1874 if (preproc.compare(0, 2, "if") == 0)
1875 {
1876 // check for " #if defined(__cplusplus)"
1877 size_t charNum = 2;
1878 charNum = preproc.find_first_not_of(" \t", charNum);
1879 if (charNum != string::npos && preproc.compare(charNum, 7, "defined") == 0)
1880 {
1881 charNum += 7;
1882 charNum = preproc.find_first_not_of(" \t", charNum);
1883 if (charNum != string::npos && preproc.compare(charNum, 1, "(") == 0)
1884 {
1885 ++charNum;
1886 charNum = preproc.find_first_not_of(" \t", charNum);
1887 if (charNum != string::npos && preproc.compare(charNum, 11, "__cplusplus") == 0)
1888 return true;
1889 }
1890 }
1891 }
1892 return false;
1893}
1894
1895/**
1896 * Check if a preprocessor definition contains an unterminated comment.
1897 * Comments within a preprocessor definition can be continued without the backslash.
1898 *
1899 * @return is true or false.
1900 */
1901bool ASBeautifier::isInPreprocessorUnterminatedComment(const string& line)
1902{
1903 if (!isInPreprocessorComment)
1904 {
1905 size_t startPos = line.find("/*");
1906 if (startPos == string::npos)
1907 return false;
1908 }
1909 size_t endNum = line.find("*/");
1910 if (endNum != string::npos)
1911 {
1912 isInPreprocessorComment = false;
1913 return false;
1914 }
1915 isInPreprocessorComment = true;
1916 return true;
1917}
1918
1919void ASBeautifier::popLastContinuationIndent()
1920{
1921 assert(!continuationIndentStackSizeStack->empty());
1922 int previousIndentStackSize = continuationIndentStackSizeStack->back();
1923 if (continuationIndentStackSizeStack->size() > 1)
1924 continuationIndentStackSizeStack->pop_back();
1925 while (previousIndentStackSize < (int) continuationIndentStack->size())
1926 continuationIndentStack->pop_back();
1927}
1928
1929// for unit testing
1930int ASBeautifier::getBeautifierFileType() const
1931{ return beautifierFileType; }
1932
1933/**
1934 * Process preprocessor statements and update the beautifier stacks.
1935 */
1936void ASBeautifier::processPreprocessor(const string& preproc, const string& line)
1937{
1938 // When finding a multi-lined #define statement, the original beautifier
1939 // 1. sets its isInDefineDefinition flag
1940 // 2. clones a new beautifier that will be used for the actual indentation
1941 // of the #define. This clone is put into the activeBeautifierStack in order
1942 // to be called for the actual indentation.
1943 // The original beautifier will have isInDefineDefinition = true, isInDefine = false
1944 // The cloned beautifier will have isInDefineDefinition = true, isInDefine = true
1945 if (shouldIndentPreprocDefine && preproc == "define" && line[line.length() - 1] == '\\')
1946 {
1947 if (!isInDefineDefinition)
1948 {
1949 // this is the original beautifier
1950 isInDefineDefinition = true;
1951
1952 // push a new beautifier into the active stack
1953 // this beautifier will be used for the indentation of this define
1954 ASBeautifier* defineBeautifier = new ASBeautifier(*this);
1955 activeBeautifierStack->emplace_back(defineBeautifier);
1956 }
1957 else
1958 {
1959 // the is the cloned beautifier that is in charge of indenting the #define.
1960 isInDefine = true;
1961 }
1962 }
1963 else if (preproc.length() >= 2 && preproc.substr(0, 2) == "if")
1964 {
1965 if (isPreprocessorConditionalCplusplus(line) && !g_preprocessorCppExternCBrace)
1966 g_preprocessorCppExternCBrace = 1;
1967 // push a new beautifier into the stack
1968 waitingBeautifierStackLengthStack->emplace_back(waitingBeautifierStack->size());
1969 activeBeautifierStackLengthStack->emplace_back(activeBeautifierStack->size());
1970 if (activeBeautifierStackLengthStack->back() == 0)
1971 waitingBeautifierStack->emplace_back(new ASBeautifier(*this));
1972 else
1973 waitingBeautifierStack->emplace_back(new ASBeautifier(*activeBeautifierStack->back()));
1974 }
1975 else if (preproc == "else")
1976 {
1977 if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
1978 {
1979 // MOVE current waiting beautifier to active stack.
1980 activeBeautifierStack->emplace_back(waitingBeautifierStack->back());
1981 waitingBeautifierStack->pop_back();
1982 }
1983 }
1984 else if (preproc == "elif")
1985 {
1986 if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
1987 {
1988 // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
1989 activeBeautifierStack->emplace_back(new ASBeautifier(*(waitingBeautifierStack->back())));
1990 }
1991 }
1992 else if (preproc == "endif")
1993 {
1994 int stackLength = 0;
1995 ASBeautifier* beautifier = nullptr;
1996
1997 if (waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty())
1998 {
1999 stackLength = waitingBeautifierStackLengthStack->back();
2000 waitingBeautifierStackLengthStack->pop_back();
2001 while ((int) waitingBeautifierStack->size() > stackLength)
2002 {
2003 beautifier = waitingBeautifierStack->back();
2004 waitingBeautifierStack->pop_back();
2005 delete beautifier;
2006 }
2007 }
2008
2009 if (!activeBeautifierStackLengthStack->empty())
2010 {
2011 stackLength = activeBeautifierStackLengthStack->back();
2012 activeBeautifierStackLengthStack->pop_back();
2013 while ((int) activeBeautifierStack->size() > stackLength)
2014 {
2015 beautifier = activeBeautifierStack->back();
2016 activeBeautifierStack->pop_back();
2017 delete beautifier;
2018 }
2019 }
2020 }
2021}
2022
2023// Compute the preliminary indentation based on data in the headerStack
2024// and data from previous lines.
2025// Update the class variable indentCount.
2026void ASBeautifier::computePreliminaryIndentation()
2027{
2028 indentCount = 0;
2029 spaceIndentCount = 0;
2030 isInClassHeaderTab = false;
2031
2032 if (isInObjCMethodDefinition && !continuationIndentStack->empty())
2033 spaceIndentObjCMethodAlignment = continuationIndentStack->back();
2034
2035 if (!continuationIndentStack->empty())
2036 spaceIndentCount = continuationIndentStack->back();
2037
2038 for (size_t i = 0; i < headerStack->size(); i++)
2039 {
2040 isInClass = false;
2041
2042 if (blockIndent)
2043 {
2044 // do NOT indent opening block for these headers
2045 if (!((*headerStack)[i] == &AS_NAMESPACE
2046 || (*headerStack)[i] == &AS_MODULE
2047 || (*headerStack)[i] == &AS_CLASS
2048 || (*headerStack)[i] == &AS_STRUCT
2049 || (*headerStack)[i] == &AS_UNION
2050 || (*headerStack)[i] == &AS_INTERFACE
2051 || (*headerStack)[i] == &AS_THROWS
2052 || (*headerStack)[i] == &AS_STATIC))
2053 ++indentCount;
2054 }
2055 else if (!(i > 0 && (*headerStack)[i - 1] != &AS_OPEN_BRACE
2056 && (*headerStack)[i] == &AS_OPEN_BRACE))
2057 ++indentCount;
2058
2059 if (!isJavaStyle() && !namespaceIndent && i > 0
2060 && ((*headerStack)[i - 1] == &AS_NAMESPACE
2061 || (*headerStack)[i - 1] == &AS_MODULE)
2062 && (*headerStack)[i] == &AS_OPEN_BRACE)
2063 --indentCount;
2064
2065 if (isCStyle() && i >= 1
2066 && (*headerStack)[i - 1] == &AS_CLASS
2067 && (*headerStack)[i] == &AS_OPEN_BRACE)
2068 {
2069 if (classIndent)
2070 ++indentCount;
2071 isInClass = true;
2072 }
2073
2074 // is the switchIndent option is on, indent switch statements an additional indent.
2075 else if (switchIndent && i > 1
2076 && (*headerStack)[i - 1] == &AS_SWITCH
2077 && (*headerStack)[i] == &AS_OPEN_BRACE)
2078 {
2079 ++indentCount;
2080 isInSwitch = true;
2081 }
2082
2083 } // end of for loop
2084
2085 if (isInClassHeader)
2086 {
2087 if (!isJavaStyle())
2088 isInClassHeaderTab = true;
2089 if (lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment)
2090 {
2091 if (!lineBeginsWithOpenBrace)
2092 --indentCount;
2093 if (!continuationIndentStack->empty())
2094 spaceIndentCount -= continuationIndentStack->back();
2095 }
2096 else if (blockIndent)
2097 {
2098 if (!lineBeginsWithOpenBrace)
2099 ++indentCount;
2100 }
2101 }
2102
2103 if (isInClassInitializer || isInEnumTypeID)
2104 {
2105 indentCount += classInitializerIndents;
2106 }
2107
2108 if (isInEnum && lineBeginsWithComma && !continuationIndentStack->empty())
2109 {
2110 // unregister '=' indent from the previous line
2111 continuationIndentStack->pop_back();
2112 isContinuation = false;
2113 spaceIndentCount = 0;
2114 }
2115
2116 // Objective-C interface continuation line
2117 if (isInObjCInterface)
2118 ++indentCount;
2119
2120 // unindent a class closing brace...
2121 if (!lineStartsInComment
2122 && isCStyle()
2123 && isInClass
2124 && classIndent
2125 && headerStack->size() >= 2
2126 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
2127 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
2128 && lineBeginsWithCloseBrace
2129 && braceBlockStateStack->back())
2130 --indentCount;
2131
2132 // unindent an indented switch closing brace...
2133 else if (!lineStartsInComment
2134 && isInSwitch
2135 && switchIndent
2136 && headerStack->size() >= 2
2137 && (*headerStack)[headerStack->size() - 2] == &AS_SWITCH
2138 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
2139 && lineBeginsWithCloseBrace)
2140 --indentCount;
2141
2142 // handle special case of run-in comment in an indented class statement
2143 if (isInClass
2144 && classIndent
2145 && isInRunInComment
2146 && !lineOpensWithComment
2147 && headerStack->size() > 1
2148 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS)
2149 --indentCount;
2150
2151 if (isInConditional)
2152 --indentCount;
2153 if (g_preprocessorCppExternCBrace >= 4)
2154 --indentCount;
2155}
2156
2157void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHeaderIndent)
2158{
2159 if (lineStartsInComment)
2160 return;
2161
2162 // unindent a one-line statement in a header indent
2163 if (!blockIndent
2164 && lineBeginsWithOpenBrace
2165 && headerStack->size() < iPrelim
2166 && isInExtraHeaderIndent
2167 && (lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2168 && shouldIndentBracedLine)
2169 --indentCount;
2170
2171 /*
2172 * if '{' doesn't follow an immediately previous '{' in the headerStack
2173 * (but rather another header such as "for" or "if", then unindent it
2174 * by one indentation relative to its block.
2175 */
2176 else if (!blockIndent
2177 && lineBeginsWithOpenBrace
2178 && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2179 && (headerStack->size() > 1 && (*headerStack)[headerStack->size() - 2] != &AS_OPEN_BRACE)
2180 && shouldIndentBracedLine)
2181 --indentCount;
2182
2183 // must check one less in headerStack if more than one header on a line (allow-addins)...
2184 else if (headerStack->size() > iPrelim + 1
2185 && !blockIndent
2186 && lineBeginsWithOpenBrace
2187 && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2188 && (headerStack->size() > 2 && (*headerStack)[headerStack->size() - 3] != &AS_OPEN_BRACE)
2189 && shouldIndentBracedLine)
2190 --indentCount;
2191
2192 // unindent a closing brace...
2193 else if (lineBeginsWithCloseBrace
2194 && shouldIndentBracedLine)
2195 --indentCount;
2196
2197 // correctly indent one-line-blocks...
2198 else if (lineOpeningBlocksNum > 0
2199 && lineOpeningBlocksNum == lineClosingBlocksNum
2200 && previousLineProbationTab)
2201 --indentCount;
2202
2203 if (indentCount < 0)
2204 indentCount = 0;
2205
2206 // take care of extra brace indentation option...
2207 if (!lineStartsInComment
2208 && braceIndent
2209 && shouldIndentBracedLine
2210 && (lineBeginsWithOpenBrace || lineBeginsWithCloseBrace))
2211 {
2212 if (!braceIndentVtk)
2213 ++indentCount;
2214 else
2215 {
2216 // determine if a style VTK brace is indented
2217 bool haveUnindentedBrace = false;
2218 for (size_t i = 0; i < headerStack->size(); i++)
2219 {
2220 if (((*headerStack)[i] == &AS_NAMESPACE
2221 || (*headerStack)[i] == &AS_MODULE
2222 || (*headerStack)[i] == &AS_CLASS
2223 || (*headerStack)[i] == &AS_STRUCT)
2224 && i + 1 < headerStack->size()
2225 && (*headerStack)[i + 1] == &AS_OPEN_BRACE)
2226 i++;
2227 else if (lineBeginsWithOpenBrace)
2228 {
2229 // don't double count the current brace
2230 if (i + 1 < headerStack->size()
2231 && (*headerStack)[i] == &AS_OPEN_BRACE)
2232 haveUnindentedBrace = true;
2233 }
2234 else if ((*headerStack)[i] == &AS_OPEN_BRACE)
2235 haveUnindentedBrace = true;
2236 } // end of for loop
2237 if (haveUnindentedBrace)
2238 ++indentCount;
2239 }
2240 }
2241}
2242
2243/**
2244 * Compute indentCount adjustment when in a series of else-if statements
2245 * and shouldBreakElseIfs is requested.
2246 * It increments by one for each 'else' in the tempStack.
2247 */
2248int ASBeautifier::adjustIndentCountForBreakElseIfComments() const
2249{
2250 assert(isElseHeaderIndent && !tempStacks->empty());
2251 int indentCountIncrement = 0;
2252 vector<const string*>* lastTempStack = tempStacks->back();
2253 if (lastTempStack != nullptr)
2254 {
2255 for (const string* const lastTemp : *lastTempStack)
2256 {
2257 if (*lastTemp == AS_ELSE)
2258 indentCountIncrement++;
2259 }
2260 }
2261 return indentCountIncrement;
2262}
2263
2264/**
2265 * Extract a preprocessor statement without the #.
2266 * If a error occurs an empty string is returned.
2267 */
2268string ASBeautifier::extractPreprocessorStatement(const string& line) const
2269{
2270 string preproc;
2271 size_t start = line.find_first_not_of("#/ \t");
2272 if (start == string::npos)
2273 return preproc;
2274 size_t end = line.find_first_of("/ \t", start);
2275 if (end == string::npos)
2276 end = line.length();
2277 preproc = line.substr(start, end - start);
2278 return preproc;
2279}
2280
2281void ASBeautifier::adjustObjCMethodDefinitionIndentation(const string& line_)
2282{
2283 // register indent for Objective-C continuation line
2284 if (line_.length() > 0
2285 && (line_[0] == '-' || line_[0] == '+'))
2286 {
2287 if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
2288 {
2289 string convertedLine = getIndentedSpaceEquivalent(line_);
2290 colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine);
2291 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
2292 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
2293 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
2294 }
2295 else if (continuationIndentStack->empty()
2296 || continuationIndentStack->back() == 0)
2297 {
2298 continuationIndentStack->emplace_back(indentLength);
2299 isContinuation = true;
2300 }
2301 }
2302 // set indent for last definition line
2303 else if (!lineBeginsWithOpenBrace)
2304 {
2305 if (shouldAlignMethodColon)
2306 spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
2307 else if (continuationIndentStack->empty())
2308 spaceIndentCount = spaceIndentObjCMethodAlignment;
2309 }
2310}
2311
2312void ASBeautifier::adjustObjCMethodCallIndentation(const string& line_)
2313{
2314 static int keywordIndentObjCMethodAlignment = 0;
2315 if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
2316 {
2317 if (isInObjCMethodCallFirst)
2318 {
2319 isInObjCMethodCallFirst = false;
2320 string convertedLine = getIndentedSpaceEquivalent(line_);
2321 bracePosObjCMethodAlignment = convertedLine.find('[');
2322 keywordIndentObjCMethodAlignment =
2323 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
2324 colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine);
2325 if (colonIndentObjCMethodAlignment >= 0)
2326 {
2327 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
2328 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
2329 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
2330 if (lineBeginsWithOpenBrace)
2331 colonIndentObjCMethodAlignment -= indentLength;
2332 }
2333 }
2334 else
2335 {
2336 if (findObjCColonAlignment(line_) != -1)
2337 {
2338 if (colonIndentObjCMethodAlignment < 0)
2339 spaceIndentCount += computeObjCColonAlignment(line_, objCColonAlignSubsequent);
2340 else if (objCColonAlignSubsequent > colonIndentObjCMethodAlignment)
2341 spaceIndentCount = computeObjCColonAlignment(line_, objCColonAlignSubsequent);
2342 else
2343 spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
2344 }
2345 else
2346 {
2347 if (spaceIndentCount < colonIndentObjCMethodAlignment)
2348 spaceIndentCount += keywordIndentObjCMethodAlignment;
2349 }
2350 }
2351 }
2352 else // align keywords instead of colons
2353 {
2354 if (isInObjCMethodCallFirst)
2355 {
2356 isInObjCMethodCallFirst = false;
2357 string convertedLine = getIndentedSpaceEquivalent(line_);
2358 bracePosObjCMethodAlignment = convertedLine.find('[');
2359 keywordIndentObjCMethodAlignment =
2360 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
2361 }
2362 else
2363 {
2364 if (spaceIndentCount < keywordIndentObjCMethodAlignment + bracePosObjCMethodAlignment)
2365 spaceIndentCount += keywordIndentObjCMethodAlignment;
2366 }
2367 }
2368}
2369
2370/**
2371 * Clear the variables used to align the Objective-C method definitions.
2372 */
2373void ASBeautifier::clearObjCMethodDefinitionAlignment()
2374{
2375 assert(isImmediatelyPostObjCMethodDefinition);
2376 spaceIndentCount = 0;
2377 spaceIndentObjCMethodAlignment = 0;
2378 colonIndentObjCMethodAlignment = 0;
2379 isInObjCMethodDefinition = false;
2380 isImmediatelyPostObjCMethodDefinition = false;
2381 if (!continuationIndentStack->empty())
2382 continuationIndentStack->pop_back();
2383}
2384
2385/**
2386 * Find the first alignment colon on a line.
2387 * Ternary operators (?) are bypassed.
2388 */
2389int ASBeautifier::findObjCColonAlignment(const string& line) const
2390{
2391 bool haveTernary = false;
2392 for (size_t i = 0; i < line.length(); i++)
2393 {
2394 i = line.find_first_of(":?", i);
2395 if (i == string::npos)
2396 break;
2397
2398 if (line[i] == '?')
2399 {
2400 haveTernary = true;
2401 continue;
2402 }
2403 if (haveTernary)
2404 {
2405 haveTernary = false;
2406 continue;
2407 }
2408 return i;
2409 }
2410 return -1;
2411}
2412
2413/**
2414 * Compute the spaceIndentCount necessary to align the current line colon
2415 * with the colon position in the argument.
2416 * If it cannot be aligned indentLength is returned and a new colon
2417 * position is calculated.
2418 */
2419int ASBeautifier::computeObjCColonAlignment(const string& line, int colonAlignPosition) const
2420{
2421 int colonPosition = findObjCColonAlignment(line);
2422 if (colonPosition < 0 || colonPosition > colonAlignPosition)
2423 return indentLength;
2424 return (colonAlignPosition - colonPosition);
2425}
2426
2427/*
2428 * Compute position of the keyword following the method call object.
2429 * This is oversimplified to find unusual method calls.
2430 * Use for now and see what happens.
2431 * Most programmers will probably use align-method-colon anyway.
2432 */
2433int ASBeautifier::getObjCFollowingKeyword(const string& line, int bracePos) const
2434{
2435 assert(line[bracePos] == '[');
2436 size_t firstText = line.find_first_not_of(" \t", bracePos + 1);
2437 if (firstText == string::npos)
2438 return -(indentCount * indentLength - 1);
2439 size_t searchBeg = firstText;
2440 size_t objectEnd = 0; // end of object text
2441 if (line[searchBeg] == '[')
2442 {
2443 objectEnd = line.find(']', searchBeg + 1);
2444 if (objectEnd == string::npos)
2445 return 0;
2446 }
2447 else
2448 {
2449 if (line[searchBeg] == '(')
2450 {
2451 searchBeg = line.find(')', searchBeg + 1);
2452 if (searchBeg == string::npos)
2453 return 0;
2454 }
2455 // bypass the object name
2456 objectEnd = line.find_first_of(" \t", searchBeg + 1);
2457 if (objectEnd == string::npos)
2458 return 0;
2459 --objectEnd;
2460 }
2461 size_t keyPos = line.find_first_not_of(" \t", objectEnd + 1);
2462 if (keyPos == string::npos)
2463 return 0;
2464 return keyPos - firstText;
2465}
2466
2467/**
2468 * Get a line using the current space indent with all tabs replaced by spaces.
2469 * The indentCount is NOT included
2470 * Needed to compute an accurate alignment.
2471 */
2472string ASBeautifier::getIndentedSpaceEquivalent(const string& line_) const
2473{
2474 string spaceIndent;
2475 spaceIndent.append(spaceIndentCount, ' ');
2476 string convertedLine = spaceIndent + line_;
2477 for (size_t i = spaceIndent.length(); i < convertedLine.length(); i++)
2478 {
2479 if (convertedLine[i] == '\t')
2480 {
2481 size_t numSpaces = indentLength - (i % indentLength);
2482 convertedLine.replace(i, 1, numSpaces, ' ');
2483 i += indentLength - 1;
2484 }
2485 }
2486 return convertedLine;
2487}
2488
2489/**
2490 * Determine if an item is at a top level.
2491 */
2492bool ASBeautifier::isTopLevel() const
2493{
2494 if (headerStack->empty())
2495 return true;
2496 if (headerStack->back() == &AS_OPEN_BRACE
2497 && headerStack->size() >= 2)
2498 {
2499 if ((*headerStack)[headerStack->size() - 2] == &AS_NAMESPACE
2500 || (*headerStack)[headerStack->size() - 2] == &AS_MODULE
2501 || (*headerStack)[headerStack->size() - 2] == &AS_CLASS
2502 || (*headerStack)[headerStack->size() - 2] == &AS_INTERFACE
2503 || (*headerStack)[headerStack->size() - 2] == &AS_STRUCT
2504 || (*headerStack)[headerStack->size() - 2] == &AS_UNION)
2505 return true;
2506 }
2507 if (headerStack->back() == &AS_NAMESPACE
2508 || headerStack->back() == &AS_MODULE
2509 || headerStack->back() == &AS_CLASS
2510 || headerStack->back() == &AS_INTERFACE
2511 || headerStack->back() == &AS_STRUCT
2512 || headerStack->back() == &AS_UNION)
2513 return true;
2514 return false;
2515}
2516
2517/**
2518 * Parse the current line to update indentCount and spaceIndentCount.
2519 */
2520void ASBeautifier::parseCurrentLine(const string& line)
2521{
2522 bool isInLineComment = false;
2523 bool isInOperator = false;
2524 bool isSpecialChar = false;
2525 bool haveCaseIndent = false;
2526 bool haveAssignmentThisLine = false;
2527 bool closingBraceReached = false;
2528 bool previousLineProbation = (probationHeader != nullptr);
2529 char ch = ' ';
2530 int tabIncrementIn = 0;
2531 if (isInQuote
2532 && !haveLineContinuationChar
2533 && !isInVerbatimQuote
2534 && !isInAsm)
2535 isInQuote = false; // missing closing quote
2536 haveLineContinuationChar = false;
2537
2538 for (size_t i = 0; i < line.length(); i++)
2539 {
2540 ch = line[i];
2541
2542 if (isInBeautifySQL)
2543 continue;
2544
2545 // handle special characters (i.e. backslash+character such as \n, \t, ...)
2546 if (isInQuote && !isInVerbatimQuote)
2547 {
2548 if (isSpecialChar)
2549 {
2550 isSpecialChar = false;
2551 continue;
2552 }
2553 if (line.compare(i, 2, "\\\\") == 0)
2554 {
2555 i++;
2556 continue;
2557 }
2558 if (ch == '\\')
2559 {
2560 if (peekNextChar(line, i) == ' ') // is this '\' at end of line
2561 haveLineContinuationChar = true;
2562 else
2563 isSpecialChar = true;
2564 continue;
2565 }
2566 }
2567 else if (isInDefine && ch == '\\')
2568 continue;
2569
2570 // bypass whitespace here
2571 if (isWhiteSpace(ch))
2572 {
2573 if (ch == '\t')
2574 tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
2575 continue;
2576 }
2577
2578 // handle quotes (such as 'x' and "Hello Dolly")
2579 if (!(isInComment || isInLineComment)
2580 && (ch == '"'
2581 || (ch == '\'' && !isDigitSeparator(line, i))))
2582 {
2583 if (!isInQuote)
2584 {
2585 quoteChar = ch;
2586 isInQuote = true;
2587 char prevCh = i > 0 ? line[i - 1] : ' ';
2588 if (isCStyle() && prevCh == 'R')
2589 {
2590 int parenPos = line.find('(', i);
2591 if (parenPos != -1)
2592 {
2593 isInVerbatimQuote = true;
2594 verbatimDelimiter = line.substr(i + 1, parenPos - i - 1);
2595 }
2596 }
2597 else if (isSharpStyle() && prevCh == '@')
2598 isInVerbatimQuote = true;
2599 // check for "C" following "extern"
2600 else if (g_preprocessorCppExternCBrace == 2 && line.compare(i, 3, "\"C\"") == 0)
2601 ++g_preprocessorCppExternCBrace;
2602 }
2603 else if (isInVerbatimQuote && ch == '"')
2604 {
2605 if (isCStyle())
2606 {
2607 string delim = ')' + verbatimDelimiter;
2608 int delimStart = i - delim.length();
2609 if (delimStart >= 0 && line.substr(delimStart, delim.length()) == delim)
2610 {
2611 isInQuote = false;
2612 isInVerbatimQuote = false;
2613 }
2614 }
2615 else if (isSharpStyle())
2616 {
2617 if (line.compare(i, 2, "\"\"") == 0)
2618 i++;
2619 else
2620 {
2621 isInQuote = false;
2622 isInVerbatimQuote = false;
2623 continue;
2624 }
2625 }
2626 }
2627 else if (quoteChar == ch)
2628 {
2629 isInQuote = false;
2630 isContinuation = true;
2631 continue;
2632 }
2633 }
2634 if (isInQuote)
2635 continue;
2636
2637 // handle comments
2638
2639 if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
2640 {
2641 // if there is a 'case' statement after these comments unindent by 1
2642 if (isCaseHeaderCommentIndent)
2643 --indentCount;
2644 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2645 // if there is an 'else' after these comments a tempStacks indent is required
2646 if (isElseHeaderIndent && lineOpensWithLineComment && !tempStacks->empty())
2647 indentCount += adjustIndentCountForBreakElseIfComments();
2648 isInLineComment = true;
2649 i++;
2650 continue;
2651 }
2652 if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
2653 {
2654 // if there is a 'case' statement after these comments unindent by 1
2655 if (isCaseHeaderCommentIndent && lineOpensWithComment)
2656 --indentCount;
2657 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2658 // if there is an 'else' after these comments a tempStacks indent is required
2659 if (isElseHeaderIndent && lineOpensWithComment && !tempStacks->empty())
2660 indentCount += adjustIndentCountForBreakElseIfComments();
2661 isInComment = true;
2662 i++;
2663 if (!lineOpensWithComment) // does line start with comment?
2664 blockCommentNoIndent = true; // if no, cannot indent continuation lines
2665 continue;
2666 }
2667 if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
2668 {
2669 size_t firstText = line.find_first_not_of(" \t");
2670 // if there is a 'case' statement after these comments unindent by 1
2671 // only if the ending comment is the first entry on the line
2672 if (isCaseHeaderCommentIndent && firstText == i)
2673 --indentCount;
2674 // if this comment close starts the line, must check for else-if indent
2675 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2676 // if there is an 'else' after these comments a tempStacks indent is required
2677 if (firstText == i)
2678 {
2679 if (isElseHeaderIndent && !lineOpensWithComment && !tempStacks->empty())
2680 indentCount += adjustIndentCountForBreakElseIfComments();
2681 }
2682 isInComment = false;
2683 i++;
2684 blockCommentNoIndent = false; // ok to indent next comment
2685 continue;
2686 }
2687 // treat indented preprocessor lines as a line comment
2688 if (line[0] == '#' && isIndentedPreprocessor(line, i))
2689 {
2690 isInLineComment = true;
2691 }
2692
2693 if (isInLineComment)
2694 {
2695 // bypass rest of the comment up to the comment end
2696 while (i + 1 < line.length())
2697 i++;
2698
2699 continue;
2700 }
2701 if (isInComment)
2702 {
2703 // if there is a 'case' statement after these comments unindent by 1
2704 if (!lineOpensWithComment && isCaseHeaderCommentIndent)
2705 --indentCount;
2706 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2707 // if there is an 'else' after these comments a tempStacks indent is required
2708 if (!lineOpensWithComment && isElseHeaderIndent && !tempStacks->empty())
2709 indentCount += adjustIndentCountForBreakElseIfComments();
2710 // bypass rest of the comment up to the comment end
2711 while (i + 1 < line.length()
2712 && line.compare(i + 1, 2, "*/") != 0)
2713 i++;
2714
2715 continue;
2716 }
2717
2718 // if we have reached this far then we are NOT in a comment or string of special character...
2719
2720 if (probationHeader != nullptr)
2721 {
2722 if ((probationHeader == &AS_STATIC && ch == '{')
2723 || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
2724 {
2725 // insert the probation header as a new header
2726 isInHeader = true;
2727 headerStack->emplace_back(probationHeader);
2728
2729 // handle the specific probation header
2730 isInConditional = (probationHeader == &AS_SYNCHRONIZED);
2731
2732 isContinuation = false;
2733 // if the probation comes from the previous line, then indent by 1 tab count.
2734 if (previousLineProbation
2735 && ch == '{'
2736 && !(blockIndent && probationHeader == &AS_STATIC))
2737 {
2738 ++indentCount;
2739 previousLineProbationTab = true;
2740 }
2741 previousLineProbation = false;
2742 }
2743
2744 // dismiss the probation header
2745 probationHeader = nullptr;
2746 }
2747
2748 prevNonSpaceCh = currentNonSpaceCh;
2749 currentNonSpaceCh = ch;
2750 if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
2751 {
2752 prevNonLegalCh = currentNonLegalCh;
2753 currentNonLegalCh = ch;
2754 }
2755
2756 if (isInHeader)
2757 {
2758 isInHeader = false;
2759 currentHeader = headerStack->back();
2760 }
2761 else
2762 currentHeader = nullptr;
2763
2764 if (isCStyle() && isInTemplate
2765 && (ch == '<' || ch == '>')
2766 && !(line.length() > i + 1 && line.compare(i, 2, ">=") == 0))
2767 {
2768 if (ch == '<')
2769 {
2770 ++templateDepth;
2771 continuationIndentStackSizeStack->emplace_back(continuationIndentStack->size());
2772 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2773 }
2774 else if (ch == '>')
2775 {
2776 popLastContinuationIndent();
2777 if (--templateDepth <= 0)
2778 {
2779 ch = ';';
2780 isInTemplate = false;
2781 templateDepth = 0;
2782 }
2783 }
2784 }
2785
2786 // handle parentheses
2787 if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
2788 {
2789 if (ch == '(' || ch == '[')
2790 {
2791 isInOperator = false;
2792 // if have a struct header, this is a declaration not a definition
2793 if (ch == '('
2794 && !headerStack->empty()
2795 && headerStack->back() == &AS_STRUCT)
2796 {
2797 headerStack->pop_back();
2798 isInClassHeader = false;
2799 if (line.find(AS_STRUCT, 0) > i) // if not on this line
2800 indentCount -= classInitializerIndents;
2801 if (indentCount < 0)
2802 indentCount = 0;
2803 }
2804
2805 if (parenDepth == 0)
2806 {
2807 // do not use emplace_back on vector<bool> until supported by macOS
2808 parenStatementStack->push_back(isContinuation);
2809 isContinuation = true;
2810 }
2811 parenDepth++;
2812 if (ch == '[')
2813 {
2814 ++squareBracketCount;
2815 if (squareBracketCount == 1 && isCStyle())
2816 {
2817 isInObjCMethodCall = true;
2818 isInObjCMethodCallFirst = true;
2819 }
2820 }
2821
2822 continuationIndentStackSizeStack->emplace_back(continuationIndentStack->size());
2823
2824 if (currentHeader != nullptr)
2825 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent, true);
2826 else if (!isInObjCMethodDefinition)
2827 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2828 }
2829 else if (ch == ')' || ch == ']')
2830 {
2831 if (ch == ']')
2832 --squareBracketCount;
2833 if (squareBracketCount <= 0)
2834 {
2835 squareBracketCount = 0;
2836 if (isInObjCMethodCall)
2837 isImmediatelyPostObjCMethodCall = true;
2838 }
2839 foundPreCommandHeader = false;
2840 parenDepth--;
2841 if (parenDepth == 0)
2842 {
2843 if (!parenStatementStack->empty()) // in case of unmatched closing parens
2844 {
2845 isContinuation = parenStatementStack->back();
2846 parenStatementStack->pop_back();
2847 }
2848 isInAsm = false;
2849 isInConditional = false;
2850 }
2851
2852 if (!continuationIndentStackSizeStack->empty())
2853 {
2854 popLastContinuationIndent();
2855
2856 if (!parenIndentStack->empty())
2857 {
2858 int poppedIndent = parenIndentStack->back();
2859 parenIndentStack->pop_back();
2860
2861 if (i == 0)
2862 spaceIndentCount = poppedIndent;
2863 }
2864 }
2865 }
2866 continue;
2867 }
2868
2869 if (ch == '{')
2870 {
2871 // first, check if '{' is a block-opener or a static-array opener
2872 bool isBlockOpener = ((prevNonSpaceCh == '{' && braceBlockStateStack->back())
2873 || prevNonSpaceCh == '}'
2874 || prevNonSpaceCh == ')'
2875 || prevNonSpaceCh == ';'
2876 || peekNextChar(line, i) == '{'
2877 || isInTrailingReturnType
2878 || foundPreCommandHeader
2879 || foundPreCommandMacro
2880 || isInClassHeader
2881 || (isInClassInitializer && !isLegalNameChar(prevNonSpaceCh))
2882 || isNonInStatementArray
2883 || isInObjCMethodDefinition
2884 || isInObjCInterface
2885 || isSharpAccessor
2886 || isSharpDelegate
2887 || isInExternC
2888 || isInAsmBlock
2889 || getNextWord(line, i) == AS_NEW
2890 || (isInDefine
2891 && (prevNonSpaceCh == '('
2892 || isLegalNameChar(prevNonSpaceCh))));
2893
2894 if (isInObjCMethodDefinition)
2895 {
2896 objCColonAlignSubsequent = 0;
2897 isImmediatelyPostObjCMethodDefinition = true;
2898 if (lineBeginsWithOpenBrace) // for run-in braces
2899 clearObjCMethodDefinitionAlignment();
2900 }
2901
2902 if (!isBlockOpener && !isContinuation && !isInClassInitializer && !isInEnum)
2903 {
2904 if (isTopLevel())
2905 isBlockOpener = true;
2906 }
2907
2908 if (!isBlockOpener && currentHeader != nullptr)
2909 {
2910 for (const string* const nonParenHeader : *nonParenHeaders)
2911 if (currentHeader == nonParenHeader)
2912 {
2913 isBlockOpener = true;
2914 break;
2915 }
2916 }
2917
2918 // do not use emplace_back on vector<bool> until supported by macOS
2919 braceBlockStateStack->push_back(isBlockOpener);
2920
2921 if (!isBlockOpener)
2922 {
2923 continuationIndentStackSizeStack->emplace_back(continuationIndentStack->size());
2924 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2925 parenDepth++;
2926 if (i == 0)
2927 shouldIndentBracedLine = false;
2928 isInEnumTypeID = false;
2929
2930 continue;
2931 }
2932
2933 // this brace is a block opener...
2934
2935 ++lineOpeningBlocksNum;
2936
2937 if (isInClassInitializer || isInEnumTypeID)
2938 {
2939 // decrease tab count if brace is broken
2940 if (lineBeginsWithOpenBrace)
2941 {
2942 indentCount -= classInitializerIndents;
2943 // decrease one more if an empty class
2944 if (!headerStack->empty()
2945 && (*headerStack).back() == &AS_CLASS)
2946 {
2947 int nextChar = getNextProgramCharDistance(line, i);
2948 if ((int) line.length() > nextChar && line[nextChar] == '}')
2949 --indentCount;
2950 }
2951 }
2952 }
2953
2954 if (isInObjCInterface)
2955 {
2956 isInObjCInterface = false;
2957 if (lineBeginsWithOpenBrace)
2958 --indentCount;
2959 }
2960
2961 if (braceIndent && !namespaceIndent && !headerStack->empty()
2962 && ((*headerStack).back() == &AS_NAMESPACE
2963 || (*headerStack).back() == &AS_MODULE))
2964 {
2965 shouldIndentBracedLine = false;
2966 --indentCount;
2967 }
2968
2969 // an indentable struct is treated like a class in the header stack
2970 if (!headerStack->empty()
2971 && (*headerStack).back() == &AS_STRUCT
2972 && isInIndentableStruct)
2973 (*headerStack).back() = &AS_CLASS;
2974
2975 // is a brace inside a paren?
2976 parenDepthStack->emplace_back(parenDepth);
2977 // do not use emplace_back on vector<bool> until supported by macOS
2978 blockStatementStack->push_back(isContinuation);
2979
2980 if (!continuationIndentStack->empty())
2981 {
2982 // completely purge the continuationIndentStack
2983 while (!continuationIndentStack->empty())
2984 popLastContinuationIndent();
2985 if (isInClassInitializer || isInClassHeaderTab)
2986 {
2987 if (lineBeginsWithOpenBrace || lineBeginsWithComma)
2988 spaceIndentCount = 0;
2989 }
2990 else
2991 spaceIndentCount = 0;
2992 }
2993
2994 blockTabCount += (isContinuation ? 1 : 0);
2995 if (g_preprocessorCppExternCBrace == 3)
2996 ++g_preprocessorCppExternCBrace;
2997 parenDepth = 0;
2998 isInTrailingReturnType = false;
2999 isInClassHeader = false;
3000 isInClassHeaderTab = false;
3001 isInClassInitializer = false;
3002 isInEnumTypeID = false;
3003 isContinuation = false;
3004 isInQuestion = false;
3005 isInLet = false;
3006 foundPreCommandHeader = false;
3007 foundPreCommandMacro = false;
3008 isInExternC = false;
3009
3010 tempStacks->emplace_back(new vector<const string*>);
3011 headerStack->emplace_back(&AS_OPEN_BRACE);
3012 lastLineHeader = &AS_OPEN_BRACE;
3013
3014 continue;
3015 } // end '{'
3016
3017 //check if a header has been reached
3018 bool isPotentialHeader = isCharPotentialHeader(line, i);
3019
3020 if (isPotentialHeader && squareBracketCount == 0)
3021 {
3022 const string* newHeader = findHeader(line, i, headers);
3023
3024 // java can have a 'default' not in a switch
3025 if (newHeader == &AS_DEFAULT
3026 && peekNextChar(line, (i + (*newHeader).length() - 1)) != ':')
3027 newHeader = nullptr;
3028 // Qt headers may be variables in C++
3029 if (isCStyle()
3030 && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
3031 {
3032 if (line.find_first_of("=;", i) != string::npos)
3033 newHeader = nullptr;
3034 }
3035 else if (isSharpStyle()
3036 && (newHeader == &AS_GET || newHeader == &AS_SET))
3037 {
3038 if (getNextWord(line, i + (*newHeader).length()) == "is")
3039 newHeader = nullptr;
3040 }
3041 else if (newHeader == &AS_USING
3042 && peekNextChar(line, i + (*newHeader).length() - 1) != '(')
3043 newHeader = nullptr;
3044
3045 if (newHeader != nullptr)
3046 {
3047 // if we reached here, then this is a header...
3048 bool isIndentableHeader = true;
3049
3050 isInHeader = true;
3051
3052 vector<const string*>* lastTempStack = nullptr;
3053 if (!tempStacks->empty())
3054 lastTempStack = tempStacks->back();
3055
3056 // if a new block is opened, push a new stack into tempStacks to hold the
3057 // future list of headers in the new block.
3058
3059 // take care of the special case: 'else if (...)'
3060 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
3061 {
3062 if (!headerStack->empty())
3063 headerStack->pop_back();
3064 }
3065
3066 // take care of 'else'
3067 else if (newHeader == &AS_ELSE)
3068 {
3069 if (lastTempStack != nullptr)
3070 {
3071 int indexOfIf = indexOf(*lastTempStack, &AS_IF);
3072 if (indexOfIf != -1)
3073 {
3074 // recreate the header list in headerStack up to the previous 'if'
3075 // from the temporary snapshot stored in lastTempStack.
3076 int restackSize = lastTempStack->size() - indexOfIf - 1;
3077 for (int r = 0; r < restackSize; r++)
3078 {
3079 headerStack->emplace_back(lastTempStack->back());
3080 lastTempStack->pop_back();
3081 }
3082 if (!closingBraceReached)
3083 indentCount += restackSize;
3084 }
3085 /*
3086 * If the above if is not true, i.e. no 'if' before the 'else',
3087 * then nothing beautiful will come out of this...
3088 * I should think about inserting an Exception here to notify the caller of this...
3089 */
3090 }
3091 }
3092
3093 // check if 'while' closes a previous 'do'
3094 else if (newHeader == &AS_WHILE)
3095 {
3096 if (lastTempStack != nullptr)
3097 {
3098 int indexOfDo = indexOf(*lastTempStack, &AS_DO);
3099 if (indexOfDo != -1)
3100 {
3101 // recreate the header list in headerStack up to the previous 'do'
3102 // from the temporary snapshot stored in lastTempStack.
3103 int restackSize = lastTempStack->size() - indexOfDo - 1;
3104 for (int r = 0; r < restackSize; r++)
3105 {
3106 headerStack->emplace_back(lastTempStack->back());
3107 lastTempStack->pop_back();
3108 }
3109 if (!closingBraceReached)
3110 indentCount += restackSize;
3111 }
3112 }
3113 }
3114 // check if 'catch' closes a previous 'try' or 'catch'
3115 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
3116 {
3117 if (lastTempStack != nullptr)
3118 {
3119 int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
3120 if (indexOfTry == -1)
3121 indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
3122 if (indexOfTry != -1)
3123 {
3124 // recreate the header list in headerStack up to the previous 'try'
3125 // from the temporary snapshot stored in lastTempStack.
3126 int restackSize = lastTempStack->size() - indexOfTry - 1;
3127 for (int r = 0; r < restackSize; r++)
3128 {
3129 headerStack->emplace_back(lastTempStack->back());
3130 lastTempStack->pop_back();
3131 }
3132
3133 if (!closingBraceReached)
3134 indentCount += restackSize;
3135 }
3136 }
3137 }
3138 else if (newHeader == &AS_CASE)
3139 {
3140 isInCase = true;
3141 if (!haveCaseIndent)
3142 {
3143 haveCaseIndent = true;
3144 if (!lineBeginsWithOpenBrace)
3145 --indentCount;
3146 }
3147 }
3148 else if (newHeader == &AS_DEFAULT)
3149 {
3150 isInCase = true;
3151 --indentCount;
3152 }
3153 else if (newHeader == &AS_STATIC
3154 || newHeader == &AS_SYNCHRONIZED)
3155 {
3156 if (!headerStack->empty()
3157 && (headerStack->back() == &AS_STATIC
3158 || headerStack->back() == &AS_SYNCHRONIZED))
3159 {
3160 isIndentableHeader = false;
3161 }
3162 else
3163 {
3164 isIndentableHeader = false;
3165 probationHeader = newHeader;
3166 }
3167 }
3168 else if (newHeader == &AS_TEMPLATE)
3169 {
3170 isInTemplate = true;
3171 isIndentableHeader = false;
3172 }
3173
3174 if (isIndentableHeader)
3175 {
3176 headerStack->emplace_back(newHeader);
3177 isContinuation = false;
3178 if (indexOf(*nonParenHeaders, newHeader) == -1)
3179 {
3180 isInConditional = true;
3181 }
3182 lastLineHeader = newHeader;
3183 }
3184 else
3185 isInHeader = false;
3186
3187 i += newHeader->length() - 1;
3188
3189 continue;
3190 } // newHeader != nullptr
3191
3192 if (findHeader(line, i, preCommandHeaders) != nullptr)
3193 // must be after function arguments
3194 if (prevNonSpaceCh == ')')
3195 foundPreCommandHeader = true;
3196
3197 // Objective-C NSException macros are preCommandHeaders
3198 if (isCStyle() && findKeyword(line, i, AS_NS_DURING))
3199 foundPreCommandMacro = true;
3200 if (isCStyle() && findKeyword(line, i, AS_NS_HANDLER))
3201 foundPreCommandMacro = true;
3202
3203 if (parenDepth == 0 && findKeyword(line, i, AS_ENUM))
3204 isInEnum = true;
3205
3206 if (isSharpStyle() && findKeyword(line, i, AS_LET))
3207 isInLet = true;
3208
3209 } // isPotentialHeader
3210
3211 if (ch == '?')
3212 isInQuestion = true;
3213
3214 // special handling of colons
3215 if (ch == ':')
3216 {
3217 if (line.length() > i + 1 && line[i + 1] == ':') // look for ::
3218 {
3219 ++i;
3220 continue;
3221 }
3222 else if (isInQuestion) // NOLINT
3223 {
3224 // do nothing special
3225 }
3226 else if (parenDepth > 0)
3227 {
3228 // found a 'for' loop or an objective-C statement
3229 // so do nothing special
3230 }
3231 else if (isInEnum)
3232 {
3233 // found an enum with a base-type
3234 isInEnumTypeID = true;
3235 if (i == 0)
3236 indentCount += classInitializerIndents;
3237 }
3238 else if ((isCStyle() || isSharpStyle())
3239 && !isInCase
3240 && (prevNonSpaceCh == ')' || foundPreCommandHeader))
3241 {
3242 // found a 'class' c'tor initializer
3243 isInClassInitializer = true;
3244 registerContinuationIndentColon(line, i, tabIncrementIn);
3245 if (i == 0)
3246 indentCount += classInitializerIndents;
3247 }
3248 else if (isInClassHeader || isInObjCInterface)
3249 {
3250 // is in a 'class A : public B' definition
3251 isInClassHeaderTab = true;
3252 registerContinuationIndentColon(line, i, tabIncrementIn);
3253 }
3254 else if (isInAsm || isInAsmOneLine || isInAsmBlock)
3255 {
3256 // do nothing special
3257 }
3258 else if (isDigit(peekNextChar(line, i)))
3259 {
3260 // found a bit field - do nothing special
3261 }
3262 else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
3263 {
3264 // found a 'private:' or 'public:' inside a class definition
3265 --indentCount;
3266 if (modifierIndent)
3267 spaceIndentCount += (indentLength / 2);
3268 }
3269 else if (isCStyle() && !isInClass
3270 && headerStack->size() >= 2
3271 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
3272 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE)
3273 {
3274 // found a 'private:' or 'public:' inside a class definition
3275 // and on the same line as the class opening brace
3276 // do nothing
3277 }
3278 else if (isJavaStyle() && lastLineHeader == &AS_FOR)
3279 {
3280 // found a java for-each statement
3281 // so do nothing special
3282 }
3283 else
3284 {
3285 currentNonSpaceCh = ';'; // so that braces after the ':' will appear as block-openers
3286 char peekedChar = peekNextChar(line, i);
3287 if (isInCase)
3288 {
3289 isInCase = false;
3290 ch = ';'; // from here on, treat char as ';'
3291 }
3292 else if (isCStyle() || (isSharpStyle() && peekedChar == ';'))
3293 {
3294 // is in a label (e.g. 'label1:')
3295 if (labelIndent)
3296 --indentCount; // unindent label by one indent
3297 else if (!lineBeginsWithOpenBrace)
3298 indentCount = 0; // completely flush indent to left
3299 }
3300 }
3301 }
3302
3303 if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !continuationIndentStackSizeStack->empty())
3304 while ((int) continuationIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
3305 < (int) continuationIndentStack->size())
3306 continuationIndentStack->pop_back();
3307
3308 else if (ch == ',' && isInEnum && isNonInStatementArray && !continuationIndentStack->empty())
3309 continuationIndentStack->pop_back();
3310
3311 // handle commas
3312 // previous "isInStatement" will be from an assignment operator or class initializer
3313 if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray)
3314 {
3315 // is comma at end of line
3316 size_t nextChar = line.find_first_not_of(" \t", i + 1);
3317 if (nextChar != string::npos)
3318 {
3319 if (line.compare(nextChar, 2, "//") == 0
3320 || line.compare(nextChar, 2, "/*") == 0)
3321 nextChar = string::npos;
3322 }
3323 // register indent
3324 if (nextChar == string::npos)
3325 {
3326 // register indent at previous word
3327 if (isJavaStyle() && isInClassHeader)
3328 {
3329 // do nothing for now
3330 }
3331 // register indent at second word on the line
3332 else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer)
3333 {
3334 int prevWord = getContinuationIndentComma(line, i);
3335 int continuationIndentCount = prevWord + spaceIndentCount + tabIncrementIn;
3336 continuationIndentStack->emplace_back(continuationIndentCount);
3337 isContinuation = true;
3338 }
3339 }
3340 }
3341 // handle comma first initializers
3342 if (ch == ',' && parenDepth == 0 && lineBeginsWithComma
3343 && (isInClassInitializer || isInClassHeaderTab))
3344 spaceIndentCount = 0;
3345
3346 // handle ends of statements
3347 if ((ch == ';' && parenDepth == 0) || ch == '}')
3348 {
3349 if (ch == '}')
3350 {
3351 // first check if this '}' closes a previous block, or a static array...
3352 if (braceBlockStateStack->size() > 1)
3353 {
3354 bool braceBlockState = braceBlockStateStack->back();
3355 braceBlockStateStack->pop_back();
3356 if (!braceBlockState)
3357 {
3358 if (!continuationIndentStackSizeStack->empty())
3359 {
3360 // this brace is a static array
3361 popLastContinuationIndent();
3362 parenDepth--;
3363 if (i == 0)
3364 shouldIndentBracedLine = false;
3365
3366 if (!parenIndentStack->empty())
3367 {
3368 int poppedIndent = parenIndentStack->back();
3369 parenIndentStack->pop_back();
3370 if (i == 0)
3371 spaceIndentCount = poppedIndent;
3372 }
3373 }
3374 continue;
3375 }
3376 }
3377
3378 // this brace is block closer...
3379
3380 ++lineClosingBlocksNum;
3381
3382 if (!continuationIndentStackSizeStack->empty())
3383 popLastContinuationIndent();
3384
3385 if (!parenDepthStack->empty())
3386 {
3387 parenDepth = parenDepthStack->back();
3388 parenDepthStack->pop_back();
3389 isContinuation = blockStatementStack->back();
3390 blockStatementStack->pop_back();
3391
3392 if (isContinuation)
3393 blockTabCount--;
3394 }
3395
3396 closingBraceReached = true;
3397 if (i == 0)
3398 spaceIndentCount = 0;
3399 isInAsmBlock = false;
3400 isInAsm = isInAsmOneLine = isInQuote = false; // close these just in case
3401
3402 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACE);
3403 if (headerPlace != -1)
3404 {
3405 const string* popped = headerStack->back();
3406 while (popped != &AS_OPEN_BRACE)
3407 {
3408 headerStack->pop_back();
3409 popped = headerStack->back();
3410 }
3411 headerStack->pop_back();
3412
3413 if (headerStack->empty())
3414 g_preprocessorCppExternCBrace = 0;
3415
3416 // do not indent namespace brace unless namespaces are indented
3417 if (!namespaceIndent && !headerStack->empty()
3418 && ((*headerStack).back() == &AS_NAMESPACE
3419 || (*headerStack).back() == &AS_MODULE)
3420 && i == 0) // must be the first brace on the line
3421 shouldIndentBracedLine = false;
3422
3423 if (!tempStacks->empty())
3424 {
3425 vector<const string*>* temp = tempStacks->back();
3426 tempStacks->pop_back();
3427 delete temp;
3428 }
3429 }
3430
3431 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' in this case) will be identified...
3432 } // ch == '}'
3433
3434 /*
3435 * Create a temporary snapshot of the current block's header-list in the
3436 * uppermost inner stack in tempStacks, and clear the headerStack up to
3437 * the beginning of the block.
3438 * Thus, the next future statement will think it comes one indent past
3439 * the block's '{' unless it specifically checks for a companion-header
3440 * (such as a previous 'if' for an 'else' header) within the tempStacks,
3441 * and recreates the temporary snapshot by manipulating the tempStacks.
3442 */
3443 if (!tempStacks->back()->empty())
3444 while (!tempStacks->back()->empty())
3445 tempStacks->back()->pop_back();
3446 while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACE)
3447 {
3448 tempStacks->back()->emplace_back(headerStack->back());
3449 headerStack->pop_back();
3450 }
3451
3452 if (parenDepth == 0 && ch == ';')
3453 {
3454 isContinuation = false;
3455 isInClassInitializer = false;
3456 }
3457
3458 if (isInObjCMethodDefinition)
3459 {
3460 objCColonAlignSubsequent = 0;
3461 isImmediatelyPostObjCMethodDefinition = true;
3462 }
3463
3464 previousLastLineHeader = nullptr;
3465 isInClassHeader = false; // for 'friend' class
3466 isInEnum = false;
3467 isInEnumTypeID = false;
3468 isInQuestion = false;
3469 isInTemplate = false;
3470 isInObjCInterface = false;
3471 foundPreCommandHeader = false;
3472 foundPreCommandMacro = false;
3473 squareBracketCount = 0;
3474
3475 continue;
3476 }
3477
3478 if (isPotentialHeader)
3479 {
3480 // check for preBlockStatements in C/C++ ONLY if not within parentheses
3481 // (otherwise 'struct XXX' statements would be wrongly interpreted...)
3482 if (!isInTemplate && !(isCStyle() && parenDepth > 0))
3483 {
3484 const string* newHeader = findHeader(line, i, preBlockStatements);
3485 // CORBA IDL module
3486 if (newHeader == &AS_MODULE)
3487 {
3488 char nextChar = peekNextChar(line, i + newHeader->length() - 1);
3489 if (prevNonSpaceCh == ')' || !isalpha(nextChar))
3490 newHeader = nullptr;
3491 }
3492 if (newHeader != nullptr
3493 && !(isCStyle() && newHeader == &AS_CLASS && isInEnum) // is not 'enum class'
3494 && !(isCStyle() && newHeader == &AS_INTERFACE // CORBA IDL interface
3495 && (headerStack->empty()
3496 || headerStack->back() != &AS_OPEN_BRACE)))
3497 {
3498 if (!isSharpStyle())
3499 headerStack->emplace_back(newHeader);
3500 // do not need 'where' in the headerStack
3501 // do not need second 'class' statement in a row
3502 else if (!(newHeader == &AS_WHERE
3503 || ((newHeader == &AS_CLASS || newHeader == &AS_STRUCT)
3504 && !headerStack->empty()
3505 && (headerStack->back() == &AS_CLASS
3506 || headerStack->back() == &AS_STRUCT))))
3507 headerStack->emplace_back(newHeader);
3508
3509 if (!headerStack->empty())
3510 {
3511 if ((*headerStack).back() == &AS_CLASS
3512 || (*headerStack).back() == &AS_STRUCT
3513 || (*headerStack).back() == &AS_INTERFACE)
3514 {
3515 isInClassHeader = true;
3516 }
3517 else if ((*headerStack).back() == &AS_NAMESPACE
3518 || (*headerStack).back() == &AS_MODULE)
3519 {
3520 // remove continuationIndent from namespace
3521 if (!continuationIndentStack->empty())
3522 continuationIndentStack->pop_back();
3523 isContinuation = false;
3524 }
3525 }
3526
3527 i += newHeader->length() - 1;
3528 continue;
3529 }
3530 }
3531 const string* foundIndentableHeader = findHeader(line, i, indentableHeaders);
3532
3533 if (foundIndentableHeader != nullptr)
3534 {
3535 // must bypass the header before registering the in statement
3536 i += foundIndentableHeader->length() - 1;
3537 if (!isInOperator && !isInTemplate && !isNonInStatementArray)
3538 {
3539 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
3540 isContinuation = true;
3541 }
3542 continue;
3543 }
3544
3545 if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
3546 isInOperator = true;
3547
3548 if (g_preprocessorCppExternCBrace == 1 && findKeyword(line, i, AS_EXTERN))
3549 ++g_preprocessorCppExternCBrace;
3550
3551 if (g_preprocessorCppExternCBrace == 3) // extern "C" is not followed by a '{'
3552 g_preprocessorCppExternCBrace = 0;
3553
3554 // "new" operator is a pointer, not a calculation
3555 if (findKeyword(line, i, AS_NEW))
3556 {
3557 if (isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=')
3558 continuationIndentStack->back() = 0;
3559 }
3560
3561 if (isCStyle() && findKeyword(line, i, AS_AUTO) && isTopLevel())
3562 {
3563 isInTrailingReturnType = true;
3564 }
3565
3566 if (isCStyle())
3567 {
3568 if (findKeyword(line, i, AS_ASM)
3569 || findKeyword(line, i, AS__ASM__))
3570 {
3571 isInAsm = true;
3572 }
3573 else if (findKeyword(line, i, AS_MS_ASM) // microsoft specific
3574 || findKeyword(line, i, AS_MS__ASM))
3575 {
3576 int index = 4;
3577 if (peekNextChar(line, i) == '_') // check for __asm
3578 index = 5;
3579
3580 char peekedChar = peekNextChar(line, i + index);
3581 if (peekedChar == '{' || peekedChar == ' ')
3582 isInAsmBlock = true;
3583 else
3584 isInAsmOneLine = true;
3585 }
3586 }
3587
3588 // bypass the entire name for all others
3589 string name = getCurrentWord(line, i);
3590 i += name.length() - 1;
3591 continue;
3592 }
3593
3594 // Handle Objective-C statements
3595
3596 if (ch == '@'
3597 && line.length() > i + 1
3598 && !isWhiteSpace(line[i + 1])
3599 && isCharPotentialHeader(line, i + 1))
3600 {
3601 string curWord = getCurrentWord(line, i + 1);
3602 if (curWord == AS_INTERFACE || curWord == AS_AUTORELEASEPOOL)
3603 {
3604 isInObjCInterface = true;
3605 string name = '@' + curWord;
3606 i += name.length() - 1;
3607 continue;
3608 }
3609
3610 if (isInObjCInterface)
3611 {
3612 --indentCount;
3613 isInObjCInterface = false;
3614 }
3615
3616 if (curWord == AS_PUBLIC
3617 || curWord == AS_PRIVATE
3618 || curWord == AS_PROTECTED)
3619 {
3620 --indentCount;
3621 if (modifierIndent)
3622 spaceIndentCount += (indentLength / 2);
3623 string name = '@' + curWord;
3624 i += name.length() - 1;
3625 continue;
3626 }
3627
3628 if (curWord == AS_END)
3629 {
3630 popLastContinuationIndent();
3631 spaceIndentCount = 0;
3632 isInObjCMethodDefinition = false;
3633 string name = '@' + curWord;
3634 i += name.length() - 1;
3635 continue;
3636 }
3637 }
3638 else if ((ch == '-' || ch == '+')
3639 && (prevNonSpaceCh == ';' || prevNonSpaceCh == '{'
3640 || headerStack->empty() || isInObjCInterface)
3641 && ASBase::peekNextChar(line, i) != '-'
3642 && ASBase::peekNextChar(line, i) != '+'
3643 && line.find_first_not_of(" \t") == i)
3644 {
3645 if (isInObjCInterface)
3646 --indentCount;
3647 isInObjCInterface = false;
3648 isInObjCMethodDefinition = true;
3649 continue;
3650 }
3651
3652 // Handle operators
3653
3654 bool isPotentialOperator = isCharPotentialOperator(ch);
3655
3656 if (isPotentialOperator)
3657 {
3658 // Check if an operator has been reached.
3659 const string* foundAssignmentOp = findOperator(line, i, assignmentOperators);
3660 const string* foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);
3661
3662 if (foundNonAssignmentOp != nullptr)
3663 {
3664 if (foundNonAssignmentOp == &AS_LAMBDA)
3665 foundPreCommandHeader = true;
3666 if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR)
3667 foundNonAssignmentOp = nullptr;
3668 }
3669
3670 // Since findHeader's boundary checking was not used above, it is possible
3671 // that both an assignment op and a non-assignment op where found,
3672 // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
3673 // found operator.
3674 if (foundAssignmentOp != nullptr && foundNonAssignmentOp != nullptr)
3675 {
3676 if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
3677 foundAssignmentOp = nullptr;
3678 else
3679 foundNonAssignmentOp = nullptr;
3680 }
3681
3682 if (foundNonAssignmentOp != nullptr)
3683 {
3684 if (foundNonAssignmentOp->length() > 1)
3685 i += foundNonAssignmentOp->length() - 1;
3686
3687 // For C++ input/output, operator<< and >> should be
3688 // aligned, if we are not in a statement already and
3689 // also not in the "operator<<(...)" header line
3690 if (!isInOperator
3691 && continuationIndentStack->empty()
3692 && isCStyle()
3693 && (foundNonAssignmentOp == &AS_GR_GR
3694 || foundNonAssignmentOp == &AS_LS_LS))
3695 {
3696 // this will be true if the line begins with the operator
3697 if (i < foundNonAssignmentOp->length() && spaceIndentCount == 0)
3698 spaceIndentCount += 2 * indentLength;
3699 // align to the beginning column of the operator
3700 registerContinuationIndent(line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false);
3701 }
3702 }
3703
3704 else if (foundAssignmentOp != nullptr)
3705 {
3706 foundPreCommandHeader = false; // clears this for array assignments
3707 foundPreCommandMacro = false;
3708
3709 if (foundAssignmentOp->length() > 1)
3710 i += foundAssignmentOp->length() - 1;
3711
3712 if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum))
3713 {
3714 // if multiple assignments, align on the previous word
3715 if (foundAssignmentOp == &AS_ASSIGN
3716 && prevNonSpaceCh != ']' // an array
3717 && statementEndsWithComma(line, i))
3718 {
3719 if (!haveAssignmentThisLine) // only one assignment indent per line
3720 {
3721 // register indent at previous word
3722 haveAssignmentThisLine = true;
3723 int prevWordIndex = getContinuationIndentAssign(line, i);
3724 int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn;
3725 continuationIndentStack->emplace_back(continuationIndentCount);
3726 isContinuation = true;
3727 }
3728 }
3729 // don't indent an assignment if 'let'
3730 else if (isInLet)
3731 {
3732 isInLet = false;
3733 }
3734 else if (!lineBeginsWithComma)
3735 {
3736 if (i == 0 && spaceIndentCount == 0)
3737 spaceIndentCount += indentLength;
3738 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
3739 isContinuation = true;
3740 }
3741 }
3742 }
3743 }
3744 } // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
3745}
3746
3747} // end namespace astyle
3748