2 // Copyright (c) 2017 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.
6 //-----------------------------------------------------------------------------
8 //-----------------------------------------------------------------------------
14 //-----------------------------------------------------------------------------
16 //-----------------------------------------------------------------------------
20 // this must be global
21 static int g_preprocessorCppExternCBrace;
23 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
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.
32 ASBeautifier::ASBeautifier()
34 waitingBeautifierStack = nullptr;
35 activeBeautifierStack = nullptr;
36 waitingBeautifierStackLengthStack = nullptr;
37 activeBeautifierStackLengthStack = nullptr;
39 headerStack = nullptr;
41 squareBracketDepthStack = 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;
58 setClassIndent(false);
59 setModifierIndent(false);
60 setSwitchIndent(false);
62 setBlockIndent(false);
63 setBraceIndent(false);
64 setBraceIndentVtk(false);
65 setNamespaceIndent(false);
66 setAfterParenIndent(false);
67 setLabelIndent(false);
68 setEmptyLineFill(false);
70 setPreprocDefineIndent(false);
71 setPreprocConditionalIndent(false);
72 setAlignMethodColon(false);
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*>;
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.
92 * Must explicitly call the base class copy constructor.
94 ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other)
96 // these don't need to copy the stack
97 waitingBeautifierStack = nullptr;
98 activeBeautifierStack = nullptr;
99 waitingBeautifierStackLengthStack = nullptr;
100 activeBeautifierStackLengthStack = nullptr;
102 // vector '=' operator performs a DEEP copy of all elements in the vector
104 headerStack = new vector<const string*>;
105 *headerStack = *other.headerStack;
107 tempStacks = copyTempStacks(other);
109 squareBracketDepthStack = new vector<int>;
110 *squareBracketDepthStack = *other.squareBracketDepthStack;
112 blockStatementStack = new vector<bool>;
113 *blockStatementStack = *other.blockStatementStack;
115 parenStatementStack = new vector<bool>;
116 *parenStatementStack = *other.parenStatementStack;
118 braceBlockStateStack = new vector<bool>;
119 *braceBlockStateStack = *other.braceBlockStateStack;
121 continuationIndentStack = new vector<int>;
122 *continuationIndentStack = *other.continuationIndentStack;
124 continuationIndentStackSizeStack = new vector<int>;
125 *continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack;
127 parenIndentStack = new vector<int>;
128 *parenIndentStack = *other.parenIndentStack;
130 preprocIndentStack = new vector<pair<int, int> >;
131 *preprocIndentStack = *other.preprocIndentStack;
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;
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;
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 modifierIndent = other.modifierIndent;
204 switchIndent = other.switchIndent;
205 caseIndent = other.caseIndent;
206 namespaceIndent = other.namespaceIndent;
207 braceIndent = other.braceIndent;
208 braceIndentVtk = other.braceIndentVtk;
209 blockIndent = other.blockIndent;
210 shouldIndentAfterParen = other.shouldIndentAfterParen;
211 labelIndent = other.labelIndent;
212 isInConditional = other.isInConditional;
213 isModeManuallySet = other.isModeManuallySet;
214 shouldForceTabIndentation = other.shouldForceTabIndentation;
215 emptyLineFill = other.emptyLineFill;
216 lineOpensWithLineComment = other.lineOpensWithLineComment;
217 lineOpensWithComment = other.lineOpensWithComment;
218 lineStartsInComment = other.lineStartsInComment;
219 backslashEndsPrevLine = other.backslashEndsPrevLine;
220 blockCommentNoIndent = other.blockCommentNoIndent;
221 blockCommentNoBeautify = other.blockCommentNoBeautify;
222 previousLineProbationTab = other.previousLineProbationTab;
223 lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace;
224 lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace;
225 lineBeginsWithComma = other.lineBeginsWithComma;
226 lineIsCommentOnly = other.lineIsCommentOnly;
227 lineIsLineCommentOnly = other.lineIsLineCommentOnly;
228 shouldIndentBracedLine = other.shouldIndentBracedLine;
229 isInSwitch = other.isInSwitch;
230 foundPreCommandHeader = other.foundPreCommandHeader;
231 foundPreCommandMacro = other.foundPreCommandMacro;
232 shouldAlignMethodColon = other.shouldAlignMethodColon;
233 shouldIndentPreprocDefine = other.shouldIndentPreprocDefine;
234 shouldIndentPreprocConditional = other.shouldIndentPreprocConditional;
235 indentCount = other.indentCount;
236 spaceIndentCount = other.spaceIndentCount;
237 spaceIndentObjCMethodAlignment = other.spaceIndentObjCMethodAlignment;
238 bracePosObjCMethodAlignment = other.bracePosObjCMethodAlignment;
239 colonIndentObjCMethodAlignment = other.colonIndentObjCMethodAlignment;
240 lineOpeningBlocksNum = other.lineOpeningBlocksNum;
241 lineClosingBlocksNum = other.lineClosingBlocksNum;
242 fileType = other.fileType;
243 minConditionalOption = other.minConditionalOption;
244 minConditionalIndent = other.minConditionalIndent;
245 parenDepth = other.parenDepth;
246 indentLength = other.indentLength;
247 tabLength = other.tabLength;
248 continuationIndent = other.continuationIndent;
249 blockTabCount = other.blockTabCount;
250 maxContinuationIndent = other.maxContinuationIndent;
251 classInitializerIndents = other.classInitializerIndents;
252 templateDepth = other.templateDepth;
253 squareBracketCount = other.squareBracketCount;
254 prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount;
255 prevFinalLineIndentCount = other.prevFinalLineIndentCount;
256 defineIndentCount = other.defineIndentCount;
257 preprocBlockIndent = other.preprocBlockIndent;
258 quoteChar = other.quoteChar;
259 prevNonSpaceCh = other.prevNonSpaceCh;
260 currentNonSpaceCh = other.currentNonSpaceCh;
261 currentNonLegalCh = other.currentNonLegalCh;
262 prevNonLegalCh = other.prevNonLegalCh;
266 * ASBeautifier's destructor
268 ASBeautifier::~ASBeautifier()
270 deleteBeautifierContainer(waitingBeautifierStack);
271 deleteBeautifierContainer(activeBeautifierStack);
272 deleteContainer(waitingBeautifierStackLengthStack);
273 deleteContainer(activeBeautifierStackLengthStack);
274 deleteContainer(headerStack);
275 deleteTempStacksContainer(tempStacks);
276 deleteContainer(squareBracketDepthStack);
277 deleteContainer(blockStatementStack);
278 deleteContainer(parenStatementStack);
279 deleteContainer(braceBlockStateStack);
280 deleteContainer(continuationIndentStack);
281 deleteContainer(continuationIndentStackSizeStack);
282 deleteContainer(parenIndentStack);
283 deleteContainer(preprocIndentStack);
287 * initialize the ASBeautifier.
289 * This init() should be called every time a ABeautifier object is to start
290 * beautifying a NEW source file.
291 * It is called only when a new ASFormatter object is created.
292 * init() receives a pointer to a ASSourceIterator object that will be
293 * used to iterate through the source code.
295 * @param iter a pointer to the ASSourceIterator or ASStreamIterator object.
297 void ASBeautifier::init(ASSourceIterator* iter)
299 sourceIterator = iter;
301 ASBase::init(getFileType());
302 g_preprocessorCppExternCBrace = 0;
304 initContainer(waitingBeautifierStack, new vector<ASBeautifier*>);
305 initContainer(activeBeautifierStack, new vector<ASBeautifier*>);
307 initContainer(waitingBeautifierStackLengthStack, new vector<int>);
308 initContainer(activeBeautifierStackLengthStack, new vector<int>);
310 initContainer(headerStack, new vector<const string*>);
312 initTempStacksContainer(tempStacks, new vector<vector<const string*>*>);
313 tempStacks->emplace_back(new vector<const string*>);
315 initContainer(squareBracketDepthStack, new vector<int>);
316 initContainer(blockStatementStack, new vector<bool>);
317 initContainer(parenStatementStack, new vector<bool>);
318 initContainer(braceBlockStateStack, new vector<bool>);
319 braceBlockStateStack->push_back(true);
320 initContainer(continuationIndentStack, new vector<int>);
321 initContainer(continuationIndentStackSizeStack, new vector<int>);
322 continuationIndentStackSizeStack->emplace_back(0);
323 initContainer(parenIndentStack, new vector<int>);
324 initContainer(preprocIndentStack, new vector<pair<int, int> >);
326 previousLastLineHeader = nullptr;
327 currentHeader = nullptr;
330 isInVerbatimQuote = false;
331 haveLineContinuationChar = false;
333 isInAsmOneLine = false;
334 isInAsmBlock = false;
336 isInPreprocessorComment = false;
337 isInRunInComment = false;
338 isContinuation = false;
340 isInQuestion = false;
341 isIndentModeOff = false;
342 isInClassHeader = false;
343 isInClassHeaderTab = false;
344 isInClassInitializer = false;
346 isInObjCMethodDefinition = false;
347 isInObjCMethodCall = false;
348 isInObjCMethodCallFirst = false;
349 isImmediatelyPostObjCMethodDefinition = false;
350 isImmediatelyPostObjCMethodCall = false;
351 isInIndentablePreprocBlock = false;
352 isInObjCInterface = false;
354 isInEnumTypeID = false;
357 isInTemplate = false;
358 isInConditional = false;
361 spaceIndentCount = 0;
362 spaceIndentObjCMethodAlignment = 0;
363 bracePosObjCMethodAlignment = 0;
364 colonIndentObjCMethodAlignment = 0;
365 lineOpeningBlocksNum = 0;
366 lineClosingBlocksNum = 0;
368 squareBracketCount = 0;
371 prevFinalLineSpaceIndentCount = 0;
372 prevFinalLineIndentCount = 0;
373 defineIndentCount = 0;
374 preprocBlockIndent = 0;
375 prevNonSpaceCh = '{';
376 currentNonSpaceCh = '{';
377 prevNonLegalCh = '{';
378 currentNonLegalCh = '{';
380 probationHeader = nullptr;
381 lastLineHeader = nullptr;
382 backslashEndsPrevLine = false;
383 lineOpensWithLineComment = false;
384 lineOpensWithComment = false;
385 lineStartsInComment = false;
387 isInDefineDefinition = false;
388 lineCommentNoBeautify = false;
389 isElseHeaderIndent = false;
390 isCaseHeaderCommentIndent = false;
391 blockCommentNoIndent = false;
392 blockCommentNoBeautify = false;
393 previousLineProbationTab = false;
394 lineBeginsWithOpenBrace = false;
395 lineBeginsWithCloseBrace = false;
396 lineBeginsWithComma = false;
397 lineIsCommentOnly = false;
398 lineIsLineCommentOnly = false;
399 shouldIndentBracedLine = true;
401 foundPreCommandHeader = false;
402 foundPreCommandMacro = false;
404 isNonInStatementArray = false;
405 isSharpAccessor = false;
406 isSharpDelegate = false;
408 isInBeautifySQL = false;
409 isInIndentableStruct = false;
410 isInIndentablePreproc = false;
412 runInIndentContinuation = 0;
413 nonInStatementBrace = 0;
414 objCColonAlignSubsequent = 0;
418 * initialize the vectors
420 void ASBeautifier::initVectors()
422 if (fileType == beautifierFileType) // don't build unless necessary
425 beautifierFileType = fileType;
428 nonParenHeaders->clear();
429 assignmentOperators->clear();
430 nonAssignmentOperators->clear();
431 preBlockStatements->clear();
432 preCommandHeaders->clear();
433 indentableHeaders->clear();
435 ASResource::buildHeaders(headers, fileType, true);
436 ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
437 ASResource::buildAssignmentOperators(assignmentOperators);
438 ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
439 ASResource::buildPreBlockStatements(preBlockStatements, fileType);
440 ASResource::buildPreCommandHeaders(preCommandHeaders, fileType);
441 ASResource::buildIndentableHeaders(indentableHeaders);
445 * set indentation style to C/C++.
447 void ASBeautifier::setCStyle()
453 * set indentation style to Java.
455 void ASBeautifier::setJavaStyle()
457 fileType = JAVA_TYPE;
461 * set indentation style to C#.
463 void ASBeautifier::setSharpStyle()
465 fileType = SHARP_TYPE;
469 * set mode manually set flag
471 void ASBeautifier::setModeManuallySet(bool state)
473 isModeManuallySet = state;
477 * set tabLength equal to indentLength.
478 * This is done when tabLength is not explicitly set by
479 * "indent=force-tab-x"
482 void ASBeautifier::setDefaultTabLength()
484 tabLength = indentLength;
488 * indent using a different tab setting for indent=force-tab
490 * @param length number of spaces per tab.
492 void ASBeautifier::setForceTabXIndentation(int length)
494 // set tabLength instead of indentLength
497 shouldForceTabIndentation = true;
501 * indent using one tab per indentation
503 void ASBeautifier::setTabIndentation(int length, bool forceTabs)
506 indentLength = length;
507 shouldForceTabIndentation = forceTabs;
511 * indent using a number of spaces per indentation.
513 * @param length number of spaces per indent.
515 void ASBeautifier::setSpaceIndentation(int length)
517 indentString = string(length, ' ');
518 indentLength = length;
522 * indent continuation lines using a number of indents.
524 * @param indent number of indents per line.
526 void ASBeautifier::setContinuationIndentation(int indent)
528 continuationIndent = indent;
532 * set the maximum indentation between two lines in a multi-line statement.
534 * @param max maximum indentation length.
536 void ASBeautifier::setMaxContinuationIndentLength(int max)
538 maxContinuationIndent = max;
541 // retained for compatability with release 2.06
542 // "MaxInStatementIndent" has been changed to "MaxContinuationIndent" in 3.0
543 // it is referenced only by the old "MaxInStatementIndent" options
544 void ASBeautifier::setMaxInStatementIndentLength(int max)
546 setMaxContinuationIndentLength(max);
550 * set the minimum conditional indentation option.
552 * @param min minimal indentation option.
554 void ASBeautifier::setMinConditionalIndentOption(int min)
556 minConditionalOption = min;
560 * set minConditionalIndent from the minConditionalOption.
562 void ASBeautifier::setMinConditionalIndentLength()
564 if (minConditionalOption == MINCOND_ZERO)
565 minConditionalIndent = 0;
566 else if (minConditionalOption == MINCOND_ONE)
567 minConditionalIndent = indentLength;
568 else if (minConditionalOption == MINCOND_ONEHALF)
569 minConditionalIndent = indentLength / 2;
570 // minConditionalOption = INDENT_TWO
572 minConditionalIndent = indentLength * 2;
576 * set the state of the brace indent option. If true, braces will
577 * be indented one additional indent.
579 * @param state state of option.
581 void ASBeautifier::setBraceIndent(bool state)
587 * set the state of the brace indent VTK option. If true, braces will
588 * be indented one additional indent, except for the opening brace.
590 * @param state state of option.
592 void ASBeautifier::setBraceIndentVtk(bool state)
594 // need to set both of these
595 setBraceIndent(state);
596 braceIndentVtk = state;
600 * set the state of the block indentation option. If true, entire blocks
601 * will be indented one additional indent, similar to the GNU indent style.
603 * @param state state of option.
605 void ASBeautifier::setBlockIndent(bool state)
611 * set the state of the class indentation option. If true, C++ class
612 * definitions will be indented one additional indent.
614 * @param state state of option.
616 void ASBeautifier::setClassIndent(bool state)
622 * set the state of the modifier indentation option. If true, C++ class
623 * access modifiers will be indented one-half an indent.
625 * @param state state of option.
627 void ASBeautifier::setModifierIndent(bool state)
629 modifierIndent = state;
633 * set the state of the switch indentation option. If true, blocks of 'switch'
634 * statements will be indented one additional indent.
636 * @param state state of option.
638 void ASBeautifier::setSwitchIndent(bool state)
640 switchIndent = state;
644 * set the state of the case indentation option. If true, lines of 'case'
645 * statements will be indented one additional indent.
647 * @param state state of option.
649 void ASBeautifier::setCaseIndent(bool state)
655 * set the state of the namespace indentation option.
656 * If true, blocks of 'namespace' statements will be indented one
657 * additional indent. Otherwise, NO indentation will be added.
659 * @param state state of option.
661 void ASBeautifier::setNamespaceIndent(bool state)
663 namespaceIndent = state;
667 * set the state of the indent after parens option.
669 * @param state state of option.
671 void ASBeautifier::setAfterParenIndent(bool state)
673 shouldIndentAfterParen = state;
677 * set the state of the label indentation option.
678 * If true, labels will be indented one indent LESS than the
679 * current indentation level.
680 * If false, labels will be flushed to the left with NO
683 * @param state state of option.
685 void ASBeautifier::setLabelIndent(bool state)
691 * set the state of the preprocessor indentation option.
692 * If true, multi-line #define statements will be indented.
694 * @param state state of option.
696 void ASBeautifier::setPreprocDefineIndent(bool state)
698 shouldIndentPreprocDefine = state;
701 void ASBeautifier::setPreprocConditionalIndent(bool state)
703 shouldIndentPreprocConditional = state;
707 * set the state of the empty line fill option.
708 * If true, empty lines will be filled with the whitespace.
709 * of their previous lines.
710 * If false, these lines will remain empty.
712 * @param state state of option.
714 void ASBeautifier::setEmptyLineFill(bool state)
716 emptyLineFill = state;
719 void ASBeautifier::setAlignMethodColon(bool state)
721 shouldAlignMethodColon = state;
727 int ASBeautifier::getFileType() const
733 * get the number of spaces per indent
735 * @return value of indentLength option.
737 int ASBeautifier::getIndentLength() const
743 * get the char used for indentation, space or tab
745 * @return the char used for indentation.
747 string ASBeautifier::getIndentString() const
753 * get mode manually set flag
755 bool ASBeautifier::getModeManuallySet() const
757 return isModeManuallySet;
761 * get the state of the force tab indentation option.
763 * @return state of force tab indentation.
765 bool ASBeautifier::getForceTabIndentation() const
767 return shouldForceTabIndentation;
771 * Get the state of the Objective-C align method colon option.
773 * @return state of shouldAlignMethodColon option.
775 bool ASBeautifier::getAlignMethodColon() const
777 return shouldAlignMethodColon;
781 * get the state of the block indentation option.
783 * @return state of blockIndent option.
785 bool ASBeautifier::getBlockIndent() const
791 * get the state of the brace indentation option.
793 * @return state of braceIndent option.
795 bool ASBeautifier::getBraceIndent() const
801 * Get the state of the namespace indentation option. If true, blocks
802 * of the 'namespace' statement will be indented one additional indent.
804 * @return state of namespaceIndent option.
806 bool ASBeautifier::getNamespaceIndent() const
808 return namespaceIndent;
812 * Get the state of the class indentation option. If true, blocks of
813 * the 'class' statement will be indented one additional indent.
815 * @return state of classIndent option.
817 bool ASBeautifier::getClassIndent() const
823 * Get the state of the class access modifier indentation option.
824 * If true, the class access modifiers will be indented one-half indent.
826 * @return state of modifierIndent option.
828 bool ASBeautifier::getModifierIndent() const
830 return modifierIndent;
834 * get the state of the switch indentation option. If true, blocks of
835 * the 'switch' statement will be indented one additional indent.
837 * @return state of switchIndent option.
839 bool ASBeautifier::getSwitchIndent() const
845 * get the state of the case indentation option. If true, lines of 'case'
846 * statements will be indented one additional indent.
848 * @return state of caseIndent option.
850 bool ASBeautifier::getCaseIndent() const
856 * get the state of the empty line fill option.
857 * If true, empty lines will be filled with the whitespace.
858 * of their previous lines.
859 * If false, these lines will remain empty.
861 * @return state of emptyLineFill option.
863 bool ASBeautifier::getEmptyLineFill() const
865 return emptyLineFill;
869 * get the state of the preprocessor indentation option.
870 * If true, preprocessor "define" lines will be indented.
871 * If false, preprocessor "define" lines will be unchanged.
873 * @return state of shouldIndentPreprocDefine option.
875 bool ASBeautifier::getPreprocDefineIndent() const
877 return shouldIndentPreprocDefine;
881 * get the length of the tab indentation option.
883 * @return length of tab indent option.
885 int ASBeautifier::getTabLength() const
891 * beautify a line of source code.
892 * every line of source code in a source code file should be sent
893 * one after the other to the beautify method.
895 * @return the indented line.
896 * @param originalLine the original unindented line.
898 string ASBeautifier::beautify(const string& originalLine)
901 bool isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
903 currentHeader = nullptr;
904 lastLineHeader = nullptr;
905 blockCommentNoBeautify = blockCommentNoIndent;
908 lineBeginsWithOpenBrace = false;
909 lineBeginsWithCloseBrace = false;
910 lineBeginsWithComma = false;
911 lineIsCommentOnly = false;
912 lineIsLineCommentOnly = false;
913 shouldIndentBracedLine = true;
914 isInAsmOneLine = false;
915 lineOpensWithLineComment = false;
916 lineOpensWithComment = false;
917 lineStartsInComment = isInComment;
918 previousLineProbationTab = false;
919 lineOpeningBlocksNum = 0;
920 lineClosingBlocksNum = 0;
921 if (isImmediatelyPostObjCMethodDefinition)
922 clearObjCMethodDefinitionAlignment();
923 if (isImmediatelyPostObjCMethodCall)
925 isImmediatelyPostObjCMethodCall = false;
926 isInObjCMethodCall = false;
927 objCColonAlignSubsequent = 0;
930 // handle and remove white spaces around the line:
931 // If not in comment, first find out size of white space before line,
932 // so that possible comments starting in the line continue in
933 // relation to the preliminary white-space.
934 if (isInQuoteContinuation)
936 // trim a single space added by ASFormatter, otherwise leave it alone
937 if (!(originalLine.length() == 1 && originalLine[0] == ' '))
940 else if (isInComment || isInBeautifySQL)
942 // trim the end of comment and SQL lines
944 size_t trimEnd = line.find_last_not_of(" \t");
945 if (trimEnd == string::npos)
949 if (trimEnd < line.length())
951 // does a brace open the line
952 size_t firstChar = line.find_first_not_of(" \t");
953 if (firstChar != string::npos)
955 if (line[firstChar] == '{')
956 lineBeginsWithOpenBrace = true;
957 else if (line[firstChar] == '}')
958 lineBeginsWithCloseBrace = true;
959 else if (line[firstChar] == ',')
960 lineBeginsWithComma = true;
965 line = trim(originalLine);
966 if (line.length() > 0)
969 lineBeginsWithOpenBrace = true;
970 else if (line[0] == '}')
971 lineBeginsWithCloseBrace = true;
972 else if (line[0] == ',')
973 lineBeginsWithComma = true;
974 else if (line.compare(0, 2, "//") == 0)
975 lineIsLineCommentOnly = true;
976 else if (line.compare(0, 2, "/*") == 0)
978 if (line.find("*/", 2) != string::npos)
979 lineIsCommentOnly = true;
983 isInRunInComment = false;
984 size_t j = line.find_first_not_of(" \t{");
985 if (j != string::npos && line.compare(j, 2, "//") == 0)
986 lineOpensWithLineComment = true;
987 if (j != string::npos && line.compare(j, 2, "/*") == 0)
989 lineOpensWithComment = true;
990 size_t k = line.find_first_not_of(" \t");
991 if (k != string::npos && line.compare(k, 1, "{") == 0)
992 isInRunInComment = true;
996 // When indent is OFF the lines must still be processed by ASBeautifier.
997 // Otherwise the lines immediately following may not be indented correctly.
998 if ((lineIsLineCommentOnly || lineIsCommentOnly)
999 && line.find("*INDENT-OFF*", 0) != string::npos)
1000 isIndentModeOff = true;
1002 if (line.length() == 0)
1004 if (backslashEndsPrevLine)
1006 backslashEndsPrevLine = false;
1007 // check if this line ends a multi-line #define
1008 // if so, remove the #define's cloned beautifier from the active
1009 // beautifier stack and delete it.
1010 if (isInDefineDefinition && !isInDefine)
1012 isInDefineDefinition = false;
1013 ASBeautifier* defineBeautifier = activeBeautifierStack->back();
1014 activeBeautifierStack->pop_back();
1015 delete defineBeautifier;
1018 if (emptyLineFill && !isInQuoteContinuation)
1020 if (isInIndentablePreprocBlock)
1021 return preLineWS(preprocBlockIndent, 0);
1022 if (!headerStack->empty() || isInEnum)
1023 return preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount);
1024 // must fall thru here
1030 // handle preprocessor commands
1031 if (isInIndentablePreprocBlock
1032 && line.length() > 0
1035 string indentedLine;
1036 if (isInClassHeaderTab || isInClassInitializer)
1038 // parsing is turned off in ASFormatter by indent-off
1039 // the originalLine will probably never be returned here
1040 indentedLine = preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount) + line;
1041 return getIndentedLineReturn(indentedLine, originalLine);
1043 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1044 return getIndentedLineReturn(indentedLine, originalLine);
1048 && !isInQuoteContinuation
1049 && line.length() > 0
1050 && ((line[0] == '#' && !isIndentedPreprocessor(line, 0))
1051 || backslashEndsPrevLine))
1053 if (line[0] == '#' && !isInDefine)
1055 string preproc = extractPreprocessorStatement(line);
1056 processPreprocessor(preproc, line);
1057 if (isInIndentablePreprocBlock || isInIndentablePreproc)
1059 string indentedLine;
1060 if ((preproc.length() >= 2 && preproc.substr(0, 2) == "if")) // #if, #ifdef, #ifndef
1062 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1063 preprocBlockIndent += 1;
1064 isInIndentablePreprocBlock = true;
1066 else if (preproc == "else" || preproc == "elif")
1068 indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line;
1070 else if (preproc == "endif")
1072 preprocBlockIndent -= 1;
1073 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1074 if (preprocBlockIndent == 0)
1075 isInIndentablePreprocBlock = false;
1078 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1079 return getIndentedLineReturn(indentedLine, originalLine);
1081 if (shouldIndentPreprocConditional && preproc.length() > 0)
1083 string indentedLine;
1084 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
1086 pair<int, int> entry; // indentCount, spaceIndentCount
1087 if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
1088 entry = activeBeautifierStack->back()->computePreprocessorIndent();
1090 entry = computePreprocessorIndent();
1091 preprocIndentStack->emplace_back(entry);
1092 indentedLine = preLineWS(preprocIndentStack->back().first,
1093 preprocIndentStack->back().second) + line;
1094 return getIndentedLineReturn(indentedLine, originalLine);
1096 if (preproc == "else" || preproc == "elif")
1098 if (!preprocIndentStack->empty()) // if no entry don't indent
1100 indentedLine = preLineWS(preprocIndentStack->back().first,
1101 preprocIndentStack->back().second) + line;
1102 return getIndentedLineReturn(indentedLine, originalLine);
1105 else if (preproc == "endif")
1107 if (!preprocIndentStack->empty()) // if no entry don't indent
1109 indentedLine = preLineWS(preprocIndentStack->back().first,
1110 preprocIndentStack->back().second) + line;
1111 preprocIndentStack->pop_back();
1112 return getIndentedLineReturn(indentedLine, originalLine);
1118 // check if the last char is a backslash
1119 if (line.length() > 0)
1120 backslashEndsPrevLine = (line[line.length() - 1] == '\\');
1121 // comments within the definition line can be continued without the backslash
1122 if (isInPreprocessorUnterminatedComment(line))
1123 backslashEndsPrevLine = true;
1125 // check if this line ends a multi-line #define
1126 // if so, use the #define's cloned beautifier for the line's indentation
1127 // and then remove it from the active beautifier stack and delete it.
1128 if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
1130 isInDefineDefinition = false;
1131 ASBeautifier* defineBeautifier = activeBeautifierStack->back();
1132 activeBeautifierStack->pop_back();
1134 string indentedLine = defineBeautifier->beautify(line);
1135 delete defineBeautifier;
1136 return getIndentedLineReturn(indentedLine, originalLine);
1139 // unless this is a multi-line #define, return this precompiler line as is.
1140 if (!isInDefine && !isInDefineDefinition)
1141 return originalLine;
1144 // if there exists any worker beautifier in the activeBeautifierStack,
1145 // then use it instead of me to indent the current line.
1146 // variables set by ASFormatter must be updated.
1147 if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
1149 activeBeautifierStack->back()->inLineNumber = inLineNumber;
1150 activeBeautifierStack->back()->runInIndentContinuation = runInIndentContinuation;
1151 activeBeautifierStack->back()->nonInStatementBrace = nonInStatementBrace;
1152 activeBeautifierStack->back()->objCColonAlignSubsequent = objCColonAlignSubsequent;
1153 activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
1154 activeBeautifierStack->back()->isElseHeaderIndent = isElseHeaderIndent;
1155 activeBeautifierStack->back()->isCaseHeaderCommentIndent = isCaseHeaderCommentIndent;
1156 activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
1157 activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
1158 activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
1159 activeBeautifierStack->back()->isInExternC = isInExternC;
1160 activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL;
1161 activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct;
1162 activeBeautifierStack->back()->isInIndentablePreproc = isInIndentablePreproc;
1163 // must return originalLine not the trimmed line
1164 return activeBeautifierStack->back()->beautify(originalLine);
1167 // Flag an indented header in case this line is a one-line block.
1168 // The header in the header stack will be deleted by a one-line block.
1169 bool isInExtraHeaderIndent = false;
1170 if (!headerStack->empty()
1171 && lineBeginsWithOpenBrace
1172 && (headerStack->back() != &AS_OPEN_BRACE
1173 || probationHeader != nullptr))
1174 isInExtraHeaderIndent = true;
1176 size_t iPrelim = headerStack->size();
1178 // calculate preliminary indentation based on headerStack and data from past lines
1179 computePreliminaryIndentation();
1181 // parse characters in the current line.
1182 parseCurrentLine(line);
1184 // handle special cases of indentation
1185 adjustParsedLineIndentation(iPrelim, isInExtraHeaderIndent);
1187 if (isInObjCMethodDefinition)
1188 adjustObjCMethodDefinitionIndentation(line);
1190 if (isInObjCMethodCall)
1191 adjustObjCMethodCallIndentation(line);
1195 if (line.length() > 0 && line[0] == '#')
1197 // the 'define' does not have to be attached to the '#'
1198 string preproc = trim(line.substr(1));
1199 if (preproc.compare(0, 6, "define") == 0)
1201 if (!continuationIndentStack->empty()
1202 && continuationIndentStack->back() > 0)
1204 defineIndentCount = indentCount;
1208 defineIndentCount = indentCount - 1;
1214 indentCount -= defineIndentCount;
1217 if (indentCount < 0)
1220 if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation)
1221 indentCount = spaceIndentCount = 0;
1223 // finally, insert indentations into beginning of line
1225 string indentedLine = preLineWS(indentCount, spaceIndentCount) + line;
1226 indentedLine = getIndentedLineReturn(indentedLine, originalLine);
1228 prevFinalLineSpaceIndentCount = spaceIndentCount;
1229 prevFinalLineIndentCount = indentCount;
1231 if (lastLineHeader != nullptr)
1232 previousLastLineHeader = lastLineHeader;
1234 if ((lineIsLineCommentOnly || lineIsCommentOnly)
1235 && line.find("*INDENT-ON*", 0) != string::npos)
1236 isIndentModeOff = false;
1238 return indentedLine;
1241 const string& ASBeautifier::getIndentedLineReturn(const string& newLine, const string& originalLine) const
1243 if (isIndentModeOff)
1244 return originalLine;
1248 string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCount) const
1250 if (shouldForceTabIndentation)
1252 if (tabLength != indentLength)
1254 // adjust for different tab length
1255 int indentCountOrig = lineIndentCount;
1256 int spaceIndentCountOrig = lineSpaceIndentCount;
1257 lineIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) / tabLength;
1258 lineSpaceIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) % tabLength;
1262 lineIndentCount += lineSpaceIndentCount / indentLength;
1263 lineSpaceIndentCount = lineSpaceIndentCount % indentLength;
1268 for (int i = 0; i < lineIndentCount; i++)
1270 while ((lineSpaceIndentCount--) > 0)
1276 * register a continuation indent.
1278 void ASBeautifier::registerContinuationIndent(const string& line, int i, int spaceIndentCount_,
1279 int tabIncrementIn, int minIndent, bool updateParenStack)
1281 int remainingCharNum = line.length() - i;
1282 int nextNonWSChar = getNextProgramCharDistance(line, i);
1284 // if indent is around the last char in the line OR indent-after-paren is requested,
1285 // indent with the continuation indent
1286 if (nextNonWSChar == remainingCharNum || shouldIndentAfterParen)
1288 int previousIndent = spaceIndentCount_;
1289 if (!continuationIndentStack->empty())
1290 previousIndent = continuationIndentStack->back();
1291 int currIndent = continuationIndent * indentLength + previousIndent;
1292 if (currIndent > maxContinuationIndent && line[i] != '{')
1293 currIndent = indentLength * 2 + spaceIndentCount_;
1294 continuationIndentStack->emplace_back(currIndent);
1295 if (updateParenStack)
1296 parenIndentStack->emplace_back(previousIndent);
1300 if (updateParenStack)
1301 parenIndentStack->emplace_back(i + spaceIndentCount_ - runInIndentContinuation);
1303 int tabIncrement = tabIncrementIn;
1305 // check for following tabs
1306 for (int j = i + 1; j < (i + nextNonWSChar); j++)
1308 if (line[j] == '\t')
1309 tabIncrement += convertTabToSpaces(j, tabIncrement);
1312 int continuationIndentCount = i + nextNonWSChar + spaceIndentCount_ + tabIncrement;
1314 // check for run-in statement
1315 if (i > 0 && line[0] == '{')
1316 continuationIndentCount -= indentLength;
1318 if (continuationIndentCount < minIndent)
1319 continuationIndentCount = minIndent + spaceIndentCount_;
1321 // this is not done for an in-statement array
1322 if (continuationIndentCount > maxContinuationIndent
1323 && !(prevNonLegalCh == '=' && currentNonLegalCh == '{'))
1324 continuationIndentCount = indentLength * 2 + spaceIndentCount_;
1326 if (!continuationIndentStack->empty()
1327 && continuationIndentCount < continuationIndentStack->back())
1328 continuationIndentCount = continuationIndentStack->back();
1330 // the block opener is not indented for a NonInStatementArray
1331 if ((isNonInStatementArray && line[i] == '{')
1332 && !isInEnum && !braceBlockStateStack->empty() && braceBlockStateStack->back())
1333 continuationIndentCount = 0;
1335 continuationIndentStack->emplace_back(continuationIndentCount);
1339 * Register a continuation indent for a class header or a class initializer colon.
1341 void ASBeautifier::registerContinuationIndentColon(const string& line, int i, int tabIncrementIn)
1343 assert(line[i] == ':');
1344 assert(isInClassInitializer || isInClassHeaderTab);
1346 // register indent at first word after the colon
1347 size_t firstChar = line.find_first_not_of(" \t");
1348 if (firstChar == (size_t) i) // firstChar is ':'
1350 size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);
1351 if (firstChar != string::npos)
1353 int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn;
1354 continuationIndentStack->emplace_back(continuationIndentCount);
1355 isContinuation = true;
1361 * Compute indentation for a preprocessor #if statement.
1362 * This may be called for the activeBeautiferStack
1363 * instead of the active ASBeautifier object.
1365 pair<int, int> ASBeautifier::computePreprocessorIndent()
1367 computePreliminaryIndentation();
1368 pair<int, int> entry(indentCount, spaceIndentCount);
1369 if (!headerStack->empty()
1371 && (headerStack->back() == &AS_IF
1372 || headerStack->back() == &AS_ELSE
1373 || headerStack->back() == &AS_FOR
1374 || headerStack->back() == &AS_WHILE))
1380 * get distance to the next non-white space, non-comment character in the line.
1381 * if no such character exists, return the length remaining to the end of the line.
1383 int ASBeautifier::getNextProgramCharDistance(const string& line, int i) const
1385 bool inComment = false;
1386 int remainingCharNum = line.length() - i;
1390 for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
1392 ch = line[i + charDistance];
1395 if (line.compare(i + charDistance, 2, "*/") == 0)
1402 else if (isWhiteSpace(ch))
1406 if (line.compare(i + charDistance, 2, "//") == 0)
1407 return remainingCharNum;
1408 if (line.compare(i + charDistance, 2, "/*") == 0)
1415 return charDistance;
1418 return charDistance;
1422 * find the index number of a string element in a container of strings
1424 * @return the index number of element in the container. -1 if element not found.
1425 * @param container a vector of strings.
1426 * @param element the element to find .
1428 int ASBeautifier::indexOf(const vector<const string*>& container, const string* element) const
1430 vector<const string*>::const_iterator where;
1432 where = find(container.begin(), container.end(), element);
1433 if (where == container.end())
1435 return (int) (where - container.begin());
1439 * convert tabs to spaces.
1440 * i is the position of the character to convert to spaces.
1441 * tabIncrementIn is the increment that must be added for tab indent characters
1442 * to get the correct column for the current tab.
1444 int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const
1446 int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength);
1447 return tabToSpacesAdjustment;
1451 * trim removes the white space surrounding a line.
1453 * @return the trimmed line.
1454 * @param str the line to trim.
1456 string ASBeautifier::trim(const string& str) const
1459 int end = str.length() - 1;
1461 while (start < end && isWhiteSpace(str[start]))
1464 while (start <= end && isWhiteSpace(str[end]))
1467 // don't trim if it ends in a continuation
1468 if (end > -1 && str[end] == '\\')
1469 end = str.length() - 1;
1471 string returnStr(str, start, end + 1 - start);
1476 * rtrim removes the white space from the end of a line.
1478 * @return the trimmed line.
1479 * @param str the line to trim.
1481 string ASBeautifier::rtrim(const string& str) const
1483 size_t len = str.length();
1484 size_t end = str.find_last_not_of(" \t");
1485 if (end == string::npos
1488 string returnStr(str, 0, end + 1);
1493 * Copy tempStacks for the copy constructor.
1494 * The value of the vectors must also be copied.
1496 vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier& other) const
1498 vector<vector<const string*>*>* tempStacksNew = new vector<vector<const string*>*>;
1499 vector<vector<const string*>*>::iterator iter;
1500 for (iter = other.tempStacks->begin();
1501 iter != other.tempStacks->end();
1504 vector<const string*>* newVec = new vector<const string*>;
1506 tempStacksNew->emplace_back(newVec);
1508 return tempStacksNew;
1512 * delete a member vectors to eliminate memory leak reporting
1514 void ASBeautifier::deleteBeautifierVectors()
1516 beautifierFileType = 9; // reset to an invalid type
1518 delete nonParenHeaders;
1519 delete preBlockStatements;
1520 delete preCommandHeaders;
1521 delete assignmentOperators;
1522 delete nonAssignmentOperators;
1523 delete indentableHeaders;
1527 * delete a vector object
1528 * T is the type of vector
1529 * used for all vectors except tempStacks
1531 template<typename T>
1532 void ASBeautifier::deleteContainer(T& container)
1534 if (container != nullptr)
1538 container = nullptr;
1543 * Delete the ASBeautifier vector object.
1544 * This is a vector of pointers to ASBeautifier objects allocated with the 'new' operator.
1545 * Therefore the ASBeautifier objects have to be deleted in addition to the
1546 * ASBeautifier pointer entries.
1548 void ASBeautifier::deleteBeautifierContainer(vector<ASBeautifier*>*& container)
1550 if (container != nullptr)
1552 vector<ASBeautifier*>::iterator iter = container->begin();
1553 while (iter < container->end())
1560 container = nullptr;
1565 * Delete the tempStacks vector object.
1566 * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
1567 * Therefore the strings have to be deleted in addition to the tempStacks entries.
1569 void ASBeautifier::deleteTempStacksContainer(vector<vector<const string*>*>*& container)
1571 if (container != nullptr)
1573 vector<vector<const string*>*>::iterator iter = container->begin();
1574 while (iter < container->end())
1581 container = nullptr;
1586 * initialize a vector object
1587 * T is the type of vector used for all vectors
1589 template<typename T>
1590 void ASBeautifier::initContainer(T& container, T value)
1592 // since the ASFormatter object is never deleted,
1593 // the existing vectors must be deleted before creating new ones
1594 if (container != nullptr)
1595 deleteContainer(container);
1600 * Initialize the tempStacks vector object.
1601 * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
1602 * Any residual entries are deleted before the vector is initialized.
1604 void ASBeautifier::initTempStacksContainer(vector<vector<const string*>*>*& container,
1605 vector<vector<const string*>*>* value)
1607 if (container != nullptr)
1608 deleteTempStacksContainer(container);
1613 * Determine if an assignment statement ends with a comma
1614 * that is not in a function argument. It ends with a
1615 * comma if a comma is the last char on the line.
1617 * @return true if line ends with a comma, otherwise false.
1619 bool ASBeautifier::statementEndsWithComma(const string& line, int index) const
1621 assert(line[index] == '=');
1623 bool isInComment_ = false;
1624 bool isInQuote_ = false;
1626 size_t lineLength = line.length();
1628 char quoteChar_ = ' ';
1630 for (i = index + 1; i < lineLength; ++i)
1636 if (line.compare(i, 2, "*/") == 0)
1638 isInComment_ = false;
1652 if (ch == quoteChar_)
1658 || (ch == '\'' && !isDigitSeparator(line, i)))
1665 if (line.compare(i, 2, "//") == 0)
1668 if (line.compare(i, 2, "/*") == 0)
1670 if (isLineEndComment(line, i))
1674 isInComment_ = true;
1690 size_t lastChar = line.find_last_not_of(" \t", i - 1);
1692 if (lastChar == string::npos || line[lastChar] != ',')
1699 * check if current comment is a line-end comment
1701 * @return is before a line-end comment.
1703 bool ASBeautifier::isLineEndComment(const string& line, int startPos) const
1705 assert(line.compare(startPos, 2, "/*") == 0);
1707 // comment must be closed on this line with nothing after it
1708 size_t endNum = line.find("*/", startPos + 2);
1709 if (endNum != string::npos)
1711 size_t nextChar = line.find_first_not_of(" \t", endNum + 2);
1712 if (nextChar == string::npos)
1719 * get the previous word index for an assignment operator
1721 * @return is the index to the previous word (the in statement indent).
1723 int ASBeautifier::getContinuationIndentAssign(const string& line, size_t currPos) const
1725 assert(line[currPos] == '=');
1730 // get the last legal word (may be a number)
1731 size_t end = line.find_last_not_of(" \t", currPos - 1);
1732 if (end == string::npos || !isLegalNameChar(line[end]))
1735 int start; // start of the previous word
1736 for (start = end; start > -1; start--)
1738 if (!isLegalNameChar(line[start]) || line[start] == '.')
1747 * get the instatement indent for a comma
1749 * @return is the indent to the second word on the line (the in statement indent).
1751 int ASBeautifier::getContinuationIndentComma(const string& line, size_t currPos) const
1753 assert(line[currPos] == ',');
1755 // get first word on a line
1756 size_t indent = line.find_first_not_of(" \t");
1757 if (indent == string::npos || !isLegalNameChar(line[indent]))
1760 // bypass first word
1761 for (; indent < currPos; indent++)
1763 if (!isLegalNameChar(line[indent]))
1767 if (indent >= currPos || indent < 4)
1770 // point to second word or assignment operator
1771 indent = line.find_first_not_of(" \t", indent);
1772 if (indent == string::npos || indent >= currPos)
1779 * get the next word on a line
1780 * the argument 'currPos' must point to the current position.
1782 * @return is the next word or an empty string if none found.
1784 string ASBeautifier::getNextWord(const string& line, size_t currPos) const
1786 size_t lineLength = line.length();
1787 // get the last legal word (may be a number)
1788 if (currPos == lineLength - 1)
1791 size_t start = line.find_first_not_of(" \t", currPos + 1);
1792 if (start == string::npos || !isLegalNameChar(line[start]))
1795 size_t end; // end of the current word
1796 for (end = start + 1; end <= lineLength; end++)
1798 if (!isLegalNameChar(line[end]) || line[end] == '.')
1802 return line.substr(start, end - start);
1806 * Check if a preprocessor directive is always indented.
1807 * C# "region" and "endregion" are always indented.
1808 * C/C++ "pragma omp" is always indented.
1810 * @return is true or false.
1812 bool ASBeautifier::isIndentedPreprocessor(const string& line, size_t currPos) const
1814 assert(line[0] == '#');
1815 string nextWord = getNextWord(line, currPos);
1816 if (nextWord == "region" || nextWord == "endregion")
1818 // is it #pragma omp
1819 if (nextWord == "pragma")
1822 size_t start = line.find("pragma");
1823 if (start == string::npos || !isLegalNameChar(line[start]))
1826 for (; start < line.length(); start++)
1828 if (!isLegalNameChar(line[start]))
1832 if (start >= line.length())
1834 // point to start of second word
1835 start = line.find_first_not_of(" \t", start);
1836 if (start == string::npos)
1838 // point to end of second word
1840 for (end = start; end < line.length(); end++)
1842 if (!isLegalNameChar(line[end]))
1845 // check for "pragma omp"
1846 string word = line.substr(start, end - start);
1847 if (word == "omp" || word == "region" || word == "endregion")
1854 * Check if a preprocessor directive is checking for __cplusplus defined.
1856 * @return is true or false.
1858 bool ASBeautifier::isPreprocessorConditionalCplusplus(const string& line) const
1860 string preproc = trim(line.substr(1));
1861 if (preproc.compare(0, 5, "ifdef") == 0 && getNextWord(preproc, 4) == "__cplusplus")
1863 if (preproc.compare(0, 2, "if") == 0)
1865 // check for " #if defined(__cplusplus)"
1867 charNum = preproc.find_first_not_of(" \t", charNum);
1868 if (charNum != string::npos && preproc.compare(charNum, 7, "defined") == 0)
1871 charNum = preproc.find_first_not_of(" \t", charNum);
1872 if (preproc.compare(charNum, 1, "(") == 0)
1875 charNum = preproc.find_first_not_of(" \t", charNum);
1876 if (preproc.compare(charNum, 11, "__cplusplus") == 0)
1885 * Check if a preprocessor definition contains an unterminated comment.
1886 * Comments within a preprocessor definition can be continued without the backslash.
1888 * @return is true or false.
1890 bool ASBeautifier::isInPreprocessorUnterminatedComment(const string& line)
1892 if (!isInPreprocessorComment)
1894 size_t startPos = line.find("/*");
1895 if (startPos == string::npos)
1898 size_t endNum = line.find("*/");
1899 if (endNum != string::npos)
1901 isInPreprocessorComment = false;
1904 isInPreprocessorComment = true;
1908 void ASBeautifier::popLastContinuationIndent()
1910 assert(!continuationIndentStackSizeStack->empty());
1911 int previousIndentStackSize = continuationIndentStackSizeStack->back();
1912 if (continuationIndentStackSizeStack->size() > 1)
1913 continuationIndentStackSizeStack->pop_back();
1914 while (previousIndentStackSize < (int) continuationIndentStack->size())
1915 continuationIndentStack->pop_back();
1919 int ASBeautifier::getBeautifierFileType() const
1920 { return beautifierFileType; }
1923 * Process preprocessor statements and update the beautifier stacks.
1925 void ASBeautifier::processPreprocessor(const string& preproc, const string& line)
1927 // When finding a multi-lined #define statement, the original beautifier
1928 // 1. sets its isInDefineDefinition flag
1929 // 2. clones a new beautifier that will be used for the actual indentation
1930 // of the #define. This clone is put into the activeBeautifierStack in order
1931 // to be called for the actual indentation.
1932 // The original beautifier will have isInDefineDefinition = true, isInDefine = false
1933 // The cloned beautifier will have isInDefineDefinition = true, isInDefine = true
1934 if (shouldIndentPreprocDefine && preproc == "define" && line[line.length() - 1] == '\\')
1936 if (!isInDefineDefinition)
1938 // this is the original beautifier
1939 isInDefineDefinition = true;
1941 // push a new beautifier into the active stack
1942 // this beautifier will be used for the indentation of this define
1943 ASBeautifier* defineBeautifier = new ASBeautifier(*this);
1944 activeBeautifierStack->emplace_back(defineBeautifier);
1948 // the is the cloned beautifier that is in charge of indenting the #define.
1952 else if (preproc.length() >= 2 && preproc.substr(0, 2) == "if")
1954 if (isPreprocessorConditionalCplusplus(line) && !g_preprocessorCppExternCBrace)
1955 g_preprocessorCppExternCBrace = 1;
1956 // push a new beautifier into the stack
1957 waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
1958 activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
1959 if (activeBeautifierStackLengthStack->back() == 0)
1960 waitingBeautifierStack->emplace_back(new ASBeautifier(*this));
1962 waitingBeautifierStack->emplace_back(new ASBeautifier(*activeBeautifierStack->back()));
1964 else if (preproc == "else")
1966 if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
1968 // MOVE current waiting beautifier to active stack.
1969 activeBeautifierStack->emplace_back(waitingBeautifierStack->back());
1970 waitingBeautifierStack->pop_back();
1973 else if (preproc == "elif")
1975 if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
1977 // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
1978 activeBeautifierStack->emplace_back(new ASBeautifier(*(waitingBeautifierStack->back())));
1981 else if (preproc == "endif")
1983 int stackLength = 0;
1984 ASBeautifier* beautifier = nullptr;
1986 if (waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty())
1988 stackLength = waitingBeautifierStackLengthStack->back();
1989 waitingBeautifierStackLengthStack->pop_back();
1990 while ((int) waitingBeautifierStack->size() > stackLength)
1992 beautifier = waitingBeautifierStack->back();
1993 waitingBeautifierStack->pop_back();
1998 if (!activeBeautifierStackLengthStack->empty())
2000 stackLength = activeBeautifierStackLengthStack->back();
2001 activeBeautifierStackLengthStack->pop_back();
2002 while ((int) activeBeautifierStack->size() > stackLength)
2004 beautifier = activeBeautifierStack->back();
2005 activeBeautifierStack->pop_back();
2012 // Compute the preliminary indentation based on data in the headerStack
2013 // and data from previous lines.
2014 // Update the class variable indentCount.
2015 void ASBeautifier::computePreliminaryIndentation()
2018 spaceIndentCount = 0;
2019 isInClassHeaderTab = false;
2021 if (isInObjCMethodDefinition && !continuationIndentStack->empty())
2022 spaceIndentObjCMethodAlignment = continuationIndentStack->back();
2024 if (!continuationIndentStack->empty())
2025 spaceIndentCount = continuationIndentStack->back();
2027 for (size_t i = 0; i < headerStack->size(); i++)
2033 // do NOT indent opening block for these headers
2034 if (!((*headerStack)[i] == &AS_NAMESPACE
2035 || (*headerStack)[i] == &AS_MODULE
2036 || (*headerStack)[i] == &AS_CLASS
2037 || (*headerStack)[i] == &AS_STRUCT
2038 || (*headerStack)[i] == &AS_UNION
2039 || (*headerStack)[i] == &AS_INTERFACE
2040 || (*headerStack)[i] == &AS_THROWS
2041 || (*headerStack)[i] == &AS_STATIC))
2044 else if (!(i > 0 && (*headerStack)[i - 1] != &AS_OPEN_BRACE
2045 && (*headerStack)[i] == &AS_OPEN_BRACE))
2048 if (!isJavaStyle() && !namespaceIndent && i > 0
2049 && ((*headerStack)[i - 1] == &AS_NAMESPACE
2050 || (*headerStack)[i - 1] == &AS_MODULE)
2051 && (*headerStack)[i] == &AS_OPEN_BRACE)
2054 if (isCStyle() && i >= 1
2055 && (*headerStack)[i - 1] == &AS_CLASS
2056 && (*headerStack)[i] == &AS_OPEN_BRACE)
2063 // is the switchIndent option is on, indent switch statements an additional indent.
2064 else if (switchIndent && i > 1
2065 && (*headerStack)[i - 1] == &AS_SWITCH
2066 && (*headerStack)[i] == &AS_OPEN_BRACE)
2072 } // end of for loop
2074 if (isInClassHeader)
2077 isInClassHeaderTab = true;
2078 if (lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment)
2080 if (!lineBeginsWithOpenBrace)
2082 if (!continuationIndentStack->empty())
2083 spaceIndentCount -= continuationIndentStack->back();
2085 else if (blockIndent)
2087 if (!lineBeginsWithOpenBrace)
2092 if (isInClassInitializer || isInEnumTypeID)
2094 indentCount += classInitializerIndents;
2097 if (isInEnum && lineBeginsWithComma && !continuationIndentStack->empty())
2099 // unregister '=' indent from the previous line
2100 continuationIndentStack->pop_back();
2101 isContinuation = false;
2102 spaceIndentCount = 0;
2105 // Objective-C interface continuation line
2106 if (isInObjCInterface)
2109 // unindent a class closing brace...
2110 if (!lineStartsInComment
2114 && headerStack->size() >= 2
2115 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
2116 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
2117 && lineBeginsWithCloseBrace
2118 && braceBlockStateStack->back())
2121 // unindent an indented switch closing brace...
2122 else if (!lineStartsInComment
2125 && headerStack->size() >= 2
2126 && (*headerStack)[headerStack->size() - 2] == &AS_SWITCH
2127 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
2128 && lineBeginsWithCloseBrace)
2131 // handle special case of run-in comment in an indented class statement
2135 && !lineOpensWithComment
2136 && headerStack->size() > 1
2137 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS)
2140 if (isInConditional)
2142 if (g_preprocessorCppExternCBrace >= 4)
2146 void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHeaderIndent)
2148 if (lineStartsInComment)
2151 // unindent a one-line statement in a header indent
2153 && lineBeginsWithOpenBrace
2154 && headerStack->size() < iPrelim
2155 && isInExtraHeaderIndent
2156 && (lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2157 && shouldIndentBracedLine)
2161 * if '{' doesn't follow an immediately previous '{' in the headerStack
2162 * (but rather another header such as "for" or "if", then unindent it
2163 * by one indentation relative to its block.
2165 else if (!blockIndent
2166 && lineBeginsWithOpenBrace
2167 && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2168 && (headerStack->size() > 1 && (*headerStack)[headerStack->size() - 2] != &AS_OPEN_BRACE)
2169 && shouldIndentBracedLine)
2172 // must check one less in headerStack if more than one header on a line (allow-addins)...
2173 else if (headerStack->size() > iPrelim + 1
2175 && lineBeginsWithOpenBrace
2176 && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2177 && (headerStack->size() > 2 && (*headerStack)[headerStack->size() - 3] != &AS_OPEN_BRACE)
2178 && shouldIndentBracedLine)
2181 // unindent a closing brace...
2182 else if (lineBeginsWithCloseBrace
2183 && shouldIndentBracedLine)
2186 // correctly indent one-line-blocks...
2187 else if (lineOpeningBlocksNum > 0
2188 && lineOpeningBlocksNum == lineClosingBlocksNum
2189 && previousLineProbationTab)
2192 if (indentCount < 0)
2195 // take care of extra brace indentation option...
2196 if (!lineStartsInComment
2198 && shouldIndentBracedLine
2199 && (lineBeginsWithOpenBrace || lineBeginsWithCloseBrace))
2201 if (!braceIndentVtk)
2205 // determine if a style VTK brace is indented
2206 bool haveUnindentedBrace = false;
2207 for (size_t i = 0; i < headerStack->size(); i++)
2209 if (((*headerStack)[i] == &AS_NAMESPACE
2210 || (*headerStack)[i] == &AS_MODULE
2211 || (*headerStack)[i] == &AS_CLASS
2212 || (*headerStack)[i] == &AS_STRUCT)
2213 && i + 1 < headerStack->size()
2214 && (*headerStack)[i + 1] == &AS_OPEN_BRACE)
2216 else if (lineBeginsWithOpenBrace)
2218 // don't double count the current brace
2219 if (i + 1 < headerStack->size()
2220 && (*headerStack)[i] == &AS_OPEN_BRACE)
2221 haveUnindentedBrace = true;
2223 else if ((*headerStack)[i] == &AS_OPEN_BRACE)
2224 haveUnindentedBrace = true;
2225 } // end of for loop
2226 if (haveUnindentedBrace)
2233 * Compute indentCount adjustment when in a series of else-if statements
2234 * and shouldBreakElseIfs is requested.
2235 * It increments by one for each 'else' in the tempStack.
2237 int ASBeautifier::adjustIndentCountForBreakElseIfComments() const
2239 assert(isElseHeaderIndent && !tempStacks->empty());
2240 int indentCountIncrement = 0;
2241 vector<const string*>* lastTempStack = tempStacks->back();
2242 if (lastTempStack != nullptr)
2244 for (size_t i = 0; i < lastTempStack->size(); i++)
2246 if (*lastTempStack->at(i) == AS_ELSE)
2247 indentCountIncrement++;
2250 return indentCountIncrement;
2254 * Extract a preprocessor statement without the #.
2255 * If a error occurs an empty string is returned.
2257 string ASBeautifier::extractPreprocessorStatement(const string& line) const
2260 size_t start = line.find_first_not_of("#/ \t");
2261 if (start == string::npos)
2263 size_t end = line.find_first_of("/ \t", start);
2264 if (end == string::npos)
2265 end = line.length();
2266 preproc = line.substr(start, end - start);
2270 void ASBeautifier::adjustObjCMethodDefinitionIndentation(const string& line_)
2272 // register indent for Objective-C continuation line
2273 if (line_.length() > 0
2274 && (line_[0] == '-' || line_[0] == '+'))
2276 if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
2278 string convertedLine = getIndentedSpaceEquivalent(line_);
2279 colonIndentObjCMethodAlignment = convertedLine.find(':');
2280 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
2281 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
2282 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
2284 else if (continuationIndentStack->empty()
2285 || continuationIndentStack->back() == 0)
2287 continuationIndentStack->emplace_back(indentLength);
2288 isContinuation = true;
2291 // set indent for last definition line
2292 else if (!lineBeginsWithOpenBrace)
2294 if (shouldAlignMethodColon)
2295 spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
2296 else if (continuationIndentStack->empty())
2297 spaceIndentCount = spaceIndentObjCMethodAlignment;
2301 void ASBeautifier::adjustObjCMethodCallIndentation(const string& line_)
2303 static int keywordIndentObjCMethodAlignment = 0;
2304 if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
2306 if (isInObjCMethodCallFirst)
2308 isInObjCMethodCallFirst = false;
2309 string convertedLine = getIndentedSpaceEquivalent(line_);
2310 bracePosObjCMethodAlignment = convertedLine.find('[');
2311 keywordIndentObjCMethodAlignment =
2312 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
2313 colonIndentObjCMethodAlignment = convertedLine.find(':');
2314 if (colonIndentObjCMethodAlignment >= 0)
2316 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
2317 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
2318 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
2319 if (lineBeginsWithOpenBrace)
2320 colonIndentObjCMethodAlignment -= indentLength;
2325 if (line_.find(':') != string::npos)
2327 if (colonIndentObjCMethodAlignment < 0)
2328 spaceIndentCount += computeObjCColonAlignment(line_, objCColonAlignSubsequent);
2329 else if (objCColonAlignSubsequent > colonIndentObjCMethodAlignment)
2330 spaceIndentCount = computeObjCColonAlignment(line_, objCColonAlignSubsequent);
2332 spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
2336 if (spaceIndentCount < colonIndentObjCMethodAlignment)
2337 spaceIndentCount += keywordIndentObjCMethodAlignment;
2341 else // align keywords instead of colons
2343 if (isInObjCMethodCallFirst)
2345 isInObjCMethodCallFirst = false;
2346 string convertedLine = getIndentedSpaceEquivalent(line_);
2347 bracePosObjCMethodAlignment = convertedLine.find('[');
2348 keywordIndentObjCMethodAlignment =
2349 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
2353 if (spaceIndentCount < keywordIndentObjCMethodAlignment + bracePosObjCMethodAlignment)
2354 spaceIndentCount += keywordIndentObjCMethodAlignment;
2360 * Clear the variables used to align the Objective-C method definitions.
2362 void ASBeautifier::clearObjCMethodDefinitionAlignment()
2364 assert(isImmediatelyPostObjCMethodDefinition);
2365 spaceIndentCount = 0;
2366 spaceIndentObjCMethodAlignment = 0;
2367 colonIndentObjCMethodAlignment = 0;
2368 isInObjCMethodDefinition = false;
2369 isImmediatelyPostObjCMethodDefinition = false;
2370 if (!continuationIndentStack->empty())
2371 continuationIndentStack->pop_back();
2375 * Compute the spaceIndentCount necessary to align the current line colon
2376 * with the colon position in the argument.
2377 * If it cannot be aligned indentLength is returned and a new colon
2378 * position is calculated.
2380 int ASBeautifier::computeObjCColonAlignment(const string& line, int colonAlignPosition) const
2382 int colonPosition = line.find(':');
2383 if (colonPosition < 0 || colonPosition > colonAlignPosition)
2384 return indentLength;
2385 return (colonAlignPosition - colonPosition);
2389 * Compute postition of the keyword following the method call object.
2391 int ASBeautifier::getObjCFollowingKeyword(const string& line, int bracePos) const
2393 assert(line[bracePos] == '[');
2394 size_t firstText = line.find_first_not_of(" \t", bracePos + 1);
2395 if (firstText == string::npos)
2396 return -(indentCount * indentLength - 1);
2397 size_t searchBeg = firstText;
2398 size_t objectEnd = 0; // end of object text
2399 if (line[searchBeg] == '[')
2401 objectEnd = line.find(']', searchBeg + 1);
2402 if (objectEnd == string::npos)
2407 if (line[searchBeg] == '(')
2409 searchBeg = line.find(')', searchBeg + 1);
2410 if (searchBeg == string::npos)
2413 // bypass the object name
2414 objectEnd = line.find_first_of(" \t", searchBeg + 1);
2415 if (objectEnd == string::npos)
2419 size_t keyPos = line.find_first_not_of(" \t", objectEnd + 1);
2420 if (keyPos == string::npos)
2422 return keyPos - firstText;
2426 * Get a line using the current space indent with all tabs replaced by spaces.
2427 * The indentCount is NOT included
2428 * Needed to compute an accurate alignment.
2430 string ASBeautifier::getIndentedSpaceEquivalent(const string& line_) const
2433 spaceIndent.append(spaceIndentCount, ' ');
2434 string convertedLine = spaceIndent + line_;
2435 for (size_t i = spaceIndent.length(); i < convertedLine.length(); i++)
2437 if (convertedLine[i] == '\t')
2439 size_t numSpaces = indentLength - (i % indentLength);
2440 convertedLine.replace(i, 1, numSpaces, ' ');
2441 i += indentLength - 1;
2444 return convertedLine;
2448 * Parse the current line to update indentCount and spaceIndentCount.
2450 void ASBeautifier::parseCurrentLine(const string& line)
2452 bool isInLineComment = false;
2453 bool isInOperator = false;
2454 bool isSpecialChar = false;
2455 bool haveCaseIndent = false;
2456 bool haveAssignmentThisLine = false;
2457 bool closingBraceReached = false;
2458 bool previousLineProbation = (probationHeader != nullptr);
2460 int tabIncrementIn = 0;
2462 && !haveLineContinuationChar
2463 && !isInVerbatimQuote
2465 isInQuote = false; // missing closing quote
2466 haveLineContinuationChar = false;
2468 for (size_t i = 0; i < line.length(); i++)
2472 if (isInBeautifySQL)
2475 // handle special characters (i.e. backslash+character such as \n, \t, ...)
2476 if (isInQuote && !isInVerbatimQuote)
2480 isSpecialChar = false;
2483 if (line.compare(i, 2, "\\\\") == 0)
2490 if (peekNextChar(line, i) == ' ') // is this '\' at end of line
2491 haveLineContinuationChar = true;
2493 isSpecialChar = true;
2497 else if (isInDefine && ch == '\\')
2500 // bypass whitespace here
2501 if (isWhiteSpace(ch))
2504 tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
2508 // handle quotes (such as 'x' and "Hello Dolly")
2509 if (!(isInComment || isInLineComment)
2511 || (ch == '\'' && !isDigitSeparator(line, i))))
2517 char prevCh = i > 0 ? line[i - 1] : ' ';
2518 if (isCStyle() && prevCh == 'R')
2520 int parenPos = line.find('(', i);
2523 isInVerbatimQuote = true;
2524 verbatimDelimiter = line.substr(i + 1, parenPos - i - 1);
2527 else if (isSharpStyle() && prevCh == '@')
2528 isInVerbatimQuote = true;
2529 // check for "C" following "extern"
2530 else if (g_preprocessorCppExternCBrace == 2 && line.compare(i, 3, "\"C\"") == 0)
2531 ++g_preprocessorCppExternCBrace;
2533 else if (isInVerbatimQuote && ch == '"')
2537 string delim = ')' + verbatimDelimiter;
2538 int delimStart = i - delim.length();
2539 if (delimStart > 0 && line.substr(delimStart, delim.length()) == delim)
2542 isInVerbatimQuote = false;
2545 else if (isSharpStyle())
2547 if (line.compare(i, 2, "\"\"") == 0)
2552 isInVerbatimQuote = false;
2557 else if (quoteChar == ch)
2560 isContinuation = true;
2569 if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
2571 // if there is a 'case' statement after these comments unindent by 1
2572 if (isCaseHeaderCommentIndent)
2574 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2575 // if there is an 'else' after these comments a tempStacks indent is required
2576 if (isElseHeaderIndent && lineOpensWithLineComment && !tempStacks->empty())
2577 indentCount += adjustIndentCountForBreakElseIfComments();
2578 isInLineComment = true;
2582 else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
2584 // if there is a 'case' statement after these comments unindent by 1
2585 if (isCaseHeaderCommentIndent && lineOpensWithComment)
2587 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2588 // if there is an 'else' after these comments a tempStacks indent is required
2589 if (isElseHeaderIndent && lineOpensWithComment && !tempStacks->empty())
2590 indentCount += adjustIndentCountForBreakElseIfComments();
2593 if (!lineOpensWithComment) // does line start with comment?
2594 blockCommentNoIndent = true; // if no, cannot indent continuation lines
2597 else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
2599 size_t firstText = line.find_first_not_of(" \t");
2600 // if there is a 'case' statement after these comments unindent by 1
2601 // only if the ending comment is the first entry on the line
2602 if (isCaseHeaderCommentIndent && firstText == i)
2604 // if this comment close starts the line, must check for else-if indent
2605 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2606 // if there is an 'else' after these comments a tempStacks indent is required
2609 if (isElseHeaderIndent && !lineOpensWithComment && !tempStacks->empty())
2610 indentCount += adjustIndentCountForBreakElseIfComments();
2612 isInComment = false;
2614 blockCommentNoIndent = false; // ok to indent next comment
2617 // treat indented preprocessor lines as a line comment
2618 else if (line[0] == '#' && isIndentedPreprocessor(line, i))
2620 isInLineComment = true;
2623 if (isInLineComment)
2625 // bypass rest of the comment up to the comment end
2626 while (i + 1 < line.length())
2633 // if there is a 'case' statement after these comments unindent by 1
2634 if (!lineOpensWithComment && isCaseHeaderCommentIndent)
2636 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2637 // if there is an 'else' after these comments a tempStacks indent is required
2638 if (!lineOpensWithComment && isElseHeaderIndent && !tempStacks->empty())
2639 indentCount += adjustIndentCountForBreakElseIfComments();
2640 // bypass rest of the comment up to the comment end
2641 while (i + 1 < line.length()
2642 && line.compare(i + 1, 2, "*/") != 0)
2648 // if we have reached this far then we are NOT in a comment or string of special character...
2650 if (probationHeader != nullptr)
2652 if ((probationHeader == &AS_STATIC && ch == '{')
2653 || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
2655 // insert the probation header as a new header
2657 headerStack->emplace_back(probationHeader);
2659 // handle the specific probation header
2660 isInConditional = (probationHeader == &AS_SYNCHRONIZED);
2662 isContinuation = false;
2663 // if the probation comes from the previous line, then indent by 1 tab count.
2664 if (previousLineProbation
2666 && !(blockIndent && probationHeader == &AS_STATIC))
2669 previousLineProbationTab = true;
2671 previousLineProbation = false;
2674 // dismiss the probation header
2675 probationHeader = nullptr;
2678 prevNonSpaceCh = currentNonSpaceCh;
2679 currentNonSpaceCh = ch;
2680 if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
2682 prevNonLegalCh = currentNonLegalCh;
2683 currentNonLegalCh = ch;
2689 currentHeader = headerStack->back();
2692 currentHeader = nullptr;
2694 if (isCStyle() && isInTemplate
2695 && (ch == '<' || ch == '>')
2696 && !(line.length() > i + 1 && line.compare(i, 2, ">=") == 0))
2701 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2702 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2706 popLastContinuationIndent();
2707 if (--templateDepth <= 0)
2710 isInTemplate = false;
2716 // handle parentheses
2717 if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
2719 if (ch == '(' || ch == '[')
2721 isInOperator = false;
2722 // if have a struct header, this is a declaration not a definition
2724 && !headerStack->empty()
2725 && headerStack->back() == &AS_STRUCT)
2727 headerStack->pop_back();
2728 isInClassHeader = false;
2729 if (line.find(AS_STRUCT, 0) > i) // if not on this line
2730 indentCount -= classInitializerIndents;
2731 if (indentCount < 0)
2735 if (parenDepth == 0)
2737 parenStatementStack->push_back(isContinuation);
2738 isContinuation = true;
2743 ++squareBracketCount;
2744 if (squareBracketCount == 1 && isCStyle())
2746 isInObjCMethodCall = true;
2747 isInObjCMethodCallFirst = true;
2751 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2753 if (currentHeader != nullptr)
2754 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent, true);
2756 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2758 else if (ch == ')' || ch == ']')
2761 --squareBracketCount;
2762 if (squareBracketCount <= 0)
2764 squareBracketCount = 0;
2765 if (isInObjCMethodCall)
2766 isImmediatelyPostObjCMethodCall = true;
2768 foundPreCommandHeader = false;
2770 if (parenDepth == 0)
2772 if (!parenStatementStack->empty()) // in case of unmatched closing parens
2774 isContinuation = parenStatementStack->back();
2775 parenStatementStack->pop_back();
2778 isInConditional = false;
2781 if (!continuationIndentStackSizeStack->empty())
2783 popLastContinuationIndent();
2785 if (!parenIndentStack->empty())
2787 int poppedIndent = parenIndentStack->back();
2788 parenIndentStack->pop_back();
2791 spaceIndentCount = poppedIndent;
2800 // first, check if '{' is a block-opener or a static-array opener
2801 bool isBlockOpener = ((prevNonSpaceCh == '{' && braceBlockStateStack->back())
2802 || prevNonSpaceCh == '}'
2803 || prevNonSpaceCh == ')'
2804 || prevNonSpaceCh == ';'
2805 || peekNextChar(line, i) == '{'
2806 || foundPreCommandHeader
2807 || foundPreCommandMacro
2809 || (isInClassInitializer && !isLegalNameChar(prevNonSpaceCh))
2810 || isNonInStatementArray
2811 || isInObjCMethodDefinition
2812 || isInObjCInterface
2817 || getNextWord(line, i) == AS_NEW
2819 && (prevNonSpaceCh == '('
2820 || isLegalNameChar(prevNonSpaceCh))));
2822 if (isInObjCMethodDefinition)
2824 objCColonAlignSubsequent = 0;
2825 isImmediatelyPostObjCMethodDefinition = true;
2826 if (lineBeginsWithOpenBrace) // for run-in braces
2827 clearObjCMethodDefinitionAlignment();
2830 if (!isBlockOpener && !isContinuation && !isInClassInitializer && !isInEnum)
2832 if (headerStack->empty())
2833 isBlockOpener = true;
2834 else if (headerStack->back() == &AS_OPEN_BRACE
2835 && headerStack->size() >= 2)
2837 if ((*headerStack)[headerStack->size() - 2] == &AS_NAMESPACE
2838 || (*headerStack)[headerStack->size() - 2] == &AS_MODULE
2839 || (*headerStack)[headerStack->size() - 2] == &AS_CLASS
2840 || (*headerStack)[headerStack->size() - 2] == &AS_INTERFACE
2841 || (*headerStack)[headerStack->size() - 2] == &AS_STRUCT
2842 || (*headerStack)[headerStack->size() - 2] == &AS_UNION)
2843 isBlockOpener = true;
2845 else if (headerStack->back() == &AS_NAMESPACE
2846 || headerStack->back() == &AS_MODULE
2847 || headerStack->back() == &AS_CLASS
2848 || headerStack->back() == &AS_INTERFACE
2849 || headerStack->back() == &AS_STRUCT
2850 || headerStack->back() == &AS_UNION)
2851 isBlockOpener = true;
2854 if (!isBlockOpener && currentHeader != nullptr)
2856 for (size_t n = 0; n < nonParenHeaders->size(); n++)
2857 if (currentHeader == (*nonParenHeaders)[n])
2859 isBlockOpener = true;
2864 braceBlockStateStack->push_back(isBlockOpener);
2868 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2869 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2872 shouldIndentBracedLine = false;
2873 isInEnumTypeID = false;
2878 // this brace is a block opener...
2880 ++lineOpeningBlocksNum;
2882 if (isInClassInitializer || isInEnumTypeID)
2884 // decrease tab count if brace is broken
2885 if (lineBeginsWithOpenBrace)
2887 indentCount -= classInitializerIndents;
2888 // decrease one more if an empty class
2889 if (!headerStack->empty()
2890 && (*headerStack).back() == &AS_CLASS)
2892 int nextChar = getNextProgramCharDistance(line, i);
2893 if ((int) line.length() > nextChar && line[nextChar] == '}')
2899 if (isInObjCInterface)
2901 isInObjCInterface = false;
2902 if (lineBeginsWithOpenBrace)
2906 if (braceIndent && !namespaceIndent && !headerStack->empty()
2907 && ((*headerStack).back() == &AS_NAMESPACE
2908 || (*headerStack).back() == &AS_MODULE))
2910 shouldIndentBracedLine = false;
2914 // an indentable struct is treated like a class in the header stack
2915 if (!headerStack->empty()
2916 && (*headerStack).back() == &AS_STRUCT
2917 && isInIndentableStruct)
2918 (*headerStack).back() = &AS_CLASS;
2920 squareBracketDepthStack->emplace_back(parenDepth);
2921 blockStatementStack->push_back(isContinuation);
2923 if (!continuationIndentStack->empty())
2925 // completely purge the inStatementIndentStack
2926 while (!continuationIndentStack->empty())
2927 popLastContinuationIndent();
2928 if (isInClassInitializer || isInClassHeaderTab)
2930 if (lineBeginsWithOpenBrace || lineBeginsWithComma)
2931 spaceIndentCount = 0;
2934 spaceIndentCount = 0;
2937 blockTabCount += (isContinuation ? 1 : 0);
2938 if (g_preprocessorCppExternCBrace == 3)
2939 ++g_preprocessorCppExternCBrace;
2941 isInClassHeader = false;
2942 isInClassHeaderTab = false;
2943 isInClassInitializer = false;
2944 isInEnumTypeID = false;
2945 isContinuation = false;
2946 isInQuestion = false;
2948 foundPreCommandHeader = false;
2949 foundPreCommandMacro = false;
2950 isInExternC = false;
2952 tempStacks->emplace_back(new vector<const string*>);
2953 headerStack->emplace_back(&AS_OPEN_BRACE);
2954 lastLineHeader = &AS_OPEN_BRACE;
2959 //check if a header has been reached
2960 bool isPotentialHeader = isCharPotentialHeader(line, i);
2962 if (isPotentialHeader && squareBracketCount == 0)
2964 const string* newHeader = findHeader(line, i, headers);
2966 // Qt headers may be variables in C++
2968 && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
2970 if (line.find_first_of("=;", i) != string::npos)
2971 newHeader = nullptr;
2973 else if (newHeader == &AS_USING
2974 && ASBeautifier::peekNextChar(line, i + (*newHeader).length() - 1) != '(')
2975 newHeader = nullptr;
2977 if (newHeader != nullptr)
2979 // if we reached here, then this is a header...
2980 bool isIndentableHeader = true;
2984 vector<const string*>* lastTempStack = nullptr;;
2985 if (!tempStacks->empty())
2986 lastTempStack = tempStacks->back();
2988 // if a new block is opened, push a new stack into tempStacks to hold the
2989 // future list of headers in the new block.
2991 // take care of the special case: 'else if (...)'
2992 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
2994 headerStack->pop_back();
2997 // take care of 'else'
2998 else if (newHeader == &AS_ELSE)
3000 if (lastTempStack != nullptr)
3002 int indexOfIf = indexOf(*lastTempStack, &AS_IF);
3003 if (indexOfIf != -1)
3005 // recreate the header list in headerStack up to the previous 'if'
3006 // from the temporary snapshot stored in lastTempStack.
3007 int restackSize = lastTempStack->size() - indexOfIf - 1;
3008 for (int r = 0; r < restackSize; r++)
3010 headerStack->emplace_back(lastTempStack->back());
3011 lastTempStack->pop_back();
3013 if (!closingBraceReached)
3014 indentCount += restackSize;
3017 * If the above if is not true, i.e. no 'if' before the 'else',
3018 * then nothing beautiful will come out of this...
3019 * I should think about inserting an Exception here to notify the caller of this...
3024 // check if 'while' closes a previous 'do'
3025 else if (newHeader == &AS_WHILE)
3027 if (lastTempStack != nullptr)
3029 int indexOfDo = indexOf(*lastTempStack, &AS_DO);
3030 if (indexOfDo != -1)
3032 // recreate the header list in headerStack up to the previous 'do'
3033 // from the temporary snapshot stored in lastTempStack.
3034 int restackSize = lastTempStack->size() - indexOfDo - 1;
3035 for (int r = 0; r < restackSize; r++)
3037 headerStack->emplace_back(lastTempStack->back());
3038 lastTempStack->pop_back();
3040 if (!closingBraceReached)
3041 indentCount += restackSize;
3045 // check if 'catch' closes a previous 'try' or 'catch'
3046 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
3048 if (lastTempStack != nullptr)
3050 int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
3051 if (indexOfTry == -1)
3052 indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
3053 if (indexOfTry != -1)
3055 // recreate the header list in headerStack up to the previous 'try'
3056 // from the temporary snapshot stored in lastTempStack.
3057 int restackSize = lastTempStack->size() - indexOfTry - 1;
3058 for (int r = 0; r < restackSize; r++)
3060 headerStack->emplace_back(lastTempStack->back());
3061 lastTempStack->pop_back();
3064 if (!closingBraceReached)
3065 indentCount += restackSize;
3069 else if (newHeader == &AS_CASE)
3072 if (!haveCaseIndent)
3074 haveCaseIndent = true;
3075 if (!lineBeginsWithOpenBrace)
3079 else if (newHeader == &AS_DEFAULT)
3084 else if (newHeader == &AS_STATIC
3085 || newHeader == &AS_SYNCHRONIZED)
3087 if (!headerStack->empty()
3088 && (headerStack->back() == &AS_STATIC
3089 || headerStack->back() == &AS_SYNCHRONIZED))
3091 isIndentableHeader = false;
3095 isIndentableHeader = false;
3096 probationHeader = newHeader;
3099 else if (newHeader == &AS_TEMPLATE)
3101 isInTemplate = true;
3102 isIndentableHeader = false;
3105 if (isIndentableHeader)
3107 headerStack->emplace_back(newHeader);
3108 isContinuation = false;
3109 if (indexOf(*nonParenHeaders, newHeader) == -1)
3111 isInConditional = true;
3113 lastLineHeader = newHeader;
3118 i += newHeader->length() - 1;
3121 } // newHeader != nullptr
3123 if (findHeader(line, i, preCommandHeaders) != nullptr)
3124 foundPreCommandHeader = true;
3126 // Objective-C NSException macros are preCommandHeaders
3127 if (isCStyle() && findKeyword(line, i, AS_NS_DURING))
3128 foundPreCommandMacro = true;
3129 if (isCStyle() && findKeyword(line, i, AS_NS_HANDLER))
3130 foundPreCommandMacro = true;
3132 if (parenDepth == 0 && findKeyword(line, i, AS_ENUM))
3135 if (isSharpStyle() && findKeyword(line, i, AS_LET))
3138 } // isPotentialHeader
3141 isInQuestion = true;
3143 // special handling of colons
3146 if (line.length() > i + 1 && line[i + 1] == ':') // look for ::
3151 else if (isInQuestion)
3153 // do nothing special
3155 else if (parenDepth > 0)
3157 // found a 'for' loop or an objective-C statement
3158 // so do nothing special
3162 // found an enum with a base-type
3163 isInEnumTypeID = true;
3165 indentCount += classInitializerIndents;
3169 && (prevNonSpaceCh == ')' || foundPreCommandHeader))
3171 // found a 'class' c'tor initializer
3172 isInClassInitializer = true;
3173 registerContinuationIndentColon(line, i, tabIncrementIn);
3175 indentCount += classInitializerIndents;
3177 else if (isInClassHeader || isInObjCInterface)
3179 // is in a 'class A : public B' definition
3180 isInClassHeaderTab = true;
3181 registerContinuationIndentColon(line, i, tabIncrementIn);
3183 else if (isInAsm || isInAsmOneLine || isInAsmBlock)
3185 // do nothing special
3187 else if (isDigit(peekNextChar(line, i)))
3189 // found a bit field - do nothing special
3191 else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
3193 // found a 'private:' or 'public:' inside a class definition
3196 spaceIndentCount += (indentLength / 2);
3198 else if (isCStyle() && !isInClass
3199 && headerStack->size() >= 2
3200 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
3201 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE)
3203 // found a 'private:' or 'public:' inside a class definition
3204 // and on the same line as the class opening brace
3207 else if (isJavaStyle() && lastLineHeader == &AS_FOR)
3209 // found a java for-each statement
3210 // so do nothing special
3214 currentNonSpaceCh = ';'; // so that braces after the ':' will appear as block-openers
3215 char peekedChar = peekNextChar(line, i);
3219 ch = ';'; // from here on, treat char as ';'
3221 else if (isCStyle() || (isSharpStyle() && peekedChar == ';'))
3223 // is in a label (e.g. 'label1:')
3225 --indentCount; // unindent label by one indent
3226 else if (!lineBeginsWithOpenBrace)
3227 indentCount = 0; // completely flush indent to left
3232 if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !continuationIndentStackSizeStack->empty())
3233 while ((int) continuationIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
3234 < (int) continuationIndentStack->size())
3235 continuationIndentStack->pop_back();
3237 else if (ch == ',' && isInEnum && isNonInStatementArray && !continuationIndentStack->empty())
3238 continuationIndentStack->pop_back();
3241 // previous "isInStatement" will be from an assignment operator or class initializer
3242 if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray)
3244 // is comma at end of line
3245 size_t nextChar = line.find_first_not_of(" \t", i + 1);
3246 if (nextChar != string::npos)
3248 if (line.compare(nextChar, 2, "//") == 0
3249 || line.compare(nextChar, 2, "/*") == 0)
3250 nextChar = string::npos;
3253 if (nextChar == string::npos)
3255 // register indent at previous word
3256 if (isJavaStyle() && isInClassHeader)
3258 // do nothing for now
3260 // register indent at second word on the line
3261 else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer)
3263 int prevWord = getContinuationIndentComma(line, i);
3264 int continuationIndentCount = prevWord + spaceIndentCount + tabIncrementIn;
3265 continuationIndentStack->emplace_back(continuationIndentCount);
3266 isContinuation = true;
3270 // handle comma first initializers
3271 if (ch == ',' && parenDepth == 0 && lineBeginsWithComma
3272 && (isInClassInitializer || isInClassHeaderTab))
3273 spaceIndentCount = 0;
3275 // handle ends of statements
3276 if ((ch == ';' && parenDepth == 0) || ch == '}')
3280 // first check if this '}' closes a previous block, or a static array...
3281 if (braceBlockStateStack->size() > 1)
3283 bool braceBlockState = braceBlockStateStack->back();
3284 braceBlockStateStack->pop_back();
3285 if (!braceBlockState)
3287 if (!continuationIndentStackSizeStack->empty())
3289 // this brace is a static array
3290 popLastContinuationIndent();
3293 shouldIndentBracedLine = false;
3295 if (!parenIndentStack->empty())
3297 int poppedIndent = parenIndentStack->back();
3298 parenIndentStack->pop_back();
3300 spaceIndentCount = poppedIndent;
3307 // this brace is block closer...
3309 ++lineClosingBlocksNum;
3311 if (!continuationIndentStackSizeStack->empty())
3312 popLastContinuationIndent();
3314 if (!squareBracketDepthStack->empty())
3316 parenDepth = squareBracketDepthStack->back();
3317 squareBracketDepthStack->pop_back();
3318 isContinuation = blockStatementStack->back();
3319 blockStatementStack->pop_back();
3325 closingBraceReached = true;
3327 spaceIndentCount = 0;
3328 isInAsmBlock = false;
3329 isInAsm = isInAsmOneLine = isInQuote = false; // close these just in case
3331 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACE);
3332 if (headerPlace != -1)
3334 const string* popped = headerStack->back();
3335 while (popped != &AS_OPEN_BRACE)
3337 headerStack->pop_back();
3338 popped = headerStack->back();
3340 headerStack->pop_back();
3342 if (headerStack->empty())
3343 g_preprocessorCppExternCBrace = 0;
3345 // do not indent namespace brace unless namespaces are indented
3346 if (!namespaceIndent && !headerStack->empty()
3347 && ((*headerStack).back() == &AS_NAMESPACE
3348 || (*headerStack).back() == &AS_MODULE)
3349 && i == 0) // must be the first brace on the line
3350 shouldIndentBracedLine = false;
3352 if (!tempStacks->empty())
3354 vector<const string*>* temp = tempStacks->back();
3355 tempStacks->pop_back();
3360 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' in this case) will be identified...
3364 * Create a temporary snapshot of the current block's header-list in the
3365 * uppermost inner stack in tempStacks, and clear the headerStack up to
3366 * the beginning of the block.
3367 * Thus, the next future statement will think it comes one indent past
3368 * the block's '{' unless it specifically checks for a companion-header
3369 * (such as a previous 'if' for an 'else' header) within the tempStacks,
3370 * and recreates the temporary snapshot by manipulating the tempStacks.
3372 if (!tempStacks->back()->empty())
3373 while (!tempStacks->back()->empty())
3374 tempStacks->back()->pop_back();
3375 while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACE)
3377 tempStacks->back()->emplace_back(headerStack->back());
3378 headerStack->pop_back();
3381 if (parenDepth == 0 && ch == ';')
3382 isContinuation = false;
3384 if (isInObjCMethodDefinition)
3386 objCColonAlignSubsequent = 0;
3387 isImmediatelyPostObjCMethodDefinition = true;
3390 previousLastLineHeader = nullptr;
3391 isInClassHeader = false; // for 'friend' class
3393 isInEnumTypeID = false;
3394 isInQuestion = false;
3395 isInTemplate = false;
3396 isInObjCInterface = false;
3397 foundPreCommandHeader = false;
3398 foundPreCommandMacro = false;
3399 squareBracketCount = 0;
3404 if (isPotentialHeader)
3406 // check for preBlockStatements in C/C++ ONLY if not within parentheses
3407 // (otherwise 'struct XXX' statements would be wrongly interpreted...)
3408 if (!isInTemplate && !(isCStyle() && parenDepth > 0))
3410 const string* newHeader = findHeader(line, i, preBlockStatements);
3411 // handle CORBA IDL module
3412 if (newHeader == &AS_MODULE)
3414 char nextChar = peekNextChar(line, i + newHeader->length() - 1);
3415 if (prevNonSpaceCh == ')' || !isalpha(nextChar))
3416 newHeader = nullptr;
3418 if (newHeader != nullptr
3419 && !(isCStyle() && newHeader == &AS_CLASS && isInEnum)) // is not 'enum class'
3421 if (!isSharpStyle())
3422 headerStack->emplace_back(newHeader);
3423 // do not need 'where' in the headerStack
3424 // do not need second 'class' statement in a row
3425 else if (!(newHeader == &AS_WHERE
3426 || ((newHeader == &AS_CLASS || newHeader == &AS_STRUCT)
3427 && !headerStack->empty()
3428 && (headerStack->back() == &AS_CLASS
3429 || headerStack->back() == &AS_STRUCT))))
3430 headerStack->emplace_back(newHeader);
3432 if (!headerStack->empty())
3434 if ((*headerStack).back() == &AS_CLASS
3435 || (*headerStack).back() == &AS_STRUCT
3436 || (*headerStack).back() == &AS_INTERFACE)
3438 isInClassHeader = true;
3440 else if ((*headerStack).back() == &AS_NAMESPACE
3441 || (*headerStack).back() == &AS_MODULE)
3443 // remove continuationIndent from namespace
3444 if (!continuationIndentStack->empty())
3445 continuationIndentStack->pop_back();
3446 isContinuation = false;
3450 i += newHeader->length() - 1;
3454 const string* foundIndentableHeader = findHeader(line, i, indentableHeaders);
3456 if (foundIndentableHeader != nullptr)
3458 // must bypass the header before registering the in statement
3459 i += foundIndentableHeader->length() - 1;
3460 if (!isInOperator && !isInTemplate && !isNonInStatementArray)
3462 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
3463 isContinuation = true;
3468 if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
3469 isInOperator = true;
3471 if (g_preprocessorCppExternCBrace == 1 && findKeyword(line, i, AS_EXTERN))
3472 ++g_preprocessorCppExternCBrace;
3474 if (g_preprocessorCppExternCBrace == 3) // extern "C" is not followed by a '{'
3475 g_preprocessorCppExternCBrace = 0;
3477 // "new" operator is a pointer, not a calculation
3478 if (findKeyword(line, i, AS_NEW))
3480 if (isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=')
3481 continuationIndentStack->back() = 0;
3486 if (findKeyword(line, i, AS_ASM)
3487 || findKeyword(line, i, AS__ASM__))
3491 else if (findKeyword(line, i, AS_MS_ASM) // microsoft specific
3492 || findKeyword(line, i, AS_MS__ASM))
3495 if (peekNextChar(line, i) == '_') // check for __asm
3498 char peekedChar = peekNextChar(line, i + index);
3499 if (peekedChar == '{' || peekedChar == ' ')
3500 isInAsmBlock = true;
3502 isInAsmOneLine = true;
3506 // bypass the entire name for all others
3507 string name = getCurrentWord(line, i);
3508 i += name.length() - 1;
3512 // Handle Objective-C statements
3514 if (ch == '@' && !isWhiteSpace(line[i + 1])
3515 && isCharPotentialHeader(line, i + 1))
3517 string curWord = getCurrentWord(line, i + 1);
3518 if (curWord == AS_INTERFACE && headerStack->empty())
3520 isInObjCInterface = true;
3521 string name = '@' + curWord;
3522 i += name.length() - 1;
3525 else if (isInObjCInterface)
3528 isInObjCInterface = false;
3531 if (curWord == AS_PUBLIC
3532 || curWord == AS_PRIVATE
3533 || curWord == AS_PROTECTED)
3537 spaceIndentCount += (indentLength / 2);
3538 string name = '@' + curWord;
3539 i += name.length() - 1;
3542 else if (curWord == AS_END)
3544 popLastContinuationIndent();
3545 spaceIndentCount = 0;
3546 isInObjCMethodDefinition = false;
3547 string name = '@' + curWord;
3548 i += name.length() - 1;
3552 else if ((ch == '-' || ch == '+')
3553 && peekNextChar(line, i) == '('
3554 && headerStack->empty()
3555 && line.find_first_not_of(" \t") == i)
3557 if (isInObjCInterface)
3559 isInObjCInterface = false;
3560 isInObjCMethodDefinition = true;
3566 bool isPotentialOperator = isCharPotentialOperator(ch);
3568 if (isPotentialOperator)
3570 // Check if an operator has been reached.
3571 const string* foundAssignmentOp = findOperator(line, i, assignmentOperators);
3572 const string* foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);
3574 if (foundNonAssignmentOp != nullptr)
3576 if (foundNonAssignmentOp == &AS_LAMBDA)
3577 foundPreCommandHeader = true;
3578 if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR)
3579 foundNonAssignmentOp = nullptr;
3582 // Since findHeader's boundary checking was not used above, it is possible
3583 // that both an assignment op and a non-assignment op where found,
3584 // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
3586 if (foundAssignmentOp != nullptr && foundNonAssignmentOp != nullptr)
3588 if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
3589 foundAssignmentOp = nullptr;
3591 foundNonAssignmentOp = nullptr;
3594 if (foundNonAssignmentOp != nullptr)
3596 if (foundNonAssignmentOp->length() > 1)
3597 i += foundNonAssignmentOp->length() - 1;
3599 // For C++ input/output, operator<< and >> should be
3600 // aligned, if we are not in a statement already and
3601 // also not in the "operator<<(...)" header line
3603 && continuationIndentStack->empty()
3605 && (foundNonAssignmentOp == &AS_GR_GR
3606 || foundNonAssignmentOp == &AS_LS_LS))
3608 // this will be true if the line begins with the operator
3609 if (i < 2 && spaceIndentCount == 0)
3610 spaceIndentCount += 2 * indentLength;
3611 // align to the beginning column of the operator
3612 registerContinuationIndent(line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false);
3616 else if (foundAssignmentOp != nullptr)
3618 foundPreCommandHeader = false; // clears this for array assignments
3619 foundPreCommandMacro = false;
3621 if (foundAssignmentOp->length() > 1)
3622 i += foundAssignmentOp->length() - 1;
3624 if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum))
3626 // if multiple assignments, align on the previous word
3627 if (foundAssignmentOp == &AS_ASSIGN
3628 && prevNonSpaceCh != ']' // an array
3629 && statementEndsWithComma(line, i))
3631 if (!haveAssignmentThisLine) // only one assignment indent per line
3633 // register indent at previous word
3634 haveAssignmentThisLine = true;
3635 int prevWordIndex = getContinuationIndentAssign(line, i);
3636 int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn;
3637 continuationIndentStack->emplace_back(continuationIndentCount);
3638 isContinuation = true;
3641 // don't indent an assignment if 'let'
3646 else if (!lineBeginsWithComma)
3648 if (i == 0 && spaceIndentCount == 0)
3649 spaceIndentCount += indentLength;
3650 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
3651 isContinuation = true;
3656 } // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
3659 } // end namespace astyle