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 //-----------------------------------------------------------------------------
15 //-----------------------------------------------------------------------------
17 //-----------------------------------------------------------------------------
21 //-----------------------------------------------------------------------------
23 //-----------------------------------------------------------------------------
26 * Constructor of ASFormatter
28 ASFormatter::ASFormatter()
30 sourceIterator = nullptr;
31 enhancer = new ASEnhancer;
32 preBraceHeaderStack = nullptr;
33 braceTypeStack = nullptr;
35 structStack = nullptr;
36 questionMarkStack = nullptr;
37 lineCommentNoIndent = false;
38 formattingStyle = STYLE_NONE;
39 braceFormatMode = NONE_MODE;
40 pointerAlignment = PTR_ALIGN_NONE;
41 referenceAlignment = REF_SAME_AS_PTR;
42 objCColonPadMode = COLON_PAD_NO_CHANGE;
43 lineEnd = LINEEND_DEFAULT;
44 maxCodeLength = string::npos;
45 shouldPadCommas = false;
46 shouldPadOperators = false;
47 shouldPadParensOutside = false;
48 shouldPadFirstParen = false;
49 shouldPadParensInside = false;
50 shouldPadHeader = false;
51 shouldStripCommentPrefix = false;
52 shouldUnPadParens = false;
53 attachClosingBraceMode = false;
54 shouldBreakOneLineBlocks = true;
55 shouldBreakOneLineHeaders = false;
56 shouldBreakOneLineStatements = true;
57 shouldConvertTabs = false;
58 shouldIndentCol1Comments = false;
59 shouldIndentPreprocBlock = false;
60 shouldCloseTemplates = false;
61 shouldAttachExternC = false;
62 shouldAttachNamespace = false;
63 shouldAttachClass = false;
64 shouldAttachClosingWhile = false;
65 shouldAttachInline = false;
66 shouldBreakBlocks = false;
67 shouldBreakClosingHeaderBlocks = false;
68 shouldBreakClosingHeaderBraces = false;
69 shouldDeleteEmptyLines = false;
70 shouldBreakElseIfs = false;
71 shouldBreakLineAfterLogical = false;
72 shouldAddBraces = false;
73 shouldAddOneLineBraces = false;
74 shouldRemoveBraces = false;
75 shouldPadMethodColon = false;
76 shouldPadMethodPrefix = false;
77 shouldUnPadMethodPrefix = false;
78 shouldPadReturnType = false;
79 shouldUnPadReturnType = false;
80 shouldPadParamType = false;
81 shouldUnPadParamType = false;
83 // initialize ASFormatter member vectors
84 formatterFileType = 9; // reset to an invalid type
85 headers = new vector<const string*>;
86 nonParenHeaders = new vector<const string*>;
87 preDefinitionHeaders = new vector<const string*>;
88 preCommandHeaders = new vector<const string*>;
89 operators = new vector<const string*>;
90 assignmentOperators = new vector<const string*>;
91 castOperators = new vector<const string*>;
93 // initialize ASEnhancer member vectors
94 indentableMacros = new vector<const pair<const string, const string>* >;
98 * Destructor of ASFormatter
100 ASFormatter::~ASFormatter()
102 // delete ASFormatter stack vectors
103 deleteContainer(preBraceHeaderStack);
104 deleteContainer(braceTypeStack);
105 deleteContainer(parenStack);
106 deleteContainer(structStack);
107 deleteContainer(questionMarkStack);
109 // delete ASFormatter member vectors
110 formatterFileType = 9; // reset to an invalid type
112 delete nonParenHeaders;
113 delete preDefinitionHeaders;
114 delete preCommandHeaders;
116 delete assignmentOperators;
117 delete castOperators;
119 // delete ASEnhancer member vectors
120 delete indentableMacros;
122 // must be done when the ASFormatter object is deleted (not ASBeautifier)
123 // delete ASBeautifier member vectors
124 ASBeautifier::deleteBeautifierVectors();
130 * initialize the ASFormatter.
132 * init() should be called every time a ASFormatter object is to start
133 * formatting a NEW source file.
134 * init() receives a pointer to a ASSourceIterator object that will be
135 * used to iterate through the source code.
137 * @param si a pointer to the ASSourceIterator or ASStreamIterator object.
139 void ASFormatter::init(ASSourceIterator* si)
141 buildLanguageVectors();
142 fixOptionVariableConflicts();
143 ASBeautifier::init(si);
146 enhancer->init(getFileType(),
149 getIndentString() == "\t",
150 getForceTabIndentation(),
151 getNamespaceIndent(),
153 shouldIndentPreprocBlock,
154 getPreprocDefineIndent(),
158 initContainer(preBraceHeaderStack, new vector<const string*>);
159 initContainer(parenStack, new vector<int>);
160 initContainer(structStack, new vector<bool>);
161 initContainer(questionMarkStack, new vector<bool>);
162 parenStack->emplace_back(0); // parenStack must contain this default entry
163 initContainer(braceTypeStack, new vector<BraceType>);
164 braceTypeStack->emplace_back(NULL_TYPE); // braceTypeStack must contain this default entry
165 clearFormattedLineSplitPoints();
167 currentHeader = nullptr;
169 readyFormattedLine = "";
171 verbatimDelimiter = "";
174 previousCommandChar = ' ';
175 previousNonWSChar = ' ';
181 currentLineFirstBraceNum = string::npos;
182 formattedLineCommentNum = 0;
184 previousReadyFormattedLineLength = string::npos;
185 preprocBraceTypeStackSize = 0;
187 nextLineSpacePadNum = 0;
190 squareBracketCount = 0;
191 runInIndentChars = 0;
193 previousBraceType = NULL_TYPE;
196 isInVirginLine = true;
197 isInLineComment = false;
199 isInCommentStartLine = false;
200 noTrimCommentContinuation = false;
201 isInPreprocessor = false;
202 isInPreprocessorBeautify = false;
203 doesLineStartComment = false;
204 lineEndsInCommentOnly = false;
205 lineIsCommentOnly = false;
206 lineIsLineCommentOnly = false;
208 isImmediatelyPostCommentOnly = false;
209 isImmediatelyPostEmptyLine = false;
210 isInClassInitializer = false;
212 isInVerbatimQuote = false;
213 haveLineContinuationChar = false;
214 isInQuoteContinuation = false;
215 isHeaderInMultiStatementLine = false;
216 isSpecialChar = false;
217 isNonParenHeader = false;
218 foundNamespaceHeader = false;
219 foundClassHeader = false;
220 foundStructHeader = false;
221 foundInterfaceHeader = false;
222 foundPreDefinitionHeader = false;
223 foundPreCommandHeader = false;
224 foundPreCommandMacro = false;
225 foundTrailingReturnType = false;
226 foundCastOperator = false;
227 foundQuestionMark = false;
228 isInLineBreak = false;
229 endOfAsmReached = false;
230 endOfCodeReached = false;
231 isFormattingModeOff = false;
235 isInAsmOneLine = false;
236 isInAsmBlock = false;
238 elseHeaderFollowsComments = false;
239 caseHeaderFollowsComments = false;
240 isPreviousBraceBlockRelated = false;
241 isInPotentialCalculation = false;
242 needHeaderOpeningBrace = false;
243 shouldBreakLineAtNextChar = false;
244 shouldKeepLineUnbroken = false;
245 shouldReparseCurrentChar = false;
246 passedSemicolon = false;
248 isImmediatelyPostNonInStmt = false;
249 isCharImmediatelyPostNonInStmt = false;
250 isInTemplate = false;
251 isImmediatelyPostComment = false;
252 isImmediatelyPostLineComment = false;
253 isImmediatelyPostEmptyBlock = false;
254 isImmediatelyPostObjCMethodPrefix = false;
255 isImmediatelyPostPreprocessor = false;
256 isImmediatelyPostReturn = false;
257 isImmediatelyPostThrow = false;
258 isImmediatelyPostNewDelete = false;
259 isImmediatelyPostOperator = false;
260 isImmediatelyPostTemplate = false;
261 isImmediatelyPostPointerOrReference = false;
262 isCharImmediatelyPostReturn = false;
263 isCharImmediatelyPostThrow = false;
264 isCharImmediatelyPostNewDelete = false;
265 isCharImmediatelyPostOperator = false;
266 isCharImmediatelyPostComment = false;
267 isPreviousCharPostComment = false;
268 isCharImmediatelyPostLineComment = false;
269 isCharImmediatelyPostOpenBlock = false;
270 isCharImmediatelyPostCloseBlock = false;
271 isCharImmediatelyPostTemplate = false;
272 isCharImmediatelyPostPointerOrReference = false;
273 isInObjCInterface = false;
274 isInObjCMethodDefinition = false;
275 isInObjCReturnType = false;
276 isInObjCSelector = false;
277 breakCurrentOneLineBlock = false;
278 shouldRemoveNextClosingBrace = false;
279 isInBraceRunIn = false;
280 currentLineBeginsWithBrace = false;
281 isPrependPostBlockEmptyLineRequested = false;
282 isAppendPostBlockEmptyLineRequested = false;
283 isIndentableProprocessor = false;
284 isIndentableProprocessorBlock = false;
285 prependEmptyLine = false;
286 appendOpeningBrace = false;
287 foundClosingHeader = false;
288 isImmediatelyPostHeader = false;
291 isFirstPreprocConditional = false;
292 processedFirstConditional = false;
293 isJavaStaticConstructor = false;
297 * build vectors for each programing language
298 * depending on the file extension.
300 void ASFormatter::buildLanguageVectors()
302 if (getFileType() == formatterFileType) // don't build unless necessary
305 formatterFileType = getFileType();
308 nonParenHeaders->clear();
309 preDefinitionHeaders->clear();
310 preCommandHeaders->clear();
312 assignmentOperators->clear();
313 castOperators->clear();
314 indentableMacros->clear(); // ASEnhancer
316 ASResource::buildHeaders(headers, getFileType());
317 ASResource::buildNonParenHeaders(nonParenHeaders, getFileType());
318 ASResource::buildPreDefinitionHeaders(preDefinitionHeaders, getFileType());
319 ASResource::buildPreCommandHeaders(preCommandHeaders, getFileType());
320 ASResource::buildOperators(operators, getFileType());
321 ASResource::buildAssignmentOperators(assignmentOperators);
322 ASResource::buildCastOperators(castOperators);
323 ASResource::buildIndentableMacros(indentableMacros); //ASEnhancer
327 * set the variables for each predefined style.
328 * this will override any previous settings.
330 void ASFormatter::fixOptionVariableConflicts()
332 if (formattingStyle == STYLE_ALLMAN)
334 setBraceFormatMode(BREAK_MODE);
336 else if (formattingStyle == STYLE_JAVA)
338 setBraceFormatMode(ATTACH_MODE);
340 else if (formattingStyle == STYLE_KR)
342 setBraceFormatMode(LINUX_MODE);
344 else if (formattingStyle == STYLE_STROUSTRUP)
346 setBraceFormatMode(LINUX_MODE);
347 setBreakClosingHeaderBracesMode(true);
349 else if (formattingStyle == STYLE_WHITESMITH)
351 setBraceFormatMode(BREAK_MODE);
352 setBraceIndent(true);
353 setClassIndent(true); // avoid hanging indent with access modifiers
354 setSwitchIndent(true); // avoid hanging indent with case statements
356 else if (formattingStyle == STYLE_VTK)
358 // the unindented class brace does NOT cause a hanging indent like Whitesmith
359 setBraceFormatMode(BREAK_MODE);
360 setBraceIndentVtk(true); // sets both braceIndent and braceIndentVtk
361 setSwitchIndent(true); // avoid hanging indent with case statements
363 else if (formattingStyle == STYLE_BANNER)
365 // attached braces can have hanging indents with the closing brace
366 setBraceFormatMode(ATTACH_MODE);
367 setBraceIndent(true);
368 setClassIndent(true); // avoid hanging indent with access modifiers
369 setSwitchIndent(true); // avoid hanging indent with case statements
371 else if (formattingStyle == STYLE_GNU)
373 setBraceFormatMode(BREAK_MODE);
374 setBlockIndent(true);
376 else if (formattingStyle == STYLE_LINUX)
378 setBraceFormatMode(LINUX_MODE);
379 // always for Linux style
380 setMinConditionalIndentOption(MINCOND_ONEHALF);
382 else if (formattingStyle == STYLE_HORSTMANN)
384 setBraceFormatMode(RUN_IN_MODE);
385 setSwitchIndent(true);
387 else if (formattingStyle == STYLE_1TBS)
389 setBraceFormatMode(LINUX_MODE);
390 setAddBracesMode(true);
391 setRemoveBracesMode(false);
393 else if (formattingStyle == STYLE_GOOGLE)
395 setBraceFormatMode(ATTACH_MODE);
396 setModifierIndent(true);
397 setClassIndent(false);
399 else if (formattingStyle == STYLE_MOZILLA)
401 setBraceFormatMode(LINUX_MODE);
403 else if (formattingStyle == STYLE_PICO)
405 setBraceFormatMode(RUN_IN_MODE);
406 setAttachClosingBraceMode(true);
407 setSwitchIndent(true);
408 setBreakOneLineBlocksMode(false);
409 setBreakOneLineStatementsMode(false);
410 // add-braces won't work for pico, but it could be fixed if necessary
411 // both options should be set to true
413 shouldAddOneLineBraces = true;
415 else if (formattingStyle == STYLE_LISP)
417 setBraceFormatMode(ATTACH_MODE);
418 setAttachClosingBraceMode(true);
419 setBreakOneLineStatementsMode(false);
420 // add-one-line-braces won't work for lisp
421 // only shouldAddBraces should be set to true
422 if (shouldAddOneLineBraces)
424 shouldAddBraces = true;
425 shouldAddOneLineBraces = false;
428 setMinConditionalIndentLength();
429 // if not set by indent=force-tab-x set equal to indentLength
430 if (getTabLength() == 0)
431 setDefaultTabLength();
432 // add-one-line-braces implies keep-one-line-blocks
433 if (shouldAddOneLineBraces)
434 setBreakOneLineBlocksMode(false);
435 // don't allow add-braces and remove-braces
436 if (shouldAddBraces || shouldAddOneLineBraces)
437 setRemoveBracesMode(false);
438 // don't allow indent-classes and indent-modifiers
439 if (getClassIndent())
440 setModifierIndent(false);
444 * get the next formatted line.
446 * @return formatted line.
448 string ASFormatter::nextLine()
450 const string* newHeader = nullptr;
451 isInVirginLine = isVirgin;
452 isCharImmediatelyPostComment = false;
453 isPreviousCharPostComment = false;
454 isCharImmediatelyPostLineComment = false;
455 isCharImmediatelyPostOpenBlock = false;
456 isCharImmediatelyPostCloseBlock = false;
457 isCharImmediatelyPostTemplate = false;
461 if (shouldReparseCurrentChar)
462 shouldReparseCurrentChar = false;
463 else if (!getNextChar())
468 else // stuff to do when reading a new character...
470 // make sure that a virgin '{' at the beginning of the file will be treated as a block...
471 if (isInVirginLine && currentChar == '{'
472 && currentLineBeginsWithBrace
473 && previousCommandChar == ' ')
474 previousCommandChar = '{';
475 if (isInClassInitializer
476 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
477 isInClassInitializer = false;
479 isInLineBreak = false;
480 if (!isWhiteSpace(currentChar))
481 isInBraceRunIn = false;
482 isPreviousCharPostComment = isCharImmediatelyPostComment;
483 isCharImmediatelyPostComment = false;
484 isCharImmediatelyPostTemplate = false;
485 isCharImmediatelyPostReturn = false;
486 isCharImmediatelyPostThrow = false;
487 isCharImmediatelyPostNewDelete = false;
488 isCharImmediatelyPostOperator = false;
489 isCharImmediatelyPostPointerOrReference = false;
490 isCharImmediatelyPostOpenBlock = false;
491 isCharImmediatelyPostCloseBlock = false;
494 if ((lineIsLineCommentOnly || lineIsCommentOnly)
495 && currentLine.find("*INDENT-ON*", charNum) != string::npos
496 && isFormattingModeOff)
498 isFormattingModeOff = false;
500 formattedLine = currentLine;
501 charNum = (int) currentLine.length() - 1;
504 if (isFormattingModeOff)
507 formattedLine = currentLine;
508 charNum = (int) currentLine.length() - 1;
511 if ((lineIsLineCommentOnly || lineIsCommentOnly)
512 && currentLine.find("*INDENT-OFF*", charNum) != string::npos)
514 isFormattingModeOff = true;
515 if (isInLineBreak) // is true if not the first line
517 formattedLine = currentLine;
518 charNum = (int)currentLine.length() - 1;
522 if (shouldBreakLineAtNextChar)
524 if (isWhiteSpace(currentChar) && !lineIsEmpty)
526 isInLineBreak = true;
527 shouldBreakLineAtNextChar = false;
530 if (isInExecSQL && !passedSemicolon)
532 if (currentChar == ';')
533 passedSemicolon = true;
540 formatLineCommentBody();
543 else if (isInComment)
555 // not in quote or comment or line comment
557 if (isSequenceReached("//"))
559 formatLineCommentOpener();
560 testForTimeToSplitFormattedLine();
563 else if (isSequenceReached("/*"))
565 formatCommentOpener();
566 testForTimeToSplitFormattedLine();
569 else if (currentChar == '"'
570 || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)))
573 testForTimeToSplitFormattedLine();
576 // treat these preprocessor statements as a line comment
577 else if (currentChar == '#'
578 && currentLine.find_first_not_of(" \t") == (size_t) charNum)
580 string preproc = trim(currentLine.c_str() + charNum + 1);
581 if (preproc.length() > 0
582 && isCharPotentialHeader(preproc, 0)
583 && (findKeyword(preproc, 0, "region")
584 || findKeyword(preproc, 0, "endregion")
585 || findKeyword(preproc, 0, "error")
586 || findKeyword(preproc, 0, "warning")
587 || findKeyword(preproc, 0, "line")))
589 currentLine = rtrim(currentLine); // trim the end only
591 if (formattedLine.length() > 0 && formattedLine[0] == '{')
593 isInLineBreak = true;
594 isInBraceRunIn = false;
596 if (previousCommandChar == '}')
597 currentHeader = nullptr;
598 isInLineComment = true;
604 if (isInPreprocessor)
610 if (isInTemplate && shouldCloseTemplates)
612 if (previousNonWSChar == '>' && isWhiteSpace(currentChar) && peekNextChar() == '>')
616 if (shouldRemoveNextClosingBrace && currentChar == '}')
618 currentLine[charNum] = currentChar = ' ';
619 shouldRemoveNextClosingBrace = false;
620 assert(adjustChecksumIn(-'}'));
621 if (isEmptyLine(currentLine))
625 // handle white space - needed to simplify the rest.
626 if (isWhiteSpace(currentChar))
632 /* not in MIDDLE of quote or comment or SQL or white-space of any type ... */
634 // check if in preprocessor
635 // ** isInPreprocessor will be automatically reset at the beginning
636 // of a new line in getnextChar()
637 if (currentChar == '#')
639 isInPreprocessor = true;
641 if (formattedLine.length() > 0 && formattedLine[0] == '{')
643 isInLineBreak = true;
644 isInBraceRunIn = false;
646 processPreprocessor();
647 // if top level it is potentially indentable
648 if (shouldIndentPreprocBlock
649 && (isBraceType(braceTypeStack->back(), NULL_TYPE)
650 || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
652 && !isInClassInitializer
653 && sourceIterator->tellg() > preprocBlockEnd)
655 // indent the #if preprocessor blocks
656 string preproc = ASBeautifier::extractPreprocessorStatement(currentLine);
657 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
659 if (isImmediatelyPostPreprocessor)
661 isIndentableProprocessorBlock = isIndentablePreprocessorBlock(currentLine, charNum);
662 isIndentableProprocessor = isIndentableProprocessorBlock;
665 if (isIndentableProprocessorBlock
666 && charNum < (int) currentLine.length() - 1
667 && isWhiteSpace(currentLine[charNum + 1]))
669 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
670 if (nextText != string::npos)
671 currentLine.erase(charNum + 1, nextText - charNum - 1);
673 if (isIndentableProprocessorBlock
674 && sourceIterator->tellg() >= preprocBlockEnd)
675 isIndentableProprocessorBlock = false;
676 // need to fall thru here to reset the variables
679 /* not in preprocessor ... */
681 if (isImmediatelyPostComment)
683 caseHeaderFollowsComments = false;
684 isImmediatelyPostComment = false;
685 isCharImmediatelyPostComment = true;
688 if (isImmediatelyPostLineComment)
690 caseHeaderFollowsComments = false;
691 isImmediatelyPostLineComment = false;
692 isCharImmediatelyPostLineComment = true;
695 if (isImmediatelyPostReturn)
697 isImmediatelyPostReturn = false;
698 isCharImmediatelyPostReturn = true;
701 if (isImmediatelyPostThrow)
703 isImmediatelyPostThrow = false;
704 isCharImmediatelyPostThrow = true;
707 if (isImmediatelyPostNewDelete)
709 isImmediatelyPostNewDelete = false;
710 isCharImmediatelyPostNewDelete = true;
713 if (isImmediatelyPostOperator)
715 isImmediatelyPostOperator = false;
716 isCharImmediatelyPostOperator = true;
718 if (isImmediatelyPostTemplate)
720 isImmediatelyPostTemplate = false;
721 isCharImmediatelyPostTemplate = true;
723 if (isImmediatelyPostPointerOrReference)
725 isImmediatelyPostPointerOrReference = false;
726 isCharImmediatelyPostPointerOrReference = true;
729 // reset isImmediatelyPostHeader information
730 if (isImmediatelyPostHeader)
732 // should braces be added
733 if (currentChar != '{'
735 && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine)
736 && isOkToBreakBlock(braceTypeStack->back()))
738 bool bracesAdded = addBracesToStatement();
739 if (bracesAdded && !shouldAddOneLineBraces)
741 size_t firstText = currentLine.find_first_not_of(" \t");
742 assert(firstText != string::npos);
743 if ((int) firstText == charNum || shouldBreakOneLineHeaders)
744 breakCurrentOneLineBlock = true;
747 // should braces be removed
748 else if (currentChar == '{' && shouldRemoveBraces)
750 bool bracesRemoved = removeBracesFromStatement();
753 shouldRemoveNextClosingBrace = true;
754 if (isBeforeAnyLineEndComment(charNum))
756 else if (shouldBreakOneLineBlocks
757 || (currentLineBeginsWithBrace
758 && currentLine.find_first_not_of(" \t") != string::npos))
759 shouldBreakLineAtNextChar = true;
764 // break 'else-if' if shouldBreakElseIfs is requested
765 if (shouldBreakElseIfs
766 && currentHeader == &AS_ELSE
767 && isOkToBreakBlock(braceTypeStack->back())
768 && !isBeforeAnyComment()
769 && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine))
771 string nextText = peekNextText(currentLine.substr(charNum));
772 if (nextText.length() > 0
773 && isCharPotentialHeader(nextText, 0)
774 && ASBase::findHeader(nextText, 0, headers) == &AS_IF)
776 isInLineBreak = true;
780 // break a header (e.g. if, while, else) from the following statement
781 if (shouldBreakOneLineHeaders
782 && peekNextChar() != ' '
783 && (shouldBreakOneLineStatements
784 || (!isHeaderInMultiStatementLine
785 && !isMultiStatementLine()))
786 && isOkToBreakBlock(braceTypeStack->back())
787 && !isBeforeAnyComment())
789 if (currentChar == '{')
791 if (!currentLineBeginsWithBrace)
793 if (isOneLineBlockReached(currentLine, charNum) == 3)
794 isInLineBreak = false;
796 breakCurrentOneLineBlock = true;
799 else if (currentHeader == &AS_ELSE)
801 string nextText = peekNextText(currentLine.substr(charNum), true);
802 if (nextText.length() > 0
803 && ((isCharPotentialHeader(nextText, 0)
804 && ASBase::findHeader(nextText, 0, headers) != &AS_IF)
805 || nextText[0] == '{'))
806 isInLineBreak = true;
810 isInLineBreak = true;
814 isImmediatelyPostHeader = false;
817 if (passedSemicolon) // need to break the formattedLine
819 passedSemicolon = false;
820 if (parenStack->back() == 0 && !isCharImmediatelyPostComment && currentChar != ';') // allow ;;
822 // does a one-line block have ending comments?
823 if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
825 size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACE);
826 assert(blockEnd != string::npos);
827 // move ending comments to this formattedLine
828 if (isBeforeAnyLineEndComment(blockEnd))
830 size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);
831 assert(commentStart != string::npos);
832 assert((currentLine.compare(commentStart, 2, "//") == 0)
833 || (currentLine.compare(commentStart, 2, "/*") == 0));
834 formattedLine.append(getIndentLength() - 1, ' ');
836 int charNumSave = charNum;
837 charNum = commentStart;
838 while (charNum < (int) currentLine.length())
840 currentChar = currentLine[charNum];
841 if (currentChar == '\t' && shouldConvertTabs)
842 convertTabToSpaces();
843 formattedLine.append(1, currentChar);
846 size_t commentLength = currentLine.length() - commentStart;
847 currentLine.erase(commentStart, commentLength);
848 charNum = charNumSave;
849 currentChar = currentLine[charNum];
850 testForTimeToSplitFormattedLine();
854 shouldReparseCurrentChar = true;
855 if (formattedLine.find_first_not_of(" \t") != string::npos)
856 isInLineBreak = true;
857 if (needHeaderOpeningBrace)
859 isCharImmediatelyPostCloseBlock = true;
860 needHeaderOpeningBrace = false;
869 if (parenStack->back() == 0
870 && !isBeforeAnyComment()
871 && (formattedLine.find_first_not_of(" \t") != string::npos))
873 shouldReparseCurrentChar = true;
874 isInLineBreak = true;
879 // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
880 if (!isInTemplate && currentChar == '<')
882 checkIfTemplateOpener();
886 if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
888 questionMarkStack->push_back(foundQuestionMark);
889 foundQuestionMark = false;
890 parenStack->back()++;
891 if (currentChar == '[')
893 ++squareBracketCount;
894 if (getAlignMethodColon() && squareBracketCount == 1 && isCStyle())
895 objCColonAlign = findObjCColonAlignment();
898 else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
900 foundPreCommandHeader = false;
901 parenStack->back()--;
902 // this can happen in preprocessor directives
903 if (parenStack->back() < 0)
904 parenStack->back() = 0;
905 if (!questionMarkStack->empty())
907 foundQuestionMark = questionMarkStack->back();
908 questionMarkStack->pop_back();
910 if (isInTemplate && currentChar == '>')
913 if (templateDepth == 0)
915 isInTemplate = false;
916 isImmediatelyPostTemplate = true;
920 // check if this parenthesis closes a header, e.g. if (...), while (...)
921 if (isInHeader && parenStack->back() == 0)
924 isImmediatelyPostHeader = true;
925 foundQuestionMark = false;
927 if (currentChar == ']')
929 --squareBracketCount;
930 if (squareBracketCount <= 0)
932 squareBracketCount = 0;
936 if (currentChar == ')')
938 foundCastOperator = false;
939 if (parenStack->back() == 0)
940 endOfAsmReached = true;
945 if (currentChar == '{' || currentChar == '}')
947 // if appendOpeningBrace this was already done for the original brace
948 if (currentChar == '{' && !appendOpeningBrace)
950 BraceType newBraceType = getBraceType();
951 breakCurrentOneLineBlock = false;
952 foundNamespaceHeader = false;
953 foundClassHeader = false;
954 foundStructHeader = false;
955 foundInterfaceHeader = false;
956 foundPreDefinitionHeader = false;
957 foundPreCommandHeader = false;
958 foundPreCommandMacro = false;
959 foundTrailingReturnType = false;
960 isInPotentialCalculation = false;
961 isInObjCMethodDefinition = false;
962 isInObjCInterface = false;
964 isJavaStaticConstructor = false;
965 isCharImmediatelyPostNonInStmt = false;
966 needHeaderOpeningBrace = false;
967 shouldKeepLineUnbroken = false;
970 isPreviousBraceBlockRelated = !isBraceType(newBraceType, ARRAY_TYPE);
971 braceTypeStack->emplace_back(newBraceType);
972 preBraceHeaderStack->emplace_back(currentHeader);
973 currentHeader = nullptr;
974 structStack->push_back(isInIndentableStruct);
975 if (isBraceType(newBraceType, STRUCT_TYPE) && isCStyle())
976 isInIndentableStruct = isStructAccessModified(currentLine, charNum);
978 isInIndentableStruct = false;
981 // this must be done before the braceTypeStack is popped
982 BraceType braceType = braceTypeStack->back();
983 bool isOpeningArrayBrace = (isBraceType(braceType, ARRAY_TYPE)
984 && braceTypeStack->size() >= 2
985 && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], ARRAY_TYPE)
988 if (currentChar == '}')
990 // if a request has been made to append a post block empty line,
991 // but the block exists immediately before a closing brace,
992 // then there is no need for the post block empty line.
993 isAppendPostBlockEmptyLineRequested = false;
995 endOfAsmReached = true;
996 isInAsmOneLine = isInQuote = false;
997 shouldKeepLineUnbroken = false;
998 squareBracketCount = 0;
1000 if (braceTypeStack->size() > 1)
1002 previousBraceType = braceTypeStack->back();
1003 braceTypeStack->pop_back();
1004 isPreviousBraceBlockRelated = !isBraceType(braceType, ARRAY_TYPE);
1008 previousBraceType = NULL_TYPE;
1009 isPreviousBraceBlockRelated = false;
1012 if (!preBraceHeaderStack->empty())
1014 currentHeader = preBraceHeaderStack->back();
1015 preBraceHeaderStack->pop_back();
1018 currentHeader = nullptr;
1020 if (!structStack->empty())
1022 isInIndentableStruct = structStack->back();
1023 structStack->pop_back();
1026 isInIndentableStruct = false;
1028 if (isNonInStatementArray
1029 && (!isBraceType(braceTypeStack->back(), ARRAY_TYPE) // check previous brace
1030 || peekNextChar() == ';')) // check for "};" added V2.01
1031 isImmediatelyPostNonInStmt = true;
1033 if (!shouldBreakOneLineStatements
1034 && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE)
1036 // handle special case of "else" at the end of line
1037 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
1038 if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')
1039 shouldBreakLineAtNextChar = true;
1044 appendOpeningBrace = false;
1045 if (isBraceType(braceType, ARRAY_TYPE))
1047 formatArrayBraces(braceType, isOpeningArrayBrace);
1051 if (currentChar == '{')
1052 formatOpeningBrace(braceType);
1054 formatClosingBrace(braceType);
1059 if ((((previousCommandChar == '{' && isPreviousBraceBlockRelated)
1060 || ((previousCommandChar == '}'
1061 && !isImmediatelyPostEmptyBlock
1062 && isPreviousBraceBlockRelated
1063 && !isPreviousCharPostComment // Fixes wrongly appended newlines after '}' immediately after comments
1064 && peekNextChar() != ' '
1065 && !isBraceType(previousBraceType, DEFINITION_TYPE))
1066 && !isBraceType(braceTypeStack->back(), DEFINITION_TYPE)))
1067 && isOkToBreakBlock(braceTypeStack->back()))
1069 || (previousCommandChar == '{' // added 9/30/2010
1070 && isBraceType(braceTypeStack->back(), ARRAY_TYPE)
1071 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1072 && isNonInStatementArray)
1073 // check for pico one line braces
1074 || (formattingStyle == STYLE_PICO
1075 && (previousCommandChar == '{' && isPreviousBraceBlockRelated)
1076 && isBraceType(braceTypeStack->back(), COMMAND_TYPE)
1077 && isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1078 && braceFormatMode == RUN_IN_MODE)
1081 isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
1082 isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
1084 if (isCharImmediatelyPostOpenBlock
1085 && !isCharImmediatelyPostComment
1086 && !isCharImmediatelyPostLineComment)
1088 previousCommandChar = ' ';
1090 if (braceFormatMode == NONE_MODE)
1092 if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1093 && (isBraceType(braceTypeStack->back(), BREAK_BLOCK_TYPE)
1094 || shouldBreakOneLineBlocks))
1095 isInLineBreak = true;
1096 else if (currentLineBeginsWithBrace)
1101 else if (braceFormatMode == RUN_IN_MODE
1102 && currentChar != '#')
1105 isInLineBreak = true;
1107 else if (isCharImmediatelyPostCloseBlock
1108 && shouldBreakOneLineStatements
1109 && !isCharImmediatelyPostComment
1110 && ((isLegalNameChar(currentChar) && currentChar != '.')
1111 || currentChar == '+'
1112 || currentChar == '-'
1113 || currentChar == '*'
1114 || currentChar == '&'
1115 || currentChar == '('))
1117 previousCommandChar = ' ';
1118 isInLineBreak = true;
1122 // reset block handling flags
1123 isImmediatelyPostEmptyBlock = false;
1126 bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum);
1128 if (isPotentialHeader && !isInTemplate && squareBracketCount == 0)
1130 isNonParenHeader = false;
1131 foundClosingHeader = false;
1133 newHeader = findHeader(headers);
1135 // Qt headers may be variables in C++
1137 && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
1139 if (currentLine.find_first_of("=;", charNum) != string::npos)
1140 newHeader = nullptr;
1143 && (newHeader == &AS_SYNCHRONIZED))
1145 // want synchronized statements not synchronized methods
1146 if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE))
1147 newHeader = nullptr;
1149 else if (newHeader == &AS_USING
1150 && ASBeautifier::peekNextChar(
1151 currentLine, charNum + (*newHeader).length() - 1) != '(')
1152 newHeader = nullptr;
1154 if (newHeader != nullptr)
1156 foundClosingHeader = isClosingHeader(newHeader);
1158 if (!foundClosingHeader)
1160 // these are closing headers
1161 if ((newHeader == &AS_WHILE && currentHeader == &AS_DO)
1162 || (newHeader == &_AS_FINALLY && currentHeader == &_AS_TRY)
1163 || (newHeader == &_AS_EXCEPT && currentHeader == &_AS_TRY))
1164 foundClosingHeader = true;
1165 // don't append empty block for these related headers
1166 else if (isSharpStyle()
1167 && previousNonWSChar == '}'
1168 && ((newHeader == &AS_SET && currentHeader == &AS_GET)
1169 || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
1170 && isOkToBreakBlock(braceTypeStack->back()))
1171 isAppendPostBlockEmptyLineRequested = false;
1174 // TODO: this can be removed in a future release
1175 // version 3.0 - break erroneous attached header from previous versions
1177 && ((newHeader == &AS_SET && currentHeader == &AS_GET)
1178 || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
1179 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1180 && currentLine[currentLine.find_first_not_of(" \t")] == '}')
1181 isInLineBreak = true;
1184 const string* previousHeader = currentHeader;
1185 currentHeader = newHeader;
1186 needHeaderOpeningBrace = true;
1188 // is the previous statement on the same line?
1189 if ((previousNonWSChar == ';' || previousNonWSChar == ':')
1191 && isOkToBreakBlock(braceTypeStack->back()))
1193 // if breaking lines, break the line at the header
1194 // except for multiple 'case' statements on a line
1195 if (maxCodeLength != string::npos
1196 && previousHeader != &AS_CASE)
1197 isInLineBreak = true;
1199 isHeaderInMultiStatementLine = true;
1202 if (foundClosingHeader && previousNonWSChar == '}')
1204 if (isOkToBreakBlock(braceTypeStack->back()))
1205 isLineBreakBeforeClosingHeader();
1207 // get the adjustment for a comment following the closing header
1209 nextLineSpacePadNum = getNextLineCommentAdjustment();
1211 spacePadNum = getCurrentLineCommentAdjustment();
1214 // check if the found header is non-paren header
1215 isNonParenHeader = findHeader(nonParenHeaders) != nullptr;
1217 if (isNonParenHeader
1218 && (currentHeader == &AS_CATCH
1219 || currentHeader == &AS_CASE))
1221 int startChar = charNum + currentHeader->length() - 1;
1222 if (ASBeautifier::peekNextChar(currentLine, startChar) == '(')
1223 isNonParenHeader = false;
1226 // join 'else if' statements
1227 if (currentHeader == &AS_IF
1228 && previousHeader == &AS_ELSE
1230 && !shouldBreakElseIfs
1231 && !isCharImmediatelyPostLineComment
1232 && !isImmediatelyPostPreprocessor)
1234 // 'else' must be last thing on the line
1235 size_t start = formattedLine.length() >= 6 ? formattedLine.length() - 6 : 0;
1236 if (formattedLine.find(AS_ELSE, start) != string::npos)
1239 isInLineBreak = false;
1243 appendSequence(*currentHeader);
1244 goForward(currentHeader->length() - 1);
1245 // if a paren-header is found add a space after it, if needed
1246 // this checks currentLine, appendSpacePad() checks formattedLine
1247 // in 'case' and C# 'catch' can be either a paren or non-paren header
1249 && !isNonParenHeader
1250 && charNum < (int) currentLine.length() - 1 && !isWhiteSpace(currentLine[charNum + 1]))
1253 // Signal that a header has been reached
1254 // *** But treat a closing while() (as in do...while)
1255 // as if it were NOT a header since a closing while()
1256 // should never have a block after it!
1257 if (currentHeader != &AS_CASE && currentHeader != &AS_DEFAULT
1258 && !(foundClosingHeader && currentHeader == &AS_WHILE))
1262 // in C# 'catch' and 'delegate' can be a paren or non-paren header
1263 if (isNonParenHeader && !isSharpStyleWithParen(currentHeader))
1265 isImmediatelyPostHeader = true;
1270 if (shouldBreakBlocks
1271 && isOkToBreakBlock(braceTypeStack->back())
1272 && !isHeaderInMultiStatementLine)
1274 if (previousHeader == nullptr
1275 && !foundClosingHeader
1276 && !isCharImmediatelyPostOpenBlock
1277 && !isImmediatelyPostCommentOnly)
1279 isPrependPostBlockEmptyLineRequested = true;
1282 if (isClosingHeader(currentHeader)
1283 || foundClosingHeader)
1285 isPrependPostBlockEmptyLineRequested = false;
1288 if (shouldBreakClosingHeaderBlocks
1289 && isCharImmediatelyPostCloseBlock
1290 && !isImmediatelyPostCommentOnly
1291 && !(currentHeader == &AS_WHILE // do-while
1292 && foundClosingHeader))
1294 isPrependPostBlockEmptyLineRequested = true;
1298 if (currentHeader == &AS_CASE
1299 || currentHeader == &AS_DEFAULT)
1304 else if ((newHeader = findHeader(preDefinitionHeaders)) != nullptr
1305 && parenStack->back() == 0
1306 && !isInEnum) // not C++11 enum class
1308 if (newHeader == &AS_NAMESPACE || newHeader == &AS_MODULE)
1309 foundNamespaceHeader = true;
1310 if (newHeader == &AS_CLASS)
1311 foundClassHeader = true;
1312 if (newHeader == &AS_STRUCT)
1313 foundStructHeader = true;
1314 if (newHeader == &AS_INTERFACE)
1315 foundInterfaceHeader = true;
1316 foundPreDefinitionHeader = true;
1317 appendSequence(*newHeader);
1318 goForward(newHeader->length() - 1);
1322 else if ((newHeader = findHeader(preCommandHeaders)) != nullptr)
1324 // a 'const' variable is not a preCommandHeader
1325 if (previousNonWSChar == ')')
1326 foundPreCommandHeader = true;
1328 else if ((newHeader = findHeader(castOperators)) != nullptr)
1330 foundCastOperator = true;
1331 appendSequence(*newHeader);
1332 goForward(newHeader->length() - 1);
1335 } // (isPotentialHeader && !isInTemplate)
1337 if (isInLineBreak) // OK to break line here
1340 if (isInVirginLine) // adjust for the first line
1342 lineCommentNoBeautify = lineCommentNoIndent;
1343 lineCommentNoIndent = false;
1344 if (isImmediatelyPostPreprocessor)
1346 isInIndentablePreproc = isIndentableProprocessor;
1347 isIndentableProprocessor = false;
1352 if (previousNonWSChar == '}' || currentChar == ';')
1354 if (currentChar == ';')
1356 squareBracketCount = 0;
1358 if (((shouldBreakOneLineStatements
1359 || isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
1360 && isOkToBreakBlock(braceTypeStack->back()))
1361 && !(attachClosingBraceMode && peekNextChar() == '}'))
1363 passedSemicolon = true;
1365 else if (!shouldBreakOneLineStatements
1366 && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE)
1368 // handle special case of "else" at the end of line
1369 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
1370 if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')
1371 passedSemicolon = true;
1374 if (shouldBreakBlocks
1375 && currentHeader != nullptr
1376 && currentHeader != &AS_CASE
1377 && currentHeader != &AS_DEFAULT
1378 && !isHeaderInMultiStatementLine
1379 && parenStack->back() == 0)
1381 isAppendPostBlockEmptyLineRequested = true;
1384 if (currentChar != ';'
1385 || (needHeaderOpeningBrace && parenStack->back() == 0))
1386 currentHeader = nullptr;
1387 resetEndOfStatement();
1390 if (currentChar == ':'
1391 && previousChar != ':' // not part of '::'
1392 && peekNextChar() != ':') // not part of '::'
1397 if (shouldBreakOneLineStatements)
1400 else if (isCStyle() // for C/C++ only
1401 && isOkToBreakBlock(braceTypeStack->back())
1402 && shouldBreakOneLineStatements
1403 && !foundQuestionMark // not in a ?: sequence
1404 && !foundPreDefinitionHeader // not in a definition block
1405 && previousCommandChar != ')' // not after closing paren of a method header
1406 && !foundPreCommandHeader // not after a 'noexcept'
1407 && squareBracketCount == 0 // not in objC method call
1408 && !isInObjCMethodDefinition // not objC '-' or '+' method
1409 && !isInObjCInterface // not objC @interface
1410 && !isInObjCSelector // not objC @selector
1411 && !isDigit(peekNextChar()) // not a bit field
1412 && !isInEnum // not an enum with a base type
1413 && !isInAsm // not in extended assembler
1414 && !isInAsmOneLine // not in extended assembler
1415 && !isInAsmBlock) // not in extended assembler
1421 && shouldPadMethodColon
1422 && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector)
1423 && !foundQuestionMark) // not in a ?: sequence
1424 padObjCMethodColon();
1426 if (isInObjCInterface)
1429 if ((int) currentLine.length() > charNum + 1
1430 && !isWhiteSpace(currentLine[charNum + 1]))
1431 currentLine.insert(charNum + 1, " ");
1434 if (isClassInitializer())
1435 isInClassInitializer = true;
1438 if (currentChar == '?')
1439 foundQuestionMark = true;
1441 if (isPotentialHeader && !isInTemplate)
1443 if (findKeyword(currentLine, charNum, AS_NEW)
1444 || findKeyword(currentLine, charNum, AS_DELETE))
1446 isInPotentialCalculation = false;
1447 isImmediatelyPostNewDelete = true;
1450 if (findKeyword(currentLine, charNum, AS_RETURN))
1452 isInPotentialCalculation = true; // return is the same as an = sign
1453 isImmediatelyPostReturn = true;
1456 if (findKeyword(currentLine, charNum, AS_OPERATOR))
1457 isImmediatelyPostOperator = true;
1459 if (findKeyword(currentLine, charNum, AS_ENUM))
1461 size_t firstNum = currentLine.find_first_of("(){},/");
1462 if (firstNum == string::npos
1463 || currentLine[firstNum] == '{'
1464 || currentLine[firstNum] == '/')
1469 && findKeyword(currentLine, charNum, AS_THROW)
1470 && previousCommandChar != ')'
1471 && !foundPreCommandHeader) // 'const' throw()
1472 isImmediatelyPostThrow = true;
1474 if (isCStyle() && findKeyword(currentLine, charNum, AS_EXTERN) && isExternC())
1477 if (isCStyle() && findKeyword(currentLine, charNum, AS_AUTO)
1478 && (isBraceType(braceTypeStack->back(), NULL_TYPE)
1479 || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE)
1480 || isBraceType(braceTypeStack->back(), CLASS_TYPE)))
1481 foundTrailingReturnType = true;
1483 // Objective-C NSException macros are preCommandHeaders
1484 if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_DURING))
1485 foundPreCommandMacro = true;
1486 if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_HANDLER))
1487 foundPreCommandMacro = true;
1489 if (isCStyle() && isExecSQL(currentLine, charNum))
1494 if (findKeyword(currentLine, charNum, AS_ASM)
1495 || findKeyword(currentLine, charNum, AS__ASM__))
1499 else if (findKeyword(currentLine, charNum, AS_MS_ASM) // microsoft specific
1500 || findKeyword(currentLine, charNum, AS_MS__ASM))
1503 if (peekNextChar() == '_') // check for __asm
1506 char peekedChar = ASBase::peekNextChar(currentLine, charNum + index);
1507 if (peekedChar == '{' || peekedChar == ' ')
1508 isInAsmBlock = true;
1510 isInAsmOneLine = true;
1515 && (findKeyword(currentLine, charNum, AS_STATIC)
1516 && isNextCharOpeningBrace(charNum + 6)))
1517 isJavaStaticConstructor = true;
1520 && (findKeyword(currentLine, charNum, AS_DELEGATE)
1521 || findKeyword(currentLine, charNum, AS_UNCHECKED)))
1522 isSharpDelegate = true;
1524 // append the entire name
1525 string name = getCurrentWord(currentLine, charNum);
1526 // must pad the 'and' and 'or' operators if required
1527 if (name == "and" || name == "or")
1529 if (shouldPadOperators && previousNonWSChar != ':')
1532 appendOperator(name);
1533 goForward(name.length() - 1);
1534 if (!isBeforeAnyComment()
1535 && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0)
1536 && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0))
1541 appendOperator(name);
1542 goForward(name.length() - 1);
1547 appendSequence(name);
1548 goForward(name.length() - 1);
1553 } // (isPotentialHeader && !isInTemplate)
1555 // determine if this is an Objective-C statement
1557 if (currentChar == '@'
1558 && isCharPotentialHeader(currentLine, charNum + 1)
1559 && findKeyword(currentLine, charNum + 1, AS_INTERFACE)
1560 && isBraceType(braceTypeStack->back(), NULL_TYPE))
1562 isInObjCInterface = true;
1563 string name = '@' + AS_INTERFACE;
1564 appendSequence(name);
1565 goForward(name.length() - 1);
1568 else if (currentChar == '@'
1569 && isCharPotentialHeader(currentLine, charNum + 1)
1570 && findKeyword(currentLine, charNum + 1, AS_SELECTOR))
1572 isInObjCSelector = true;
1573 string name = '@' + AS_SELECTOR;
1574 appendSequence(name);
1575 goForward(name.length() - 1);
1578 else if ((currentChar == '-' || currentChar == '+')
1579 && (int) currentLine.find_first_not_of(" \t") == charNum
1580 && peekNextChar() == '('
1581 && isBraceType(braceTypeStack->back(), NULL_TYPE)
1582 && !isInPotentialCalculation)
1584 isInObjCMethodDefinition = true;
1585 isImmediatelyPostObjCMethodPrefix = true;
1586 isInObjCInterface = false;
1587 if (getAlignMethodColon())
1588 objCColonAlign = findObjCColonAlignment();
1589 appendCurrentChar();
1593 // determine if this is a potential calculation
1595 bool isPotentialOperator = isCharPotentialOperator(currentChar);
1596 newHeader = nullptr;
1598 if (isPotentialOperator)
1600 newHeader = findOperator(operators);
1602 // check for Java ? wildcard
1603 if (newHeader != nullptr
1604 && newHeader == &AS_GCC_MIN_ASSIGN
1607 newHeader = nullptr;
1609 if (newHeader != nullptr)
1611 if (newHeader == &AS_LAMBDA)
1612 foundPreCommandHeader = true;
1614 // correct mistake of two >> closing a template
1615 if (isInTemplate && (newHeader == &AS_GR_GR || newHeader == &AS_GR_GR_GR))
1618 if (!isInPotentialCalculation)
1620 // must determine if newHeader is an assignment operator
1621 // do NOT use findOperator - the length must be exact!!!
1622 if (find(begin(*assignmentOperators), end(*assignmentOperators), newHeader)
1623 != end(*assignmentOperators))
1625 foundPreCommandHeader = false;
1626 char peekedChar = peekNextChar();
1627 isInPotentialCalculation = !(newHeader == &AS_EQUAL && peekedChar == '*')
1628 && !(newHeader == &AS_EQUAL && peekedChar == '&')
1629 && !isCharImmediatelyPostOperator;
1635 // process pointers and references
1636 // check newHeader to eliminate things like '&&' sequence
1637 if (newHeader != nullptr && !isJavaStyle()
1638 && (newHeader == &AS_MULT
1639 || newHeader == &AS_BIT_AND
1640 || newHeader == &AS_BIT_XOR
1641 || newHeader == &AS_AND)
1642 && isPointerOrReference())
1644 if (!isDereferenceOrAddressOf() && !isOperatorPaddingDisabled())
1645 formatPointerOrReference();
1648 appendOperator(*newHeader);
1649 goForward(newHeader->length() - 1);
1651 isImmediatelyPostPointerOrReference = true;
1655 if (shouldPadOperators && newHeader != nullptr && !isOperatorPaddingDisabled())
1657 padOperators(newHeader);
1661 // remove spaces before commas
1662 if (currentChar == ',')
1664 const size_t len = formattedLine.length();
1665 size_t lastText = formattedLine.find_last_not_of(' ');
1666 if (lastText != string::npos && lastText < len - 1)
1668 formattedLine.resize(lastText + 1);
1669 int size_diff = len - (lastText + 1);
1670 spacePadNum -= size_diff;
1674 // pad commas and semi-colons
1675 if (currentChar == ';'
1676 || (currentChar == ',' && (shouldPadOperators || shouldPadCommas)))
1678 char nextChar = ' ';
1679 if (charNum + 1 < (int) currentLine.length())
1680 nextChar = currentLine[charNum + 1];
1681 if (!isWhiteSpace(nextChar)
1687 && !isBeforeAnyComment()
1688 /* && !(isBraceType(braceTypeStack->back(), ARRAY_TYPE)) */
1691 appendCurrentChar();
1698 if (currentChar == '(' || currentChar == ')')
1700 if (currentChar == '(')
1703 && (isCharImmediatelyPostReturn
1704 || isCharImmediatelyPostThrow
1705 || isCharImmediatelyPostNewDelete))
1709 if (shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen)
1712 appendCurrentChar();
1714 if (isInObjCMethodDefinition)
1716 if (currentChar == '(' && isImmediatelyPostObjCMethodPrefix)
1718 if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)
1719 padObjCMethodPrefix();
1720 isImmediatelyPostObjCMethodPrefix = false;
1721 isInObjCReturnType = true;
1723 else if (currentChar == ')' && isInObjCReturnType)
1725 if (shouldPadReturnType || shouldUnPadReturnType)
1726 padObjCReturnType();
1727 isInObjCReturnType = false;
1729 else if (shouldPadParamType || shouldUnPadParamType)
1735 // bypass the entire operator
1736 if (newHeader != nullptr)
1738 appendOperator(*newHeader);
1739 goForward(newHeader->length() - 1);
1743 appendCurrentChar();
1745 } // end of while loop * end of while loop * end of while loop * end of while loop
1747 // return a beautified (i.e. correctly indented) line.
1749 string beautifiedLine;
1750 size_t readyFormattedLineLength = trim(readyFormattedLine).length();
1751 bool isInNamespace = isBraceType(braceTypeStack->back(), NAMESPACE_TYPE);
1753 if (prependEmptyLine // prepend a blank line before this formatted line
1754 && readyFormattedLineLength > 0
1755 && previousReadyFormattedLineLength > 0)
1757 isLineReady = true; // signal a waiting readyFormattedLine
1758 beautifiedLine = beautify("");
1759 previousReadyFormattedLineLength = 0;
1760 // call the enhancer for new empty lines
1761 enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);
1763 else // format the current formatted line
1765 isLineReady = false;
1766 runInIndentContinuation = runInIndentChars;
1767 beautifiedLine = beautify(readyFormattedLine);
1768 previousReadyFormattedLineLength = readyFormattedLineLength;
1769 // the enhancer is not called for no-indent line comments
1770 if (!lineCommentNoBeautify && !isFormattingModeOff)
1771 enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);
1772 runInIndentChars = 0;
1773 lineCommentNoBeautify = lineCommentNoIndent;
1774 lineCommentNoIndent = false;
1775 isInIndentablePreproc = isIndentableProprocessor;
1776 isIndentableProprocessor = false;
1777 isElseHeaderIndent = elseHeaderFollowsComments;
1778 isCaseHeaderCommentIndent = caseHeaderFollowsComments;
1779 objCColonAlignSubsequent = objCColonAlign;
1780 if (isCharImmediatelyPostNonInStmt)
1782 isNonInStatementArray = false;
1783 isCharImmediatelyPostNonInStmt = false;
1785 isInPreprocessorBeautify = isInPreprocessor; // used by ASEnhancer
1786 isInBeautifySQL = isInExecSQL; // used by ASEnhancer
1789 prependEmptyLine = false;
1790 assert(computeChecksumOut(beautifiedLine));
1791 return beautifiedLine;
1795 * check if there are any indented lines ready to be read by nextLine()
1797 * @return are there any indented lines ready?
1799 bool ASFormatter::hasMoreLines() const
1801 return !endOfCodeReached;
1805 * comparison function for BraceType enum
1807 bool ASFormatter::isBraceType(BraceType a, BraceType b) const
1809 if (a == NULL_TYPE || b == NULL_TYPE)
1811 return ((a & b) == b);
1815 * set the formatting style.
1817 * @param style the formatting style.
1819 void ASFormatter::setFormattingStyle(FormatStyle style)
1821 formattingStyle = style;
1825 * set the add braces mode.
1827 * true braces added to headers for single line statements.
1828 * false braces NOT added to headers for single line statements.
1830 * @param state the add braces state.
1832 void ASFormatter::setAddBracesMode(bool state)
1834 shouldAddBraces = state;
1838 * set the add one line braces mode.
1840 * true one line braces added to headers for single line statements.
1841 * false one line braces NOT added to headers for single line statements.
1843 * @param state the add one line braces state.
1845 void ASFormatter::setAddOneLineBracesMode(bool state)
1847 shouldAddBraces = state;
1848 shouldAddOneLineBraces = state;
1852 * set the remove braces mode.
1854 * true braces removed from headers for single line statements.
1855 * false braces NOT removed from headers for single line statements.
1857 * @param state the remove braces state.
1859 void ASFormatter::setRemoveBracesMode(bool state)
1861 shouldRemoveBraces = state;
1864 // retained for compatability with release 2.06
1865 // "Brackets" have been changed to "Braces" in 3.0
1866 // it is referenced only by the old "bracket" options
1867 void ASFormatter::setAddBracketsMode(bool state)
1869 setAddBracesMode(state);
1872 // retained for compatability with release 2.06
1873 // "Brackets" have been changed to "Braces" in 3.0
1874 // it is referenced only by the old "bracket" options
1875 void ASFormatter::setAddOneLineBracketsMode(bool state)
1877 setAddOneLineBracesMode(state);
1880 // retained for compatability with release 2.06
1881 // "Brackets" have been changed to "Braces" in 3.0
1882 // it is referenced only by the old "bracket" options
1883 void ASFormatter::setRemoveBracketsMode(bool state)
1885 setRemoveBracesMode(state);
1888 // retained for compatability with release 2.06
1889 // "Brackets" have been changed to "Braces" in 3.0
1890 // it is referenced only by the old "bracket" options
1891 void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
1893 setBreakClosingHeaderBracesMode(state);
1898 * set the brace formatting mode.
1901 * @param mode the brace formatting mode.
1903 void ASFormatter::setBraceFormatMode(BraceMode mode)
1905 braceFormatMode = mode;
1909 * set 'break after' mode for maximum code length
1911 * @param state the 'break after' mode.
1913 void ASFormatter::setBreakAfterMode(bool state)
1915 shouldBreakLineAfterLogical = state;
1919 * set closing header brace breaking mode
1921 * true braces just before closing headers (e.g. 'else', 'catch')
1922 * will be broken, even if standard braces are attached.
1923 * false closing header braces will be treated as standard braces.
1925 * @param state the closing header brace breaking mode.
1927 void ASFormatter::setBreakClosingHeaderBracesMode(bool state)
1929 shouldBreakClosingHeaderBraces = state;
1933 * set 'else if()' breaking mode
1935 * true 'else' headers will be broken from their succeeding 'if' headers.
1936 * false 'else' headers will be attached to their succeeding 'if' headers.
1938 * @param state the 'else if()' breaking mode.
1940 void ASFormatter::setBreakElseIfsMode(bool state)
1942 shouldBreakElseIfs = state;
1946 * set comma padding mode.
1948 * true statement commas and semicolons will be padded with spaces around them.
1949 * false statement commas and semicolons will not be padded.
1951 * @param state the padding mode.
1953 void ASFormatter::setCommaPaddingMode(bool state)
1955 shouldPadCommas = state;
1959 * set maximum code length
1961 * @param max the maximum code length.
1963 void ASFormatter::setMaxCodeLength(int max)
1965 maxCodeLength = max;
1969 * set operator padding mode.
1971 * true statement operators will be padded with spaces around them.
1972 * false statement operators will not be padded.
1974 * @param state the padding mode.
1976 void ASFormatter::setOperatorPaddingMode(bool state)
1978 shouldPadOperators = state;
1982 * set parenthesis outside padding mode.
1984 * true statement parentheses will be padded with spaces around them.
1985 * false statement parentheses will not be padded.
1987 * @param state the padding mode.
1989 void ASFormatter::setParensOutsidePaddingMode(bool state)
1991 shouldPadParensOutside = state;
1995 * set parenthesis inside padding mode.
1997 * true statement parenthesis will be padded with spaces around them.
1998 * false statement parenthesis will not be padded.
2000 * @param state the padding mode.
2002 void ASFormatter::setParensInsidePaddingMode(bool state)
2004 shouldPadParensInside = state;
2008 * set padding mode before one or more open parentheses.
2010 * true first open parenthesis will be padded with a space before.
2011 * false first open parenthesis will not be padded.
2013 * @param state the padding mode.
2015 void ASFormatter::setParensFirstPaddingMode(bool state)
2017 shouldPadFirstParen = state;
2021 * set header padding mode.
2023 * true headers will be padded with spaces around them.
2024 * false headers will not be padded.
2026 * @param state the padding mode.
2028 void ASFormatter::setParensHeaderPaddingMode(bool state)
2030 shouldPadHeader = state;
2034 * set parenthesis unpadding mode.
2036 * true statement parenthesis will be unpadded with spaces removed around them.
2037 * false statement parenthesis will not be unpadded.
2039 * @param state the padding mode.
2041 void ASFormatter::setParensUnPaddingMode(bool state)
2043 shouldUnPadParens = state;
2047 * set the state of the preprocessor indentation option.
2048 * If true, #ifdef blocks at level 0 will be indented.
2050 * @param state state of option.
2052 void ASFormatter::setPreprocBlockIndent(bool state)
2054 shouldIndentPreprocBlock = state;
2058 * Set strip comment prefix mode.
2060 * true strip leading '*' in a comment.
2061 * false leading '*' in a comment will be left unchanged.
2063 * @param state the strip comment prefix mode.
2065 void ASFormatter::setStripCommentPrefix(bool state)
2067 shouldStripCommentPrefix = state;
2071 * set objective-c '-' or '+' class prefix padding mode.
2073 * true class prefix will be padded a spaces after them.
2074 * false class prefix will be left unchanged.
2076 * @param state the padding mode.
2078 void ASFormatter::setMethodPrefixPaddingMode(bool state)
2080 shouldPadMethodPrefix = state;
2084 * set objective-c '-' or '+' class prefix unpadding mode.
2086 * true class prefix will be unpadded with spaces after them removed.
2087 * false class prefix will left unchanged.
2089 * @param state the unpadding mode.
2091 void ASFormatter::setMethodPrefixUnPaddingMode(bool state)
2093 shouldUnPadMethodPrefix = state;
2096 // set objective-c '-' or '+' return type padding mode.
2097 void ASFormatter::setReturnTypePaddingMode(bool state)
2099 shouldPadReturnType = state;
2102 // set objective-c '-' or '+' return type unpadding mode.
2103 void ASFormatter::setReturnTypeUnPaddingMode(bool state)
2105 shouldUnPadReturnType = state;
2108 // set objective-c method parameter type padding mode.
2109 void ASFormatter::setParamTypePaddingMode(bool state)
2111 shouldPadParamType = state;
2114 // set objective-c method parameter type unpadding mode.
2115 void ASFormatter::setParamTypeUnPaddingMode(bool state)
2117 shouldUnPadParamType = state;
2121 * set objective-c method colon padding mode.
2123 * @param mode objective-c colon padding mode.
2125 void ASFormatter::setObjCColonPaddingMode(ObjCColonPad mode)
2127 shouldPadMethodColon = true;
2128 objCColonPadMode = mode;
2132 * set option to attach closing braces
2134 * @param state true = attach, false = don't attach.
2136 void ASFormatter::setAttachClosingBraceMode(bool state)
2138 attachClosingBraceMode = state;
2142 * set option to attach class braces
2144 * @param state true = attach, false = use style default.
2146 void ASFormatter::setAttachClass(bool state)
2148 shouldAttachClass = state;
2152 * set option to attach extern "C" braces
2154 * @param state true = attach, false = use style default.
2156 void ASFormatter::setAttachExternC(bool state)
2158 shouldAttachExternC = state;
2162 * set option to attach namespace braces
2164 * @param state true = attach, false = use style default.
2166 void ASFormatter::setAttachNamespace(bool state)
2168 shouldAttachNamespace = state;
2172 * set option to attach inline braces
2174 * @param state true = attach, false = use style default.
2176 void ASFormatter::setAttachInline(bool state)
2178 shouldAttachInline = state;
2181 void ASFormatter::setAttachClosingWhile(bool state)
2183 shouldAttachClosingWhile = state;
2187 * set option to break/not break one-line blocks
2189 * @param state true = break, false = don't break.
2191 void ASFormatter::setBreakOneLineBlocksMode(bool state)
2193 shouldBreakOneLineBlocks = state;
2197 * set one line headers breaking mode
2199 void ASFormatter::setBreakOneLineHeadersMode(bool state)
2201 shouldBreakOneLineHeaders = state;
2205 * set option to break/not break lines consisting of multiple statements.
2207 * @param state true = break, false = don't break.
2209 void ASFormatter::setBreakOneLineStatementsMode(bool state)
2211 shouldBreakOneLineStatements = state;
2214 void ASFormatter::setCloseTemplatesMode(bool state)
2216 shouldCloseTemplates = state;
2220 * set option to convert tabs to spaces.
2222 * @param state true = convert, false = don't convert.
2224 void ASFormatter::setTabSpaceConversionMode(bool state)
2226 shouldConvertTabs = state;
2230 * set option to indent comments in column 1.
2232 * @param state true = indent, false = don't indent.
2234 void ASFormatter::setIndentCol1CommentsMode(bool state)
2236 shouldIndentCol1Comments = state;
2240 * set option to force all line ends to a particular style.
2242 * @param fmt format enum value
2244 void ASFormatter::setLineEndFormat(LineEndFormat fmt)
2250 * set option to break unrelated blocks of code with empty lines.
2252 * @param state true = convert, false = don't convert.
2254 void ASFormatter::setBreakBlocksMode(bool state)
2256 shouldBreakBlocks = state;
2260 * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
2262 * @param state true = convert, false = don't convert.
2264 void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
2266 shouldBreakClosingHeaderBlocks = state;
2270 * set option to delete empty lines.
2272 * @param state true = delete, false = don't delete.
2274 void ASFormatter::setDeleteEmptyLinesMode(bool state)
2276 shouldDeleteEmptyLines = state;
2280 * set the pointer alignment.
2282 * @param alignment the pointer alignment.
2284 void ASFormatter::setPointerAlignment(PointerAlign alignment)
2286 pointerAlignment = alignment;
2289 void ASFormatter::setReferenceAlignment(ReferenceAlign alignment)
2291 referenceAlignment = alignment;
2295 * jump over several characters.
2297 * @param i the number of characters to jump over.
2299 void ASFormatter::goForward(int i)
2306 * peek at the next unread character.
2308 * @return the next unread character.
2310 char ASFormatter::peekNextChar() const
2313 size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2315 if (peekNum == string::npos)
2318 ch = currentLine[peekNum];
2324 * check if current placement is before a comment
2326 * @return is before a comment.
2328 bool ASFormatter::isBeforeComment() const
2330 bool foundComment = false;
2331 size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2333 if (peekNum == string::npos)
2334 return foundComment;
2336 foundComment = (currentLine.compare(peekNum, 2, "/*") == 0);
2338 return foundComment;
2342 * check if current placement is before a comment or line-comment
2344 * @return is before a comment or line-comment.
2346 bool ASFormatter::isBeforeAnyComment() const
2348 bool foundComment = false;
2349 size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2351 if (peekNum == string::npos)
2352 return foundComment;
2354 foundComment = (currentLine.compare(peekNum, 2, "/*") == 0
2355 || currentLine.compare(peekNum, 2, "//") == 0);
2357 return foundComment;
2361 * check if current placement is before a comment or line-comment
2362 * if a block comment it must be at the end of the line
2364 * @return is before a comment or line-comment.
2366 bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const
2368 bool foundLineEndComment = false;
2369 size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
2371 if (peekNum != string::npos)
2373 if (currentLine.compare(peekNum, 2, "//") == 0)
2374 foundLineEndComment = true;
2375 else if (currentLine.compare(peekNum, 2, "/*") == 0)
2377 // comment must be closed on this line with nothing after it
2378 size_t endNum = currentLine.find("*/", peekNum + 2);
2379 if (endNum != string::npos)
2381 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
2382 if (nextChar == string::npos)
2383 foundLineEndComment = true;
2387 return foundLineEndComment;
2391 * check if current placement is before a comment followed by a line-comment
2393 * @return is before a multiple line-end comment.
2395 bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const
2397 bool foundMultipleLineEndComment = false;
2398 size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
2400 if (peekNum != string::npos)
2402 if (currentLine.compare(peekNum, 2, "/*") == 0)
2404 // comment must be closed on this line with nothing after it
2405 size_t endNum = currentLine.find("*/", peekNum + 2);
2406 if (endNum != string::npos)
2408 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
2409 if (nextChar != string::npos
2410 && currentLine.compare(nextChar, 2, "//") == 0)
2411 foundMultipleLineEndComment = true;
2415 return foundMultipleLineEndComment;
2419 * get the next character, increasing the current placement in the process.
2420 * the new character is inserted into the variable currentChar.
2422 * @return whether succeeded to receive the new character.
2424 bool ASFormatter::getNextChar()
2426 isInLineBreak = false;
2427 previousChar = currentChar;
2429 if (!isWhiteSpace(currentChar))
2431 previousNonWSChar = currentChar;
2432 if (!isInComment && !isInLineComment && !isInQuote
2433 && !isImmediatelyPostComment
2434 && !isImmediatelyPostLineComment
2435 && !isInPreprocessor
2436 && !isSequenceReached("/*")
2437 && !isSequenceReached("//"))
2438 previousCommandChar = currentChar;
2441 if (charNum + 1 < (int) currentLine.length()
2442 && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
2444 currentChar = currentLine[++charNum];
2446 if (currentChar == '\t' && shouldConvertTabs)
2447 convertTabToSpaces();
2452 // end of line has been reached
2453 return getNextLine();
2457 * get the next line of input, increasing the current placement in the process.
2459 * @param emptyLineWasDeleted an empty line was deleted.
2460 * @return whether succeeded in reading the next line.
2462 bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/)
2464 if (!sourceIterator->hasMoreLines())
2466 endOfCodeReached = true;
2469 if (appendOpeningBrace)
2470 currentLine = "{"; // append brace that was removed from the previous line
2473 currentLine = sourceIterator->nextLine(emptyLineWasDeleted);
2474 assert(computeChecksumIn(currentLine));
2476 // reset variables for new line
2478 if (endOfAsmReached)
2479 endOfAsmReached = isInAsmBlock = isInAsm = false;
2480 shouldKeepLineUnbroken = false;
2481 isInCommentStartLine = false;
2483 isInAsmOneLine = false;
2484 isHeaderInMultiStatementLine = false;
2485 isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
2486 haveLineContinuationChar = false;
2487 isImmediatelyPostEmptyLine = lineIsEmpty;
2490 if (currentLine.length() == 0)
2491 currentLine = string(" "); // a null is inserted if this is not done
2493 // unless reading in the first line of the file, break a new line.
2495 isInLineBreak = true;
2499 if (isImmediatelyPostNonInStmt)
2501 isCharImmediatelyPostNonInStmt = true;
2502 isImmediatelyPostNonInStmt = false;
2505 // check if is in preprocessor before line trimming
2506 // a blank line after a \ will remove the flag
2507 isImmediatelyPostPreprocessor = isInPreprocessor;
2509 && (previousNonWSChar != '\\'
2510 || isEmptyLine(currentLine)))
2511 isInPreprocessor = false;
2513 if (passedSemicolon)
2514 isInExecSQL = false;
2517 currentChar = currentLine[charNum];
2518 if (isInBraceRunIn && previousNonWSChar == '{' && !isInComment)
2519 isInLineBreak = false;
2520 isInBraceRunIn = false;
2522 if (currentChar == '\t' && shouldConvertTabs)
2523 convertTabToSpaces();
2525 // check for an empty line inside a command brace.
2526 // if yes then read the next line (calls getNextLine recursively).
2527 // must be after initNewLine.
2528 if (shouldDeleteEmptyLines
2530 && isBraceType((*braceTypeStack)[braceTypeStack->size() - 1], COMMAND_TYPE))
2532 if (!shouldBreakBlocks || previousNonWSChar == '{' || !commentAndHeaderFollows())
2534 isInPreprocessor = isImmediatelyPostPreprocessor; // restore
2535 lineIsEmpty = false;
2536 return getNextLine(true);
2543 * jump over the leading white space in the current line,
2544 * IF the line does not begin a comment or is in a preprocessor definition.
2546 void ASFormatter::initNewLine()
2548 size_t len = currentLine.length();
2549 size_t tabSize = getTabLength();
2553 if (isInQuoteContinuation
2554 || (isInPreprocessor && !getPreprocDefineIndent()))
2557 // SQL continuation lines must be adjusted so the leading spaces
2558 // is equivalent to the opening EXEC SQL
2561 // replace leading tabs with spaces
2562 // so that continuation indent will be spaces
2563 size_t tabCount_ = 0;
2565 for (i = 0; i < currentLine.length(); i++)
2567 if (!isWhiteSpace(currentLine[i])) // stop at first text
2569 if (currentLine[i] == '\t')
2571 size_t numSpaces = tabSize - ((tabCount_ + i) % tabSize);
2572 currentLine.replace(i, 1, numSpaces, ' ');
2577 // this will correct the format if EXEC SQL is not a hanging indent
2578 trimContinuationLine();
2582 // comment continuation lines must be adjusted so the leading spaces
2583 // is equivalent to the opening comment
2586 if (noTrimCommentContinuation)
2587 leadingSpaces = tabIncrementIn = 0;
2588 trimContinuationLine();
2592 // compute leading spaces
2593 isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly;
2594 lineIsCommentOnly = false;
2595 lineIsLineCommentOnly = false;
2596 lineEndsInCommentOnly = false;
2597 doesLineStartComment = false;
2598 currentLineBeginsWithBrace = false;
2599 lineIsEmpty = false;
2600 currentLineFirstBraceNum = string::npos;
2603 // bypass whitespace at the start of a line
2604 // preprocessor tabs are replaced later in the program
2605 for (charNum = 0; isWhiteSpace(currentLine[charNum]) && charNum + 1 < (int) len; charNum++)
2607 if (currentLine[charNum] == '\t' && !isInPreprocessor)
2608 tabIncrementIn += tabSize - 1 - ((tabIncrementIn + charNum) % tabSize);
2610 leadingSpaces = charNum + tabIncrementIn;
2612 if (isSequenceReached("/*"))
2614 doesLineStartComment = true;
2615 if ((int) currentLine.length() > charNum + 2
2616 && currentLine.find("*/", charNum + 2) != string::npos)
2617 lineIsCommentOnly = true;
2619 else if (isSequenceReached("//"))
2621 lineIsLineCommentOnly = true;
2623 else if (isSequenceReached("{"))
2625 currentLineBeginsWithBrace = true;
2626 currentLineFirstBraceNum = charNum;
2627 size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1);
2628 if (firstText != string::npos)
2630 if (currentLine.compare(firstText, 2, "//") == 0)
2631 lineIsLineCommentOnly = true;
2632 else if (currentLine.compare(firstText, 2, "/*") == 0
2633 || isExecSQL(currentLine, firstText))
2635 // get the extra adjustment
2637 for (j = charNum + 1; j < firstText && isWhiteSpace(currentLine[j]); j++)
2639 if (currentLine[j] == '\t')
2640 tabIncrementIn += tabSize - 1 - ((tabIncrementIn + j) % tabSize);
2642 leadingSpaces = j + tabIncrementIn;
2643 if (currentLine.compare(firstText, 2, "/*") == 0)
2644 doesLineStartComment = true;
2648 else if (isWhiteSpace(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length()))
2653 // do not trim indented preprocessor define (except for comment continuation lines)
2654 if (isInPreprocessor)
2656 if (!doesLineStartComment)
2663 * Append a character to the current formatted line.
2664 * The formattedLine split points are updated.
2666 * @param ch the character to append.
2667 * @param canBreakLine if true, a registered line-break
2669 void ASFormatter::appendChar(char ch, bool canBreakLine)
2671 if (canBreakLine && isInLineBreak)
2674 formattedLine.append(1, ch);
2675 isImmediatelyPostCommentOnly = false;
2676 if (maxCodeLength != string::npos)
2678 // These compares reduce the frequency of function calls.
2679 if (isOkToSplitFormattedLine())
2680 updateFormattedLineSplitPoints(ch);
2681 if (formattedLine.length() > maxCodeLength)
2682 testForTimeToSplitFormattedLine();
2687 * Append a string sequence to the current formatted line.
2688 * The formattedLine split points are NOT updated.
2689 * But the formattedLine is checked for time to split.
2691 * @param sequence the sequence to append.
2692 * @param canBreakLine if true, a registered line-break
2694 void ASFormatter::appendSequence(const string& sequence, bool canBreakLine)
2696 if (canBreakLine && isInLineBreak)
2698 formattedLine.append(sequence);
2699 if (formattedLine.length() > maxCodeLength)
2700 testForTimeToSplitFormattedLine();
2704 * Append an operator sequence to the current formatted line.
2705 * The formattedLine split points are updated.
2707 * @param sequence the sequence to append.
2708 * @param canBreakLine if true, a registered line-break
2710 void ASFormatter::appendOperator(const string& sequence, bool canBreakLine)
2712 if (canBreakLine && isInLineBreak)
2714 formattedLine.append(sequence);
2715 if (maxCodeLength != string::npos)
2717 // These compares reduce the frequency of function calls.
2718 if (isOkToSplitFormattedLine())
2719 updateFormattedLineSplitPointsOperator(sequence);
2720 if (formattedLine.length() > maxCodeLength)
2721 testForTimeToSplitFormattedLine();
2726 * append a space to the current formattedline, UNLESS the
2727 * last character is already a white-space character.
2729 void ASFormatter::appendSpacePad()
2731 int len = formattedLine.length();
2732 if (len > 0 && !isWhiteSpace(formattedLine[len - 1]))
2734 formattedLine.append(1, ' ');
2736 if (maxCodeLength != string::npos)
2738 // These compares reduce the frequency of function calls.
2739 if (isOkToSplitFormattedLine())
2740 updateFormattedLineSplitPoints(' ');
2741 if (formattedLine.length() > maxCodeLength)
2742 testForTimeToSplitFormattedLine();
2748 * append a space to the current formattedline, UNLESS the
2749 * next character is already a white-space character.
2751 void ASFormatter::appendSpaceAfter()
2753 int len = currentLine.length();
2754 if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum + 1]))
2756 formattedLine.append(1, ' ');
2758 if (maxCodeLength != string::npos)
2760 // These compares reduce the frequency of function calls.
2761 if (isOkToSplitFormattedLine())
2762 updateFormattedLineSplitPoints(' ');
2763 if (formattedLine.length() > maxCodeLength)
2764 testForTimeToSplitFormattedLine();
2770 * register a line break for the formatted line.
2772 void ASFormatter::breakLine(bool isSplitLine /*false*/)
2775 isInLineBreak = false;
2776 spacePadNum = nextLineSpacePadNum;
2777 nextLineSpacePadNum = 0;
2778 readyFormattedLine = formattedLine;
2779 formattedLine.erase();
2780 // queue an empty line prepend request if one exists
2781 prependEmptyLine = isPrependPostBlockEmptyLineRequested;
2785 formattedLineCommentNum = string::npos;
2786 clearFormattedLineSplitPoints();
2788 if (isAppendPostBlockEmptyLineRequested)
2790 isAppendPostBlockEmptyLineRequested = false;
2791 isPrependPostBlockEmptyLineRequested = true;
2794 isPrependPostBlockEmptyLineRequested = false;
2799 * check if the currently reached open-brace (i.e. '{')
2801 * - a definition type block (such as a class or namespace),
2802 * - a command block (such as a method block)
2804 * this method takes for granted that the current character
2805 * is an opening brace.
2807 * @return the type of the opened block.
2809 BraceType ASFormatter::getBraceType()
2811 assert(currentChar == '{');
2813 BraceType returnVal = NULL_TYPE;
2815 if ((previousNonWSChar == '='
2816 || isBraceType(braceTypeStack->back(), ARRAY_TYPE))
2817 && previousCommandChar != ')'
2818 && !isNonParenHeader)
2819 returnVal = ARRAY_TYPE;
2820 else if (foundPreDefinitionHeader && previousCommandChar != ')')
2822 returnVal = DEFINITION_TYPE;
2823 if (foundNamespaceHeader)
2824 returnVal = (BraceType)(returnVal | NAMESPACE_TYPE);
2825 else if (foundClassHeader)
2826 returnVal = (BraceType)(returnVal | CLASS_TYPE);
2827 else if (foundStructHeader)
2828 returnVal = (BraceType)(returnVal | STRUCT_TYPE);
2829 else if (foundInterfaceHeader)
2830 returnVal = (BraceType)(returnVal | INTERFACE_TYPE);
2834 returnVal = (BraceType)(ARRAY_TYPE | ENUM_TYPE);
2838 bool isCommandType = (foundPreCommandHeader
2839 || foundPreCommandMacro
2840 || (currentHeader != nullptr && isNonParenHeader)
2841 || (previousCommandChar == ')')
2842 || (previousCommandChar == ':' && !foundQuestionMark)
2843 || (previousCommandChar == ';')
2844 || ((previousCommandChar == '{' || previousCommandChar == '}')
2845 && isPreviousBraceBlockRelated)
2846 || (isInClassInitializer
2847 && (!isLegalNameChar(previousNonWSChar) || foundPreCommandHeader))
2848 || foundTrailingReturnType
2849 || isInObjCMethodDefinition
2850 || isInObjCInterface
2851 || isJavaStaticConstructor
2852 || isSharpDelegate);
2854 // C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens
2855 if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1))
2857 isCommandType = true;
2858 isSharpAccessor = true;
2862 returnVal = (isCommandType ? COMMAND_TYPE : EXTERN_TYPE);
2864 returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
2867 int foundOneLineBlock = isOneLineBlockReached(currentLine, charNum);
2869 if (foundOneLineBlock == 2 && returnVal == COMMAND_TYPE)
2870 returnVal = ARRAY_TYPE;
2872 if (foundOneLineBlock > 0)
2874 returnVal = (BraceType) (returnVal | SINGLE_LINE_TYPE);
2875 if (breakCurrentOneLineBlock)
2876 returnVal = (BraceType) (returnVal | BREAK_BLOCK_TYPE);
2877 if (foundOneLineBlock == 3)
2878 returnVal = (BraceType)(returnVal | EMPTY_BLOCK_TYPE);
2881 if (isBraceType(returnVal, ARRAY_TYPE))
2883 if (isNonInStatementArrayBrace())
2885 returnVal = (BraceType)(returnVal | ARRAY_NIS_TYPE);
2886 isNonInStatementArray = true;
2887 isImmediatelyPostNonInStmt = false; // in case of "},{"
2888 nonInStatementBrace = formattedLine.length() - 1;
2890 if (isUniformInitializerBrace())
2891 returnVal = (BraceType)(returnVal | INIT_TYPE);
2898 * check if a colon is a class initializer separator
2900 * @return whether it is a class initializer separator
2902 bool ASFormatter::isClassInitializer() const
2904 assert(currentChar == ':');
2905 assert(previousChar != ':' && peekNextChar() != ':'); // not part of '::'
2907 // this should be similar to ASBeautifier::parseCurrentLine()
2908 bool foundClassInitializer = false;
2910 if (foundQuestionMark)
2912 // do nothing special
2914 else if (parenStack->back() > 0)
2916 // found a 'for' loop or an objective-C statement
2917 // so do nothing special
2921 // found an enum with a base-type
2925 && (previousCommandChar == ')' || foundPreCommandHeader))
2927 // found a 'class' c'tor initializer
2928 foundClassInitializer = true;
2930 return foundClassInitializer;
2934 * check if a line is empty
2936 * @return whether line is empty
2938 bool ASFormatter::isEmptyLine(const string& line) const
2940 return line.find_first_not_of(" \t") == string::npos;
2944 * Check if the following text is "C" as in extern "C".
2946 * @return whether the statement is extern "C"
2948 bool ASFormatter::isExternC() const
2950 // charNum should be at 'extern'
2951 assert(!isWhiteSpace(currentLine[charNum]));
2952 size_t startQuote = currentLine.find_first_of(" \t\"", charNum);
2953 if (startQuote == string::npos)
2955 startQuote = currentLine.find_first_not_of(" \t", startQuote);
2956 if (startQuote == string::npos)
2958 if (currentLine.compare(startQuote, 3, "\"C\"") != 0)
2964 * Check if the currently reached '*', '&' or '^' character is
2965 * a pointer-or-reference symbol, or another operator.
2966 * A pointer dereference (*) or an "address of" character (&)
2967 * counts as a pointer or reference because it is not an
2968 * arithmetic operator.
2970 * @return whether current character is a reference-or-pointer
2972 bool ASFormatter::isPointerOrReference() const
2974 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
2979 if (isCharImmediatelyPostOperator)
2982 // get the last legal word (may be a number)
2983 string lastWord = getPreviousWord(currentLine, charNum);
2984 if (lastWord.empty())
2987 // check for preceding or following numeric values
2988 string nextText = peekNextText(currentLine.substr(charNum + 1));
2989 if (nextText.length() == 0)
2991 char nextChar = nextText[0];
2992 if (isDigit(lastWord[0])
2993 || isDigit(nextChar)
2998 // check for multiply then a dereference (a * *b)
2999 if (currentChar == '*'
3000 && charNum < (int) currentLine.length() - 1
3001 && isWhiteSpace(currentLine[charNum + 1])
3005 if ((foundCastOperator && nextChar == '>')
3006 || isPointerOrReferenceVariable(lastWord))
3009 if (isInClassInitializer
3010 && previousNonWSChar != '('
3011 && previousNonWSChar != '{'
3012 && previousCommandChar != ','
3017 //check for rvalue reference
3018 if (currentChar == '&' && nextChar == '&')
3020 if (previousNonWSChar == '>')
3022 string followingText;
3023 if ((int) currentLine.length() > charNum + 2)
3024 followingText = peekNextText(currentLine.substr(charNum + 2));
3025 if (followingText.length() > 0 && followingText[0] == ')')
3027 if (currentHeader != nullptr || isInPotentialCalculation)
3029 if (parenStack->back() > 0 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
3034 || previousNonWSChar == '='
3035 || previousNonWSChar == '('
3036 || previousNonWSChar == '['
3037 || isCharImmediatelyPostReturn
3039 || isCharImmediatelyPostTemplate
3040 || currentHeader == &AS_CATCH
3041 || currentHeader == &AS_FOREACH
3042 || currentHeader == &AS_QFOREACH)
3045 if (isBraceType(braceTypeStack->back(), ARRAY_TYPE)
3046 && isLegalNameChar(lastWord[0])
3047 && isLegalNameChar(nextChar)
3048 && previousNonWSChar != ')')
3050 if (isArrayOperator())
3054 // checks on operators in parens
3055 if (parenStack->back() > 0
3056 && isLegalNameChar(lastWord[0])
3057 && isLegalNameChar(nextChar))
3059 // if followed by an assignment it is a pointer or reference
3060 // if followed by semicolon it is a pointer or reference in range-based for
3061 const string* followingOperator = getFollowingOperator();
3062 if (followingOperator != nullptr
3063 && followingOperator != &AS_MULT
3064 && followingOperator != &AS_BIT_AND)
3066 if (followingOperator == &AS_ASSIGN || followingOperator == &AS_COLON)
3071 if (isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3072 || squareBracketCount > 0)
3077 // checks on operators in parens with following '('
3078 if (parenStack->back() > 0
3080 && previousNonWSChar != ','
3081 && previousNonWSChar != '('
3082 && previousNonWSChar != '!'
3083 && previousNonWSChar != '&'
3084 && previousNonWSChar != '*'
3085 && previousNonWSChar != '|')
3091 size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
3092 if (nextNum != string::npos)
3094 if (currentLine.compare(nextNum, 2, "++") != 0
3095 && currentLine.compare(nextNum, 2, "--") != 0)
3100 bool isPR = (!isInPotentialCalculation
3101 || (!isLegalNameChar(previousNonWSChar)
3102 && !(previousNonWSChar == ')' && nextChar == '(')
3103 && !(previousNonWSChar == ')' && currentChar == '*' && !isImmediatelyPostCast())
3104 && previousNonWSChar != ']')
3105 || (!isWhiteSpace(nextChar)
3109 && !isLegalNameChar(nextChar))
3116 * Check if the currently reached '*' or '&' character is
3117 * a dereferenced pointer or "address of" symbol.
3118 * NOTE: this MUST be a pointer or reference as determined by
3119 * the function isPointerOrReference().
3121 * @return whether current character is a dereference or address of
3123 bool ASFormatter::isDereferenceOrAddressOf() const
3125 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3127 if (isCharImmediatelyPostTemplate)
3130 if (previousNonWSChar == '='
3131 || previousNonWSChar == ','
3132 || previousNonWSChar == '.'
3133 || previousNonWSChar == '{'
3134 || previousNonWSChar == '>'
3135 || previousNonWSChar == '<'
3136 || previousNonWSChar == '?'
3137 || isCharImmediatelyPostLineComment
3138 || isCharImmediatelyPostComment
3139 || isCharImmediatelyPostReturn)
3142 char nextChar = peekNextChar();
3143 if (currentChar == '*' && nextChar == '*')
3145 if (previousNonWSChar == '(')
3147 if ((int) currentLine.length() < charNum + 2)
3151 if (currentChar == '&' && nextChar == '&')
3153 if (previousNonWSChar == '(' || isInTemplate)
3155 if ((int) currentLine.length() < charNum + 2)
3160 // check first char on the line
3161 if (charNum == (int) currentLine.find_first_not_of(" \t")
3162 && (isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3163 || parenStack->back() != 0))
3166 string nextText = peekNextText(currentLine.substr(charNum + 1));
3167 if (nextText.length() > 0)
3169 if (nextText[0] == ')' || nextText[0] == '>'
3170 || nextText[0] == ',' || nextText[0] == '=')
3172 if (nextText[0] == ';')
3176 // check for reference to a pointer *& (cannot have &*)
3177 if ((currentChar == '*' && nextChar == '&')
3178 || (previousNonWSChar == '*' && currentChar == '&'))
3181 if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3182 && parenStack->back() == 0)
3185 string lastWord = getPreviousWord(currentLine, charNum);
3186 if (lastWord == "else" || lastWord == "delete")
3189 if (isPointerOrReferenceVariable(lastWord))
3192 bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>')
3193 || (nextText.length() > 0 && !isLegalNameChar(nextText[0]) && nextText[0] != '/')
3194 || (ispunct((unsigned char)previousNonWSChar) && previousNonWSChar != '.')
3195 || isCharImmediatelyPostReturn);
3201 * Check if the currently reached '*' or '&' character is
3202 * centered with one space on each side.
3203 * Only spaces are checked, not tabs.
3204 * If true then a space will be deleted on the output.
3206 * @return whether current character is centered.
3208 bool ASFormatter::isPointerOrReferenceCentered() const
3210 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3212 int prNum = charNum;
3213 int lineLength = (int) currentLine.length();
3215 // check for end of line
3216 if (peekNextChar() == ' ')
3219 // check space before
3221 || currentLine[prNum - 1] != ' ')
3224 // check no space before that
3226 || currentLine[prNum - 2] == ' ')
3229 // check for ** or &&
3230 if (prNum + 1 < lineLength
3231 && (currentLine[prNum + 1] == '*' || currentLine[prNum + 1] == '&'))
3234 // check space after
3235 if (prNum + 1 <= lineLength
3236 && currentLine[prNum + 1] != ' ')
3239 // check no space after that
3240 if (prNum + 2 < lineLength
3241 && currentLine[prNum + 2] == ' ')
3248 * Check if a word is a pointer or reference variable type.
3250 * @return whether word is a pointer or reference variable.
3252 bool ASFormatter::isPointerOrReferenceVariable(const string& word) const
3254 return (word == "char"
3257 || (word.length() >= 6 // check end of word for _t
3258 && word.compare(word.length() - 2, 2, "_t") == 0)
3264 * check if the currently reached '+' or '-' character is a unary operator
3265 * this method takes for granted that the current character
3268 * @return whether the current '+' or '-' is a unary operator.
3270 bool ASFormatter::isUnaryOperator() const
3272 assert(currentChar == '+' || currentChar == '-');
3274 return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar))
3275 && previousCommandChar != '.'
3276 && previousCommandChar != '\"'
3277 && previousCommandChar != '\''
3278 && previousCommandChar != ')'
3279 && previousCommandChar != ']');
3283 * check if the currently reached comment is in a 'switch' statement
3285 * @return whether the current '+' or '-' is in an exponent.
3287 bool ASFormatter::isInSwitchStatement() const
3289 assert(isInLineComment || isInComment);
3290 if (!preBraceHeaderStack->empty())
3291 for (size_t i = 1; i < preBraceHeaderStack->size(); i++)
3292 if (preBraceHeaderStack->at(i) == &AS_SWITCH)
3298 * check if the currently reached '+' or '-' character is
3299 * part of an exponent, i.e. 0.2E-5.
3301 * @return whether the current '+' or '-' is in an exponent.
3303 bool ASFormatter::isInExponent() const
3305 assert(currentChar == '+' || currentChar == '-');
3309 char prevPrevFormattedChar = currentLine[charNum - 2];
3310 char prevFormattedChar = currentLine[charNum - 1];
3311 return ((prevFormattedChar == 'e' || prevFormattedChar == 'E')
3312 && (prevPrevFormattedChar == '.' || isDigit(prevPrevFormattedChar)));
3318 * check if an array brace should NOT have an in-statement indent
3320 * @return the array is non in-statement
3322 bool ASFormatter::isNonInStatementArrayBrace() const
3324 bool returnVal = false;
3325 char nextChar = peekNextChar();
3326 // if this opening brace begins the line there will be no inStatement indent
3327 if (currentLineBeginsWithBrace
3328 && charNum == (int) currentLineFirstBraceNum
3331 // if an opening brace ends the line there will be no inStatement indent
3332 if (isWhiteSpace(nextChar)
3333 || isBeforeAnyLineEndComment(charNum)
3337 // Java "new Type [] {...}" IS an inStatement indent
3338 if (isJavaStyle() && previousNonWSChar == ']')
3345 * check if a one-line block has been reached,
3346 * i.e. if the currently reached '{' character is closed
3347 * with a complimentary '}' elsewhere on the current line,
3349 * @return 0 = one-line block has not been reached.
3350 * 1 = one-line block has been reached.
3351 * 2 = one-line block has been reached and is followed by a comma.
3352 * 3 = one-line block has been reached and is an empty block.
3354 int ASFormatter::isOneLineBlockReached(const string& line, int startChar) const
3356 assert(line[startChar] == '{');
3358 bool isInComment_ = false;
3359 bool isInQuote_ = false;
3360 bool hasText = false;
3362 int lineLength = line.length();
3363 char quoteChar_ = ' ';
3367 for (int i = startChar; i < lineLength; ++i)
3373 if (line.compare(i, 2, "*/") == 0)
3375 isInComment_ = false;
3389 if (ch == quoteChar_)
3395 || (ch == '\'' && !isDigitSeparator(line, i)))
3402 if (line.compare(i, 2, "//") == 0)
3405 if (line.compare(i, 2, "/*") == 0)
3407 isInComment_ = true;
3420 if (braceCount == 0)
3422 // is this an array?
3423 if (parenStack->back() == 0 && prevCh != '}')
3425 size_t peekNum = line.find_first_not_of(" \t", i + 1);
3426 if (peekNum != string::npos && line[peekNum] == ',')
3430 return 3; // is an empty block
3436 if (!isWhiteSpace(ch))
3447 * peek at the next word to determine if it is a C# non-paren header.
3448 * will look ahead in the input file if necessary.
3450 * @param startChar position on currentLine to start the search
3451 * @return true if the next word is get or set.
3453 bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const
3455 // look ahead to find the next non-comment text
3456 string nextText = peekNextText(currentLine.substr(startChar));
3457 if (nextText.length() == 0)
3459 if (nextText[0] == '[')
3461 if (!isCharPotentialHeader(nextText, 0))
3463 if (findKeyword(nextText, 0, AS_GET) || findKeyword(nextText, 0, AS_SET)
3464 || findKeyword(nextText, 0, AS_ADD) || findKeyword(nextText, 0, AS_REMOVE))
3470 * peek at the next char to determine if it is an opening brace.
3471 * will look ahead in the input file if necessary.
3472 * this determines a java static constructor.
3474 * @param startChar position on currentLine to start the search
3475 * @return true if the next word is an opening brace.
3477 bool ASFormatter::isNextCharOpeningBrace(int startChar) const
3479 bool retVal = false;
3480 string nextText = peekNextText(currentLine.substr(startChar));
3481 if (nextText.length() > 0
3482 && nextText.compare(0, 1, "{") == 0)
3488 * Check if operator and, pointer, and reference padding is disabled.
3489 * Disabling is done thru a NOPAD tag in an ending comment.
3491 * @return true if the formatting on this line is disabled.
3493 bool ASFormatter::isOperatorPaddingDisabled() const
3495 size_t commentStart = currentLine.find("//", charNum);
3496 if (commentStart == string::npos)
3498 commentStart = currentLine.find("/*", charNum);
3499 // comment must end on this line
3500 if (commentStart != string::npos)
3502 size_t commentEnd = currentLine.find("*/", commentStart + 2);
3503 if (commentEnd == string::npos)
3504 commentStart = string::npos;
3507 if (commentStart == string::npos)
3509 size_t noPadStart = currentLine.find("*NOPAD*", commentStart);
3510 if (noPadStart == string::npos)
3516 * Determine if an opening array-type brace should have a leading space pad.
3517 * This is to identify C++11 uniform initializers.
3519 bool ASFormatter::isUniformInitializerBrace() const
3521 if (isCStyle() && !isInEnum && !isImmediatelyPostPreprocessor)
3523 if (isInClassInitializer
3524 || isLegalNameChar(previousNonWSChar))
3531 * Determine if there is a following statement on the current line.
3533 bool ASFormatter::isMultiStatementLine() const
3535 assert((isImmediatelyPostHeader || foundClosingHeader));
3536 bool isInComment_ = false;
3537 bool isInQuote_ = false;
3539 int parenCount_ = 0;
3540 int braceCount_ = 0;
3542 for (size_t i = 0; i < currentLine.length(); i++)
3546 if (currentLine.compare(i, 2, "*/") == 0)
3548 isInComment_ = false;
3552 if (currentLine.compare(i, 2, "/*") == 0)
3554 isInComment_ = true;
3557 if (currentLine.compare(i, 2, "//") == 0)
3561 if (currentLine[i] == '"' || currentLine[i] == '\'')
3565 if (currentLine[i] == '"' || currentLine[i] == '\'')
3570 if (currentLine[i] == '(')
3575 if (currentLine[i] == ')')
3580 if (parenCount_ > 0)
3582 if (currentLine[i] == '{')
3586 if (currentLine[i] == '}')
3590 if (braceCount_ > 0)
3592 if (currentLine[i] == ';')
3604 * get the next non-whitespace substring on following lines, bypassing all comments.
3606 * @param firstLine the first line to check
3607 * @return the next non-whitespace substring.
3609 string ASFormatter::peekNextText(const string& firstLine,
3610 bool endOnEmptyLine /*false*/,
3611 shared_ptr<ASPeekStream> streamArg /*nullptr*/) const
3613 bool isFirstLine = true;
3614 string nextLine_ = firstLine;
3615 size_t firstChar = string::npos;
3616 shared_ptr<ASPeekStream> stream = streamArg;
3617 if (stream == nullptr) // Borland may need == 0
3618 stream = make_shared<ASPeekStream>(sourceIterator);
3620 // find the first non-blank text, bypassing all comments.
3621 bool isInComment_ = false;
3622 while (stream->hasMoreLines() || isFirstLine)
3625 isFirstLine = false;
3627 nextLine_ = stream->peekNextLine();
3629 firstChar = nextLine_.find_first_not_of(" \t");
3630 if (firstChar == string::npos)
3632 if (endOnEmptyLine && !isInComment_)
3637 if (nextLine_.compare(firstChar, 2, "/*") == 0)
3640 isInComment_ = true;
3645 firstChar = nextLine_.find("*/", firstChar);
3646 if (firstChar == string::npos)
3649 isInComment_ = false;
3650 firstChar = nextLine_.find_first_not_of(" \t", firstChar);
3651 if (firstChar == string::npos)
3655 if (nextLine_.compare(firstChar, 2, "//") == 0)
3658 // found the next text
3662 if (firstChar == string::npos)
3665 nextLine_ = nextLine_.substr(firstChar);
3670 * adjust comment position because of adding or deleting spaces
3671 * the spaces are added or deleted to formattedLine
3672 * spacePadNum contains the adjustment
3674 void ASFormatter::adjustComments()
3676 assert(spacePadNum != 0);
3677 assert(isSequenceReached("//") || isSequenceReached("/*"));
3679 // block comment must be closed on this line with nothing after it
3680 if (isSequenceReached("/*"))
3682 size_t endNum = currentLine.find("*/", charNum + 2);
3683 if (endNum == string::npos)
3685 if (currentLine.find_first_not_of(" \t", endNum + 2) != string::npos)
3689 size_t len = formattedLine.length();
3690 // don't adjust a tab
3691 if (formattedLine[len - 1] == '\t')
3693 // if spaces were removed, need to add spaces before the comment
3694 if (spacePadNum < 0)
3696 int adjust = -spacePadNum; // make the number positive
3697 formattedLine.append(adjust, ' ');
3699 // if spaces were added, need to delete extra spaces before the comment
3700 // if cannot be done put the comment one space after the last text
3701 else if (spacePadNum > 0)
3703 int adjust = spacePadNum;
3704 size_t lastText = formattedLine.find_last_not_of(' ');
3705 if (lastText != string::npos
3706 && lastText < len - adjust - 1)
3707 formattedLine.resize(len - adjust);
3708 else if (len > lastText + 2)
3709 formattedLine.resize(lastText + 2);
3710 else if (len < lastText + 2)
3711 formattedLine.append(len - lastText, ' ');
3716 * append the current brace inside the end of line comments
3717 * currentChar contains the brace, it will be appended to formattedLine
3718 * formattedLineCommentNum is the comment location on formattedLine
3720 void ASFormatter::appendCharInsideComments()
3722 if (formattedLineCommentNum == string::npos // does the comment start on the previous line?
3723 || formattedLineCommentNum == 0)
3725 appendCurrentChar(); // don't attach
3728 assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0
3729 || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);
3731 // find the previous non space char
3732 size_t end = formattedLineCommentNum;
3733 size_t beg = formattedLine.find_last_not_of(" \t", end - 1);
3734 if (beg == string::npos)
3736 appendCurrentChar(); // don't attach
3742 if (end - beg < 3) // is there room to insert?
3743 formattedLine.insert(beg, 3 - end + beg, ' ');
3744 if (formattedLine[beg] == '\t') // don't pad with a tab
3745 formattedLine.insert(beg, 1, ' ');
3746 formattedLine[beg + 1] = currentChar;
3747 testForTimeToSplitFormattedLine();
3749 if (isBeforeComment())
3751 else if (isCharImmediatelyPostLineComment)
3752 shouldBreakLineAtNextChar = true;
3756 * add or remove space padding to operators
3757 * the operators and necessary padding will be appended to formattedLine
3758 * the calling function should have a continue statement after calling this method
3760 * @param newOperator the operator to be padded
3762 void ASFormatter::padOperators(const string* newOperator)
3764 assert(shouldPadOperators);
3765 assert(newOperator != nullptr);
3767 char nextNonWSChar = ASBase::peekNextChar(currentLine, charNum);
3768 bool shouldPad = (newOperator != &AS_SCOPE_RESOLUTION
3769 && newOperator != &AS_PLUS_PLUS
3770 && newOperator != &AS_MINUS_MINUS
3771 && newOperator != &AS_NOT
3772 && newOperator != &AS_BIT_NOT
3773 && newOperator != &AS_ARROW
3774 && !(newOperator == &AS_COLON && !foundQuestionMark // objC methods
3775 && (isInObjCMethodDefinition || isInObjCInterface
3776 || isInObjCSelector || squareBracketCount != 0))
3777 && !(newOperator == &AS_MINUS && isInExponent())
3778 && !(newOperator == &AS_PLUS && isInExponent())
3779 && !((newOperator == &AS_PLUS || newOperator == &AS_MINUS) // check for unary plus or minus
3780 && (previousNonWSChar == '('
3781 || previousNonWSChar == '['
3782 || previousNonWSChar == '='
3783 || previousNonWSChar == ','
3784 || previousNonWSChar == ':'
3785 || previousNonWSChar == '{'))
3786 //? // commented out in release 2.05.1 - doesn't seem to do anything???
3787 //x && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND || newOperator == &AS_AND)
3788 //x && isPointerOrReference())
3789 && !(newOperator == &AS_MULT
3790 && (previousNonWSChar == '.'
3791 || previousNonWSChar == '>')) // check for ->
3792 && !(newOperator == &AS_MULT && peekNextChar() == '>')
3793 && !((isInTemplate || isImmediatelyPostTemplate)
3794 && (newOperator == &AS_LS || newOperator == &AS_GR))
3795 && !(newOperator == &AS_GCC_MIN_ASSIGN
3796 && ASBase::peekNextChar(currentLine, charNum + 1) == '>')
3797 && !(newOperator == &AS_GR && previousNonWSChar == '?')
3798 && !(newOperator == &AS_QUESTION // check for Java wildcard
3800 && (previousNonWSChar == '<'
3801 || nextNonWSChar == '>'
3802 || nextNonWSChar == '.'))
3803 && !(newOperator == &AS_QUESTION // check for C# null conditional operator
3805 && (nextNonWSChar == '.'
3806 || nextNonWSChar == '['))
3807 && !isCharImmediatelyPostOperator
3814 // pad before operator
3816 && !(newOperator == &AS_COLON
3817 && (!foundQuestionMark && !isInEnum) && currentHeader != &AS_FOR)
3818 && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
3819 && currentLine.find(':', charNum + 1) == string::npos)
3822 appendOperator(*newOperator);
3823 goForward(newOperator->length() - 1);
3825 currentChar = (*newOperator)[newOperator->length() - 1];
3826 // pad after operator
3827 // but do not pad after a '-' that is a unary-minus.
3829 && !isBeforeAnyComment()
3830 && !(newOperator == &AS_PLUS && isUnaryOperator())
3831 && !(newOperator == &AS_MINUS && isUnaryOperator())
3832 && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0)
3833 && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0)
3834 && !(peekNextChar() == ',')
3835 && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
3836 && peekNextChar() == '[')
3842 * format pointer or reference
3843 * currentChar contains the pointer or reference
3844 * the symbol and necessary padding will be appended to formattedLine
3845 * the calling function should have a continue statement after calling this method
3847 * NOTE: Do NOT use appendCurrentChar() in this method. The line should not be
3848 * broken once the calculation starts.
3850 void ASFormatter::formatPointerOrReference()
3852 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3853 assert(!isJavaStyle());
3855 int pa = pointerAlignment;
3856 int ra = referenceAlignment;
3857 int itemAlignment = (currentChar == '*' || currentChar == '^') ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
3859 // check for ** and &&
3861 char peekedChar = peekNextChar();
3862 if ((currentChar == '*' && peekedChar == '*')
3863 || (currentChar == '&' && peekedChar == '&'))
3866 size_t nextChar = currentLine.find_first_not_of(" \t", charNum + 2);
3867 if (nextChar == string::npos)
3870 peekedChar = currentLine[nextChar];
3873 if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',')
3875 formatPointerOrReferenceCast();
3879 // check for a padded space and remove it
3881 && !isWhiteSpace(currentLine[charNum - 1])
3882 && formattedLine.length() > 0
3883 && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
3885 formattedLine.erase(formattedLine.length() - 1);
3889 if (itemAlignment == PTR_ALIGN_TYPE)
3891 formatPointerOrReferenceToType();
3893 else if (itemAlignment == PTR_ALIGN_MIDDLE)
3895 formatPointerOrReferenceToMiddle();
3897 else if (itemAlignment == PTR_ALIGN_NAME)
3899 formatPointerOrReferenceToName();
3901 else // pointerAlignment == PTR_ALIGN_NONE
3903 formattedLine.append(ptrLength, currentChar);
3905 goForward(ptrLength - 1);
3910 * format pointer or reference with align to type
3912 void ASFormatter::formatPointerOrReferenceToType()
3914 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3915 assert(!isJavaStyle());
3917 // do this before bumping charNum
3918 bool isOldPRCentered = isPointerOrReferenceCentered();
3920 size_t prevCh = formattedLine.find_last_not_of(" \t");
3921 if (prevCh == string::npos)
3923 if (formattedLine.length() == 0 || prevCh == formattedLine.length() - 1)
3924 formattedLine.append(1, currentChar);
3927 // exchange * or & with character following the type
3928 // this may not work every time with a tab character
3929 string charSave = formattedLine.substr(prevCh + 1, 1);
3930 formattedLine[prevCh + 1] = currentChar;
3931 formattedLine.append(charSave);
3933 if (isSequenceReached("**") || isSequenceReached("&&"))
3935 if (formattedLine.length() == 1)
3936 formattedLine.append(1, currentChar);
3938 formattedLine.insert(prevCh + 2, 1, currentChar);
3941 // if no space after then add one
3942 if (charNum < (int) currentLine.length() - 1
3943 && !isWhiteSpace(currentLine[charNum + 1])
3944 && currentLine[charNum + 1] != ')')
3946 // if old pointer or reference is centered, remove a space
3948 && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
3950 formattedLine.erase(formattedLine.length() - 1, 1);
3953 // update the formattedLine split point
3954 if (maxCodeLength != string::npos)
3956 size_t index = formattedLine.length() - 1;
3957 if (isWhiteSpace(formattedLine[index]))
3959 updateFormattedLineSplitPointsPointerOrReference(index);
3960 testForTimeToSplitFormattedLine();
3966 * format pointer or reference with align in the middle
3968 void ASFormatter::formatPointerOrReferenceToMiddle()
3970 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3971 assert(!isJavaStyle());
3973 // compute current whitespace before
3974 size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1);
3975 if (wsBefore == string::npos)
3978 wsBefore = charNum - wsBefore - 1;
3979 string sequenceToInsert(1, currentChar);
3980 if (isSequenceReached("**"))
3982 sequenceToInsert = "**";
3985 else if (isSequenceReached("&&"))
3987 sequenceToInsert = "&&";
3990 // if reference to a pointer check for conflicting alignment
3991 else if (currentChar == '*' && peekNextChar() == '&'
3992 && (referenceAlignment == REF_ALIGN_TYPE
3993 || referenceAlignment == REF_ALIGN_MIDDLE
3994 || referenceAlignment == REF_SAME_AS_PTR))
3996 sequenceToInsert = "*&";
3998 for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++)
4001 // if a comment follows don't align, just space pad
4002 if (isBeforeAnyComment())
4005 formattedLine.append(sequenceToInsert);
4009 // do this before goForward()
4010 bool isAfterScopeResolution = previousNonWSChar == ':';
4011 size_t charNumSave = charNum;
4012 // if this is the last thing on the line
4013 if (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos)
4015 if (wsBefore == 0 && !isAfterScopeResolution)
4016 formattedLine.append(1, ' ');
4017 formattedLine.append(sequenceToInsert);
4020 // goForward() to convert tabs to spaces, if necessary,
4021 // and move following characters to preceding characters
4022 // this may not work every time with tab characters
4023 for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
4026 if (formattedLine.length() > 0)
4027 formattedLine.append(1, currentLine[i]);
4031 // find space padding after
4032 size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1);
4033 if (wsAfter == string::npos || isBeforeAnyComment())
4036 wsAfter = wsAfter - charNumSave - 1;
4037 // don't pad before scope resolution operator, but pad after
4038 if (isAfterScopeResolution)
4040 size_t lastText = formattedLine.find_last_not_of(" \t");
4041 formattedLine.insert(lastText + 1, sequenceToInsert);
4044 else if (formattedLine.length() > 0)
4046 // whitespace should be at least 2 chars to center
4047 if (wsBefore + wsAfter < 2)
4049 size_t charsToAppend = (2 - (wsBefore + wsAfter));
4050 formattedLine.append(charsToAppend, ' ');
4051 spacePadNum += charsToAppend;
4057 // insert the pointer or reference char
4058 size_t padAfter = (wsBefore + wsAfter) / 2;
4059 size_t index = formattedLine.length() - padAfter;
4060 formattedLine.insert(index, sequenceToInsert);
4062 else // formattedLine.length() == 0
4064 formattedLine.append(sequenceToInsert);
4067 formattedLine.append(wsAfter, ' ');
4068 spacePadNum += wsAfter;
4070 // update the formattedLine split point after the pointer
4071 if (maxCodeLength != string::npos && formattedLine.length() > 0)
4073 size_t index = formattedLine.find_last_not_of(" \t");
4074 if (index != string::npos && (index < formattedLine.length() - 1))
4077 updateFormattedLineSplitPointsPointerOrReference(index);
4078 testForTimeToSplitFormattedLine();
4084 * format pointer or reference with align to name
4086 void ASFormatter::formatPointerOrReferenceToName()
4088 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4089 assert(!isJavaStyle());
4091 // do this before bumping charNum
4092 bool isOldPRCentered = isPointerOrReferenceCentered();
4094 size_t startNum = formattedLine.find_last_not_of(" \t");
4095 if (startNum == string::npos)
4097 string sequenceToInsert(1, currentChar);
4098 if (isSequenceReached("**"))
4100 sequenceToInsert = "**";
4103 else if (isSequenceReached("&&"))
4105 sequenceToInsert = "&&";
4108 // if reference to a pointer align both to name
4109 else if (currentChar == '*' && peekNextChar() == '&')
4111 sequenceToInsert = "*&";
4113 for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++)
4116 char peekedChar = peekNextChar();
4117 bool isAfterScopeResolution = previousNonWSChar == ':'; // check for ::
4118 // if this is not the last thing on the line
4119 if (!isBeforeAnyComment()
4120 && (int) currentLine.find_first_not_of(" \t", charNum + 1) > charNum)
4122 // goForward() to convert tabs to spaces, if necessary,
4123 // and move following characters to preceding characters
4124 // this may not work every time with tab characters
4125 for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
4127 // if a padded paren follows don't move
4128 if (shouldPadParensOutside && peekedChar == '(' && !isOldPRCentered)
4130 // empty parens don't count
4131 size_t start = currentLine.find_first_not_of("( \t", charNum + 1);
4132 if (start != string::npos && currentLine[start] != ')')
4136 if (formattedLine.length() > 0)
4137 formattedLine.append(1, currentLine[i]);
4142 // don't pad before scope resolution operator
4143 if (isAfterScopeResolution)
4145 size_t lastText = formattedLine.find_last_not_of(" \t");
4146 if (lastText != string::npos && lastText + 1 < formattedLine.length())
4147 formattedLine.erase(lastText + 1);
4149 // if no space before * then add one
4150 else if (formattedLine.length() > 0
4151 && (formattedLine.length() <= startNum + 1
4152 || !isWhiteSpace(formattedLine[startNum + 1])))
4154 formattedLine.insert(startNum + 1, 1, ' ');
4157 appendSequence(sequenceToInsert, false);
4158 // if old pointer or reference is centered, remove a space
4160 && formattedLine.length() > startNum + 1
4161 && isWhiteSpace(formattedLine[startNum + 1])
4162 && !isBeforeAnyComment())
4164 formattedLine.erase(startNum + 1, 1);
4167 // don't convert to *= or &=
4168 if (peekedChar == '=')
4171 // if more than one space before, delete one
4172 if (formattedLine.length() > startNum
4173 && isWhiteSpace(formattedLine[startNum + 1])
4174 && isWhiteSpace(formattedLine[startNum + 2]))
4176 formattedLine.erase(startNum + 1, 1);
4180 // update the formattedLine split point
4181 if (maxCodeLength != string::npos)
4183 size_t index = formattedLine.find_last_of(" \t");
4184 if (index != string::npos
4185 && index < formattedLine.length() - 1
4186 && (formattedLine[index + 1] == '*'
4187 || formattedLine[index + 1] == '&'
4188 || formattedLine[index + 1] == '^'))
4190 updateFormattedLineSplitPointsPointerOrReference(index);
4191 testForTimeToSplitFormattedLine();
4197 * format pointer or reference cast
4198 * currentChar contains the pointer or reference
4199 * NOTE: the pointers and references in function definitions
4200 * are processed as a cast (e.g. void foo(void*, void*))
4201 * is processed here.
4203 void ASFormatter::formatPointerOrReferenceCast()
4205 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4206 assert(!isJavaStyle());
4208 int pa = pointerAlignment;
4209 int ra = referenceAlignment;
4210 int itemAlignment = (currentChar == '*' || currentChar == '^') ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
4212 string sequenceToInsert(1, currentChar);
4213 if (isSequenceReached("**") || isSequenceReached("&&"))
4216 sequenceToInsert.append(1, currentLine[charNum]);
4218 if (itemAlignment == PTR_ALIGN_NONE)
4220 appendSequence(sequenceToInsert, false);
4223 // remove preceding whitespace
4225 size_t prevNum = formattedLine.find_last_not_of(" \t");
4226 if (prevNum != string::npos)
4228 prevCh = formattedLine[prevNum];
4229 if (prevNum + 1 < formattedLine.length()
4230 && isWhiteSpace(formattedLine[prevNum + 1])
4233 spacePadNum -= (formattedLine.length() - 1 - prevNum);
4234 formattedLine.erase(prevNum + 1);
4237 bool isAfterScopeResolution = previousNonWSChar == ':';
4238 if ((itemAlignment == PTR_ALIGN_MIDDLE || itemAlignment == PTR_ALIGN_NAME)
4239 && !isAfterScopeResolution && prevCh != '(')
4242 // in this case appendSpacePad may or may not update the split point
4243 if (maxCodeLength != string::npos && formattedLine.length() > 0)
4244 updateFormattedLineSplitPointsPointerOrReference(formattedLine.length() - 1);
4245 appendSequence(sequenceToInsert, false);
4248 appendSequence(sequenceToInsert, false);
4252 * add or remove space padding to parens
4253 * currentChar contains the paren
4254 * the parens and necessary padding will be appended to formattedLine
4255 * the calling function should have a continue statement after calling this method
4257 void ASFormatter::padParens()
4259 assert(currentChar == '(' || currentChar == ')');
4260 assert(shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen);
4262 int spacesOutsideToDelete = 0;
4263 int spacesInsideToDelete = 0;
4265 if (currentChar == '(')
4267 spacesOutsideToDelete = formattedLine.length() - 1;
4268 spacesInsideToDelete = 0;
4270 // compute spaces outside the opening paren to delete
4271 if (shouldUnPadParens)
4273 char lastChar = ' ';
4274 bool prevIsParenHeader = false;
4275 size_t i = formattedLine.find_last_not_of(" \t");
4276 if (i != string::npos)
4278 // if last char is a brace the previous whitespace is an indent
4279 if (formattedLine[i] == '{')
4280 spacesOutsideToDelete = 0;
4281 else if (isCharImmediatelyPostPointerOrReference)
4282 spacesOutsideToDelete = 0;
4285 spacesOutsideToDelete -= i;
4286 lastChar = formattedLine[i];
4287 // if previous word is a header, it will be a paren header
4288 string prevWord = getPreviousWord(formattedLine, formattedLine.length());
4289 const string* prevWordH = nullptr;
4291 && prevWord.length() > 0
4292 && isCharPotentialHeader(prevWord, 0))
4293 prevWordH = ASBase::findHeader(prevWord, 0, headers);
4294 if (prevWordH != nullptr)
4295 prevIsParenHeader = true;
4296 else if (prevWord == AS_RETURN) // don't unpad
4297 prevIsParenHeader = true;
4298 else if ((prevWord == AS_NEW || prevWord == AS_DELETE)
4299 && shouldPadHeader) // don't unpad
4300 prevIsParenHeader = true;
4301 else if (isCStyle() && prevWord == AS_THROW && shouldPadHeader) // don't unpad
4302 prevIsParenHeader = true;
4303 else if (prevWord == "and" || prevWord == "or" || prevWord == "in") // don't unpad
4304 prevIsParenHeader = true;
4305 // don't unpad variables
4306 else if (prevWord == "bool"
4307 || prevWord == "int"
4308 || prevWord == "void"
4309 || prevWord == "void*"
4310 || prevWord == "char"
4311 || prevWord == "char*"
4312 || prevWord == "long"
4313 || prevWord == "double"
4314 || prevWord == "float"
4315 || (prevWord.length() >= 4 // check end of word for _t
4316 && prevWord.compare(prevWord.length() - 2, 2, "_t") == 0)
4317 || prevWord == "Int32"
4318 || prevWord == "UInt32"
4319 || prevWord == "Int64"
4320 || prevWord == "UInt64"
4321 || prevWord == "BOOL"
4322 || prevWord == "DWORD"
4323 || prevWord == "HWND"
4324 || prevWord == "INT"
4325 || prevWord == "LPSTR"
4326 || prevWord == "VOID"
4327 || prevWord == "LPVOID"
4330 prevIsParenHeader = true;
4334 // do not unpad operators, but leave them if already padded
4335 if (shouldPadParensOutside || prevIsParenHeader)
4336 spacesOutsideToDelete--;
4337 else if (lastChar == '|' // check for ||
4338 || lastChar == '&' // check for &&
4340 || (lastChar == '(' && shouldPadParensInside)
4341 || (lastChar == '>' && !foundCastOperator)
4354 spacesOutsideToDelete--;
4356 if (spacesOutsideToDelete > 0)
4358 formattedLine.erase(i + 1, spacesOutsideToDelete);
4359 spacePadNum -= spacesOutsideToDelete;
4363 // pad open paren outside
4364 char peekedCharOutside = peekNextChar();
4365 if (shouldPadFirstParen && previousChar != '(' && peekedCharOutside != ')')
4367 else if (shouldPadParensOutside)
4369 if (!(currentChar == '(' && peekedCharOutside == ')'))
4373 appendCurrentChar();
4375 // unpad open paren inside
4376 if (shouldUnPadParens)
4378 size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
4379 if (j != string::npos)
4380 spacesInsideToDelete = j - charNum - 1;
4381 if (shouldPadParensInside)
4382 spacesInsideToDelete--;
4383 if (spacesInsideToDelete > 0)
4385 currentLine.erase(charNum + 1, spacesInsideToDelete);
4386 spacePadNum -= spacesInsideToDelete;
4388 // convert tab to space if requested
4389 if (shouldConvertTabs
4390 && (int) currentLine.length() > charNum + 1
4391 && currentLine[charNum + 1] == '\t')
4392 currentLine[charNum + 1] = ' ';
4395 // pad open paren inside
4396 char peekedCharInside = peekNextChar();
4397 if (shouldPadParensInside)
4398 if (!(currentChar == '(' && peekedCharInside == ')'))
4401 else if (currentChar == ')')
4403 // unpad close paren inside
4404 if (shouldUnPadParens)
4406 spacesInsideToDelete = formattedLine.length();
4407 size_t i = formattedLine.find_last_not_of(" \t");
4408 if (i != string::npos)
4409 spacesInsideToDelete = formattedLine.length() - 1 - i;
4410 if (shouldPadParensInside)
4411 spacesInsideToDelete--;
4412 if (spacesInsideToDelete > 0)
4414 formattedLine.erase(i + 1, spacesInsideToDelete);
4415 spacePadNum -= spacesInsideToDelete;
4419 // pad close paren inside
4420 if (shouldPadParensInside)
4421 if (!(previousChar == '(' && currentChar == ')'))
4424 appendCurrentChar();
4426 // unpad close paren outside
4427 // close parens outside are left unchanged
4428 if (shouldUnPadParens)
4430 //spacesOutsideToDelete = 0;
4431 //size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
4432 //if (j != string::npos)
4433 // spacesOutsideToDelete = j - charNum - 1;
4434 //if (shouldPadParensOutside)
4435 // spacesOutsideToDelete--;
4437 //if (spacesOutsideToDelete > 0)
4439 // currentLine.erase(charNum + 1, spacesOutsideToDelete);
4440 // spacePadNum -= spacesOutsideToDelete;
4444 // pad close paren outside
4445 char peekedCharOutside = peekNextChar();
4446 if (shouldPadParensOutside)
4447 if (peekedCharOutside != ';'
4448 && peekedCharOutside != ','
4449 && peekedCharOutside != '.'
4450 && peekedCharOutside != '+' // check for ++
4451 && peekedCharOutside != '-' // check for --
4452 && peekedCharOutside != ']')
4458 * add or remove space padding to objective-c parens
4459 * these options have precedence over the padParens methods
4460 * the padParens method has already been called, this method adjusts
4462 void ASFormatter::padObjCMethodPrefix()
4464 assert(currentChar == '(' && isImmediatelyPostObjCMethodPrefix);
4465 assert(shouldPadMethodPrefix || shouldUnPadMethodPrefix);
4467 size_t prefix = formattedLine.find_first_of("+-");
4468 if (prefix == string::npos)
4470 size_t paren = formattedLine.find_first_of('(');
4471 if (paren == string::npos)
4473 int spaces = paren - prefix - 1;
4475 if (shouldPadMethodPrefix)
4479 formattedLine.insert(prefix + 1, 1, ' ');
4482 else if (spaces > 1)
4484 formattedLine.erase(prefix + 1, spaces - 1);
4485 spacePadNum -= spaces - 1;
4488 // this option will be ignored if used with pad-method-prefix
4489 else if (shouldUnPadMethodPrefix)
4493 formattedLine.erase(prefix + 1, spaces);
4494 spacePadNum -= spaces;
4500 * add or remove space padding to objective-c parens
4501 * these options have precedence over the padParens methods
4502 * the padParens method has already been called, this method adjusts
4504 void ASFormatter::padObjCReturnType()
4506 assert(currentChar == ')' && isInObjCReturnType);
4507 assert(shouldPadReturnType || shouldUnPadReturnType);
4509 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
4510 if (nextText == string::npos)
4512 int spaces = nextText - charNum - 1;
4514 if (shouldPadReturnType)
4518 // this will already be padded if pad-paren is used
4519 if (formattedLine[formattedLine.length() - 1] != ' ')
4521 formattedLine.append(" ");
4525 else if (spaces > 1)
4527 // do not use goForward here
4528 currentLine.erase(charNum + 1, spaces - 1);
4529 spacePadNum -= spaces - 1;
4532 // this option will be ignored if used with pad-return-type
4533 else if (shouldUnPadReturnType)
4535 // this will already be padded if pad-paren is used
4536 if (formattedLine[formattedLine.length() - 1] == ' ')
4538 spacePadNum -= formattedLine.length() - 1 - nextText;
4539 int lastText = formattedLine.find_last_not_of(" \t");
4540 formattedLine.resize(lastText + 1);
4544 // do not use goForward here
4545 currentLine.erase(charNum + 1, spaces);
4546 spacePadNum -= spaces;
4552 * add or remove space padding to objective-c parens
4553 * these options have precedence over the padParens methods
4554 * the padParens method has already been called, this method adjusts
4556 void ASFormatter::padObjCParamType()
4558 assert((currentChar == '(' || currentChar == ')') && isInObjCMethodDefinition);
4559 assert(!isImmediatelyPostObjCMethodPrefix && !isInObjCReturnType);
4560 assert(shouldPadParamType || shouldUnPadParamType);
4562 if (currentChar == '(')
4564 // open paren has already been attached to formattedLine by padParen
4565 size_t paramOpen = formattedLine.rfind('(');
4566 assert(paramOpen != string::npos);
4567 size_t prevText = formattedLine.find_last_not_of(" \t", paramOpen - 1);
4568 if (prevText == string::npos)
4570 int spaces = paramOpen - prevText - 1;
4572 if (shouldPadParamType
4573 || objCColonPadMode == COLON_PAD_ALL
4574 || objCColonPadMode == COLON_PAD_AFTER)
4578 formattedLine.insert(paramOpen, 1, ' ');
4583 formattedLine.erase(prevText + 1, spaces - 1);
4584 spacePadNum -= spaces - 1;
4587 // this option will be ignored if used with pad-param-type
4588 else if (shouldUnPadParamType
4589 || objCColonPadMode == COLON_PAD_NONE
4590 || objCColonPadMode == COLON_PAD_BEFORE)
4594 formattedLine.erase(prevText + 1, spaces);
4595 spacePadNum -= spaces;
4599 else if (currentChar == ')')
4601 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
4602 if (nextText == string::npos)
4604 int spaces = nextText - charNum - 1;
4606 if (shouldPadParamType)
4610 // this will already be padded if pad-paren is used
4611 if (formattedLine[formattedLine.length() - 1] != ' ')
4613 formattedLine.append(" ");
4617 else if (spaces > 1)
4619 // do not use goForward here
4620 currentLine.erase(charNum + 1, spaces - 1);
4621 spacePadNum -= spaces - 1;
4624 // this option will be ignored if used with pad-param-type
4625 else if (shouldUnPadParamType)
4627 // this will already be padded if pad-paren is used
4628 if (formattedLine[formattedLine.length() - 1] == ' ')
4631 int lastText = formattedLine.find_last_not_of(" \t");
4632 formattedLine.resize(lastText + 1);
4636 // do not use goForward here
4637 currentLine.erase(charNum + 1, spaces);
4638 spacePadNum -= spaces;
4645 * format opening brace as attached or broken
4646 * currentChar contains the brace
4647 * the braces will be appended to the current formattedLine or a new formattedLine as necessary
4648 * the calling function should have a continue statement after calling this method
4650 * @param braceType the type of brace to be formatted.
4652 void ASFormatter::formatOpeningBrace(BraceType braceType)
4654 assert(!isBraceType(braceType, ARRAY_TYPE));
4655 assert(currentChar == '{');
4657 parenStack->emplace_back(0);
4659 bool breakBrace = isCurrentBraceBroken();
4663 if (isBeforeAnyComment() && isOkToBreakBlock(braceType))
4665 // if comment is at line end leave the comment on this line
4666 if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
4668 currentChar = ' '; // remove brace from current line
4669 if (parenStack->size() > 1)
4670 parenStack->pop_back();
4671 currentLine[charNum] = currentChar;
4672 appendOpeningBrace = true; // append brace to following line
4674 // else put comment after the brace
4675 else if (!isBeforeMultipleLineEndComments(charNum))
4678 else if (!isBraceType(braceType, SINGLE_LINE_TYPE))
4680 formattedLine = rtrim(formattedLine);
4683 else if ((shouldBreakOneLineBlocks || isBraceType(braceType, BREAK_BLOCK_TYPE))
4684 && !isBraceType(braceType, EMPTY_BLOCK_TYPE))
4686 else if (!isInLineBreak)
4689 appendCurrentChar();
4691 // should a following comment break from the brace?
4692 // must break the line AFTER the brace
4693 if (isBeforeComment()
4694 && formattedLine.length() > 0
4695 && formattedLine[0] == '{'
4696 && isOkToBreakBlock(braceType)
4697 && (braceFormatMode == BREAK_MODE
4698 || braceFormatMode == LINUX_MODE))
4700 shouldBreakLineAtNextChar = true;
4703 else // attach brace
4705 // are there comments before the brace?
4706 if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
4708 if (isOkToBreakBlock(braceType)
4709 && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment) // don't attach if two comments on the line
4710 && !isImmediatelyPostPreprocessor
4711 // && peekNextChar() != '}' // don't attach { } // removed release 2.03
4712 && previousCommandChar != '{' // don't attach { {
4713 && previousCommandChar != '}' // don't attach } {
4714 && previousCommandChar != ';') // don't attach ; {
4716 appendCharInsideComments();
4720 appendCurrentChar(); // don't attach
4723 else if (previousCommandChar == '{'
4724 || (previousCommandChar == '}' && !isInClassInitializer)
4725 || previousCommandChar == ';') // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
4727 appendCurrentChar(); // don't attach
4731 // if a blank line precedes this don't attach
4732 if (isEmptyLine(formattedLine))
4733 appendCurrentChar(); // don't attach
4734 else if (isOkToBreakBlock(braceType)
4735 && !(isImmediatelyPostPreprocessor
4736 && currentLineBeginsWithBrace))
4738 if (!isBraceType(braceType, EMPTY_BLOCK_TYPE))
4741 appendCurrentChar(false); // OK to attach
4742 testForTimeToSplitFormattedLine(); // line length will have changed
4743 // should a following comment attach with the brace?
4744 // insert spaces to reposition the comment
4745 if (isBeforeComment()
4746 && !isBeforeMultipleLineEndComments(charNum)
4747 && (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace))
4749 shouldBreakLineAtNextChar = true;
4750 currentLine.insert(charNum + 1, charNum + 1, ' ');
4752 else if (!isBeforeAnyComment()) // added in release 2.03
4754 shouldBreakLineAtNextChar = true;
4759 if (currentLineBeginsWithBrace && charNum == (int) currentLineFirstBraceNum)
4762 appendCurrentChar(false); // attach
4763 shouldBreakLineAtNextChar = true;
4768 appendCurrentChar(); // don't attach
4776 appendCurrentChar(); // don't attach
4783 * format closing brace
4784 * currentChar contains the brace
4785 * the calling function should have a continue statement after calling this method
4787 * @param braceType the type of the opening brace for this closing brace.
4789 void ASFormatter::formatClosingBrace(BraceType braceType)
4791 assert(!isBraceType(braceType, ARRAY_TYPE));
4792 assert(currentChar == '}');
4794 // parenStack must contain one entry
4795 if (parenStack->size() > 1)
4796 parenStack->pop_back();
4798 // mark state of immediately after empty block
4799 // this state will be used for locating braces that appear immediately AFTER an empty block (e.g. '{} \n}').
4800 if (previousCommandChar == '{')
4801 isImmediatelyPostEmptyBlock = true;
4803 if (attachClosingBraceMode)
4805 // for now, namespaces and classes will be attached. Uncomment the lines below to break.
4806 if ((isEmptyLine(formattedLine) // if a blank line precedes this
4807 || isCharImmediatelyPostLineComment
4808 || isCharImmediatelyPostComment
4809 || (isImmediatelyPostPreprocessor && (int) currentLine.find_first_not_of(" \t") == charNum)
4810 // || (isBraceType(braceType, CLASS_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{')
4811 // || (isBraceType(braceType, NAMESPACE_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{')
4813 && (!isBraceType(braceType, SINGLE_LINE_TYPE) || isOkToBreakBlock(braceType)))
4816 appendCurrentChar(); // don't attach
4820 if (previousNonWSChar != '{'
4821 && (!isBraceType(braceType, SINGLE_LINE_TYPE)
4822 || isOkToBreakBlock(braceType)))
4824 appendCurrentChar(false); // attach
4827 else if (!isBraceType(braceType, EMPTY_BLOCK_TYPE)
4828 && (isBraceType(braceType, BREAK_BLOCK_TYPE)
4829 || isOkToBreakBlock(braceType)))
4832 appendCurrentChar();
4836 appendCurrentChar();
4839 // if a declaration follows a definition, space pad
4840 if (isLegalNameChar(peekNextChar()))
4843 if (shouldBreakBlocks
4844 && currentHeader != nullptr
4845 && !isHeaderInMultiStatementLine
4846 && parenStack->back() == 0)
4848 if (currentHeader == &AS_CASE || currentHeader == &AS_DEFAULT)
4850 // do not yet insert a line if "break" statement is outside the braces
4851 string nextText = peekNextText(currentLine.substr(charNum + 1));
4852 if (nextText.length() > 0
4853 && nextText.substr(0, 5) != "break")
4854 isAppendPostBlockEmptyLineRequested = true;
4857 isAppendPostBlockEmptyLineRequested = true;
4862 * format array braces as attached or broken
4863 * determine if the braces can have an inStatement indent
4864 * currentChar contains the brace
4865 * the braces will be appended to the current formattedLine or a new formattedLine as necessary
4866 * the calling function should have a continue statement after calling this method
4868 * @param braceType the type of brace to be formatted, must be an ARRAY_TYPE.
4869 * @param isOpeningArrayBrace indicates if this is the opening brace for the array block.
4871 void ASFormatter::formatArrayBraces(BraceType braceType, bool isOpeningArrayBrace)
4873 assert(isBraceType(braceType, ARRAY_TYPE));
4874 assert(currentChar == '{' || currentChar == '}');
4876 if (currentChar == '{')
4878 // is this the first opening brace in the array?
4879 if (isOpeningArrayBrace)
4881 if (braceFormatMode == ATTACH_MODE
4882 || braceFormatMode == LINUX_MODE)
4884 // break an enum if mozilla
4885 if (isBraceType(braceType, ENUM_TYPE)
4886 && formattingStyle == STYLE_MOZILLA)
4888 isInLineBreak = true;
4889 appendCurrentChar(); // don't attach
4891 // don't attach to a preprocessor directive or '\' line
4892 else if ((isImmediatelyPostPreprocessor
4893 || (formattedLine.length() > 0
4894 && formattedLine[formattedLine.length() - 1] == '\\'))
4895 && currentLineBeginsWithBrace)
4897 isInLineBreak = true;
4898 appendCurrentChar(); // don't attach
4900 else if (isCharImmediatelyPostComment)
4902 // TODO: attach brace to line-end comment
4903 appendCurrentChar(); // don't attach
4905 else if (isCharImmediatelyPostLineComment && !isBraceType(braceType, SINGLE_LINE_TYPE))
4907 appendCharInsideComments();
4911 // if a blank line precedes this don't attach
4912 if (isEmptyLine(formattedLine))
4913 appendCurrentChar(); // don't attach
4916 // if brace is broken or not an assignment
4917 if (currentLineBeginsWithBrace
4918 && !isBraceType(braceType, SINGLE_LINE_TYPE))
4921 appendCurrentChar(false); // OK to attach
4922 // TODO: debug the following line
4923 testForTimeToSplitFormattedLine(); // line length will have changed
4925 if (currentLineBeginsWithBrace
4926 && (int) currentLineFirstBraceNum == charNum)
4927 shouldBreakLineAtNextChar = true;
4931 if (previousNonWSChar != '(')
4933 // don't space pad C++11 uniform initialization
4934 if (!isBraceType(braceType, INIT_TYPE))
4937 appendCurrentChar();
4942 else if (braceFormatMode == BREAK_MODE)
4944 if (isWhiteSpace(peekNextChar()) && !isInVirginLine)
4946 else if (isBeforeAnyComment())
4948 // do not break unless comment is at line end
4949 if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
4951 currentChar = ' '; // remove brace from current line
4952 appendOpeningBrace = true; // append brace to following line
4955 if (!isInLineBreak && previousNonWSChar != '(')
4957 // don't space pad C++11 uniform initialization
4958 if (!isBraceType(braceType, INIT_TYPE))
4961 appendCurrentChar();
4963 if (currentLineBeginsWithBrace
4964 && (int) currentLineFirstBraceNum == charNum
4965 && !isBraceType(braceType, SINGLE_LINE_TYPE))
4966 shouldBreakLineAtNextChar = true;
4968 else if (braceFormatMode == RUN_IN_MODE)
4970 if (isWhiteSpace(peekNextChar()) && !isInVirginLine)
4972 else if (isBeforeAnyComment())
4974 // do not break unless comment is at line end
4975 if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
4977 currentChar = ' '; // remove brace from current line
4978 appendOpeningBrace = true; // append brace to following line
4981 if (!isInLineBreak && previousNonWSChar != '(')
4983 // don't space pad C++11 uniform initialization
4984 if (!isBraceType(braceType, INIT_TYPE))
4987 appendCurrentChar();
4989 else if (braceFormatMode == NONE_MODE)
4991 if (currentLineBeginsWithBrace
4992 && charNum == (int) currentLineFirstBraceNum)
4994 appendCurrentChar(); // don't attach
4998 if (previousNonWSChar != '(')
5000 // don't space pad C++11 uniform initialization
5001 if (!isBraceType(braceType, INIT_TYPE))
5004 appendCurrentChar(false); // OK to attach
5008 else // not the first opening brace
5010 if (braceFormatMode == RUN_IN_MODE)
5012 if (previousNonWSChar == '{'
5013 && braceTypeStack->size() > 2
5014 && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],
5018 else if (!isInLineBreak
5019 && !isWhiteSpace(peekNextChar())
5020 && previousNonWSChar == '{'
5021 && braceTypeStack->size() > 2
5022 && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],
5026 appendCurrentChar();
5029 else if (currentChar == '}')
5031 if (attachClosingBraceMode)
5033 if (isEmptyLine(formattedLine) // if a blank line precedes this
5034 || isImmediatelyPostPreprocessor
5035 || isCharImmediatelyPostLineComment
5036 || isCharImmediatelyPostComment)
5037 appendCurrentChar(); // don't attach
5041 appendCurrentChar(false); // attach
5046 // does this close the first opening brace in the array?
5047 // must check if the block is still a single line because of anonymous statements
5048 if (!isBraceType(braceType, INIT_TYPE)
5049 && (!isBraceType(braceType, SINGLE_LINE_TYPE)
5050 || formattedLine.find('{') == string::npos))
5052 appendCurrentChar();
5055 // if a declaration follows an enum definition, space pad
5056 char peekedChar = peekNextChar();
5057 if (isLegalNameChar(peekedChar)
5058 || peekedChar == '[')
5064 * determine if a run-in can be attached.
5065 * if it can insert the indents in formattedLine and reset the current line break.
5067 void ASFormatter::formatRunIn()
5069 assert(braceFormatMode == RUN_IN_MODE || braceFormatMode == NONE_MODE);
5071 // keep one line blocks returns true without indenting the run-in
5072 if (formattingStyle != STYLE_PICO
5073 && !isOkToBreakBlock(braceTypeStack->back()))
5076 // make sure the line begins with a brace
5077 size_t lastText = formattedLine.find_last_not_of(" \t");
5078 if (lastText == string::npos || formattedLine[lastText] != '{')
5081 // make sure the brace is broken
5082 if (formattedLine.find_first_not_of(" \t{") != string::npos)
5085 if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
5088 bool extraIndent = false;
5089 bool extraHalfIndent = false;
5090 isInLineBreak = true;
5092 // cannot attach a class modifier without indent-classes
5094 && isCharPotentialHeader(currentLine, charNum)
5095 && (isBraceType(braceTypeStack->back(), CLASS_TYPE)
5096 || (isBraceType(braceTypeStack->back(), STRUCT_TYPE)
5097 && isInIndentableStruct)))
5099 if (findKeyword(currentLine, charNum, AS_PUBLIC)
5100 || findKeyword(currentLine, charNum, AS_PRIVATE)
5101 || findKeyword(currentLine, charNum, AS_PROTECTED))
5103 if (getModifierIndent())
5104 extraHalfIndent = true;
5105 else if (!getClassIndent())
5108 else if (getClassIndent())
5112 // cannot attach a 'case' statement without indent-switches
5113 if (!getSwitchIndent()
5114 && isCharPotentialHeader(currentLine, charNum)
5115 && (findKeyword(currentLine, charNum, AS_CASE)
5116 || findKeyword(currentLine, charNum, AS_DEFAULT)))
5119 // extra indent for switch statements
5120 if (getSwitchIndent()
5121 && !preBraceHeaderStack->empty()
5122 && preBraceHeaderStack->back() == &AS_SWITCH
5123 && ((isLegalNameChar(currentChar)
5124 && !findKeyword(currentLine, charNum, AS_CASE))))
5127 isInLineBreak = false;
5128 // remove for extra whitespace
5129 if (formattedLine.length() > lastText + 1
5130 && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos)
5131 formattedLine.erase(lastText + 1);
5133 if (extraHalfIndent)
5135 int indentLength_ = getIndentLength();
5136 runInIndentChars = indentLength_ / 2;
5137 formattedLine.append(runInIndentChars - 1, ' ');
5139 else if (getForceTabIndentation() && getIndentLength() != getTabLength())
5141 // insert the space indents
5143 int indentLength_ = getIndentLength();
5144 int tabLength_ = getTabLength();
5145 indent.append(indentLength_, ' ');
5147 indent.append(indentLength_, ' ');
5148 // replace spaces indents with tab indents
5149 size_t tabCount = indent.length() / tabLength_; // truncate extra spaces
5150 indent.replace(0U, tabCount * tabLength_, tabCount, '\t');
5151 runInIndentChars = indentLength_;
5152 if (indent[0] == ' ') // allow for brace
5154 formattedLine.append(indent);
5156 else if (getIndentString() == "\t")
5158 appendChar('\t', false);
5159 runInIndentChars = 2; // one for { and one for tab
5162 appendChar('\t', false);
5168 int indentLength_ = getIndentLength();
5169 formattedLine.append(indentLength_ - 1, ' ');
5170 runInIndentChars = indentLength_;
5173 formattedLine.append(indentLength_, ' ');
5174 runInIndentChars += indentLength_;
5177 isInBraceRunIn = true;
5181 * remove whitespace and add indentation for an array run-in.
5183 void ASFormatter::formatArrayRunIn()
5185 assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));
5187 // make sure the brace is broken
5188 if (formattedLine.find_first_not_of(" \t{") != string::npos)
5191 size_t lastText = formattedLine.find_last_not_of(" \t");
5192 if (lastText == string::npos || formattedLine[lastText] != '{')
5195 // check for extra whitespace
5196 if (formattedLine.length() > lastText + 1
5197 && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos)
5198 formattedLine.erase(lastText + 1);
5200 if (getIndentString() == "\t")
5202 appendChar('\t', false);
5203 runInIndentChars = 2; // one for { and one for tab
5207 int indent = getIndentLength();
5208 formattedLine.append(indent - 1, ' ');
5209 runInIndentChars = indent;
5211 isInBraceRunIn = true;
5212 isInLineBreak = false;
5216 * delete a braceTypeStack vector object
5217 * BraceTypeStack did not work with the DeleteContainer template
5219 void ASFormatter::deleteContainer(vector<BraceType>*& container)
5221 if (container != nullptr)
5225 container = nullptr;
5230 * delete a vector object
5231 * T is the type of vector
5232 * used for all vectors except braceTypeStack
5234 template<typename T>
5235 void ASFormatter::deleteContainer(T& container)
5237 if (container != nullptr)
5241 container = nullptr;
5246 * initialize a braceType vector object
5247 * braceType did not work with the DeleteContainer template
5249 void ASFormatter::initContainer(vector<BraceType>*& container, vector<BraceType>* value)
5251 if (container != nullptr)
5252 deleteContainer(container);
5257 * initialize a vector object
5258 * T is the type of vector
5259 * used for all vectors except braceTypeStack
5261 template<typename T>
5262 void ASFormatter::initContainer(T& container, T value)
5264 // since the ASFormatter object is never deleted,
5265 // the existing vectors must be deleted before creating new ones
5266 if (container != nullptr)
5267 deleteContainer(container);
5272 * convert a tab to spaces.
5273 * charNum points to the current character to convert to spaces.
5274 * tabIncrementIn is the increment that must be added for tab indent characters
5275 * to get the correct column for the current tab.
5276 * replaces the tab in currentLine with the required number of spaces.
5277 * replaces the value of currentChar.
5279 void ASFormatter::convertTabToSpaces()
5281 assert(currentChar == '\t');
5283 // do NOT replace if in quotes
5284 if (isInQuote || isInQuoteContinuation)
5287 size_t tabSize = getTabLength();
5288 size_t numSpaces = tabSize - ((tabIncrementIn + charNum) % tabSize);
5289 currentLine.replace(charNum, 1, numSpaces, ' ');
5290 currentChar = currentLine[charNum];
5294 * is it ok to break this block?
5296 bool ASFormatter::isOkToBreakBlock(BraceType braceType) const
5298 // Actually, there should not be an ARRAY_TYPE brace here.
5299 // But this will avoid breaking a one line block when there is.
5300 // Otherwise they will be formatted differently on consecutive runs.
5301 if (isBraceType(braceType, ARRAY_TYPE)
5302 && isBraceType(braceType, SINGLE_LINE_TYPE))
5304 if (isBraceType(braceType, COMMAND_TYPE)
5305 && isBraceType(braceType, EMPTY_BLOCK_TYPE))
5307 if (!isBraceType(braceType, SINGLE_LINE_TYPE)
5308 || isBraceType(braceType, BREAK_BLOCK_TYPE)
5309 || shouldBreakOneLineBlocks)
5315 * check if a sharp header is a paren or non-paren header
5317 bool ASFormatter::isSharpStyleWithParen(const string* header) const
5319 return (isSharpStyle() && peekNextChar() == '('
5320 && (header == &AS_CATCH
5321 || header == &AS_DELEGATE));
5325 * Check for a following header when a comment is reached.
5326 * firstLine must contain the start of the comment.
5327 * return value is a pointer to the header or nullptr.
5329 const string* ASFormatter::checkForHeaderFollowingComment(const string& firstLine) const
5331 assert(isInComment || isInLineComment);
5332 assert(shouldBreakElseIfs || shouldBreakBlocks || isInSwitchStatement());
5333 // look ahead to find the next non-comment text
5334 bool endOnEmptyLine = (currentHeader == nullptr);
5335 if (isInSwitchStatement())
5336 endOnEmptyLine = false;
5337 string nextText = peekNextText(firstLine, endOnEmptyLine);
5339 if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
5342 return ASBase::findHeader(nextText, 0, headers);
5346 * process preprocessor statements.
5347 * charNum should be the index of the #.
5349 * delete braceTypeStack entries added by #if if a #else is found.
5350 * prevents double entries in the braceTypeStack.
5352 void ASFormatter::processPreprocessor()
5354 assert(currentChar == '#');
5356 const size_t preproc = currentLine.find_first_not_of(" \t", charNum + 1);
5358 if (preproc == string::npos)
5361 if (currentLine.compare(preproc, 2, "if") == 0)
5363 preprocBraceTypeStackSize = braceTypeStack->size();
5365 else if (currentLine.compare(preproc, 4, "else") == 0)
5367 // delete stack entries added in #if
5368 // should be replaced by #else
5369 if (preprocBraceTypeStackSize > 0)
5371 int addedPreproc = braceTypeStack->size() - preprocBraceTypeStackSize;
5372 for (int i = 0; i < addedPreproc; i++)
5373 braceTypeStack->pop_back();
5379 * determine if the next line starts a comment
5380 * and a header follows the comment or comments.
5382 bool ASFormatter::commentAndHeaderFollows()
5384 // called ONLY IF shouldDeleteEmptyLines and shouldBreakBlocks are TRUE.
5385 assert(shouldDeleteEmptyLines && shouldBreakBlocks);
5387 // is the next line a comment
5388 auto stream = make_shared<ASPeekStream>(sourceIterator);
5389 if (!stream->hasMoreLines())
5391 string nextLine_ = stream->peekNextLine();
5392 size_t firstChar = nextLine_.find_first_not_of(" \t");
5393 if (firstChar == string::npos
5394 || !(nextLine_.compare(firstChar, 2, "//") == 0
5395 || nextLine_.compare(firstChar, 2, "/*") == 0))
5398 // find the next non-comment text, and reset
5399 string nextText = peekNextText(nextLine_, false, stream);
5400 if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
5403 const string* newHeader = ASBase::findHeader(nextText, 0, headers);
5405 if (newHeader == nullptr)
5408 // if a closing header, reset break unless break is requested
5409 if (isClosingHeader(newHeader) && !shouldBreakClosingHeaderBlocks)
5411 isAppendPostBlockEmptyLineRequested = false;
5419 * determine if a brace should be attached or broken
5420 * uses braces in the braceTypeStack
5421 * the last brace in the braceTypeStack is the one being formatted
5422 * returns true if the brace should be broken
5424 bool ASFormatter::isCurrentBraceBroken() const
5426 assert(braceTypeStack->size() > 1);
5428 bool breakBrace = false;
5429 size_t stackEnd = braceTypeStack->size() - 1;
5431 // check brace modifiers
5432 if (shouldAttachExternC
5433 && isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))
5437 if (shouldAttachNamespace
5438 && isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))
5442 if (shouldAttachClass
5443 && (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)
5444 || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE)))
5448 if (shouldAttachInline
5449 && isCStyle() // for C++ only
5450 && braceFormatMode != RUN_IN_MODE
5451 && !(currentLineBeginsWithBrace && peekNextChar() == '/')
5452 && isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))
5455 for (i = 1; i < braceTypeStack->size(); i++)
5456 if (isBraceType((*braceTypeStack)[i], CLASS_TYPE)
5457 || isBraceType((*braceTypeStack)[i], STRUCT_TYPE))
5462 if (isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))
5464 if (currentLineBeginsWithBrace
5465 || braceFormatMode == RUN_IN_MODE)
5468 else if (braceFormatMode == NONE_MODE)
5470 if (currentLineBeginsWithBrace
5471 && (int) currentLineFirstBraceNum == charNum)
5474 else if (braceFormatMode == BREAK_MODE || braceFormatMode == RUN_IN_MODE)
5478 else if (braceFormatMode == LINUX_MODE)
5480 // break a namespace if NOT stroustrup or mozilla
5481 if (isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))
5483 if (formattingStyle != STYLE_STROUSTRUP
5484 && formattingStyle != STYLE_MOZILLA)
5487 // break a class or interface if NOT stroustrup
5488 else if (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)
5489 || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE))
5491 if (formattingStyle != STYLE_STROUSTRUP)
5494 // break a struct if mozilla - an enum is processed as an array brace
5495 else if (isBraceType((*braceTypeStack)[stackEnd], STRUCT_TYPE))
5497 if (formattingStyle == STYLE_MOZILLA)
5500 // break the first brace if a function
5501 else if (isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))
5507 else if (stackEnd > 1)
5509 // break the first brace after these if a function
5510 if (isBraceType((*braceTypeStack)[stackEnd - 1], NAMESPACE_TYPE)
5511 || isBraceType((*braceTypeStack)[stackEnd - 1], CLASS_TYPE)
5512 || isBraceType((*braceTypeStack)[stackEnd - 1], ARRAY_TYPE)
5513 || isBraceType((*braceTypeStack)[stackEnd - 1], STRUCT_TYPE)
5514 || isBraceType((*braceTypeStack)[stackEnd - 1], EXTERN_TYPE))
5525 * format comment body
5526 * the calling function should have a continue statement after calling this method
5528 void ASFormatter::formatCommentBody()
5530 assert(isInComment);
5532 // append the comment
5533 while (charNum < (int) currentLine.length())
5535 currentChar = currentLine[charNum];
5536 if (isSequenceReached("*/"))
5538 formatCommentCloser();
5541 if (currentChar == '\t' && shouldConvertTabs)
5542 convertTabToSpaces();
5543 appendCurrentChar();
5546 if (shouldStripCommentPrefix)
5547 stripCommentPrefix();
5551 * format a comment opener
5552 * the comment opener will be appended to the current formattedLine or a new formattedLine as necessary
5553 * the calling function should have a continue statement after calling this method
5555 void ASFormatter::formatCommentOpener()
5557 assert(isSequenceReached("/*"));
5559 isInComment = isInCommentStartLine = true;
5560 isImmediatelyPostLineComment = false;
5561 if (previousNonWSChar == '}')
5562 resetEndOfStatement();
5564 // Check for a following header.
5565 // For speed do not check multiple comment lines more than once.
5566 // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.
5567 const string* followingHeader = nullptr;
5568 if ((doesLineStartComment
5569 && !isImmediatelyPostCommentOnly
5570 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
5571 && (shouldBreakElseIfs
5572 || isInSwitchStatement()
5573 || (shouldBreakBlocks
5574 && !isImmediatelyPostEmptyLine
5575 && previousCommandChar != '{')))
5576 followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));
5578 if (spacePadNum != 0 && !isInLineBreak)
5580 formattedLineCommentNum = formattedLine.length();
5582 // must be done BEFORE appendSequence
5583 if (previousCommandChar == '{'
5584 && !isImmediatelyPostComment
5585 && !isImmediatelyPostLineComment)
5587 if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
5589 // namespace run-in is always broken.
5590 isInLineBreak = true;
5592 else if (braceFormatMode == NONE_MODE)
5594 // should a run-in statement be attached?
5595 if (currentLineBeginsWithBrace)
5598 else if (braceFormatMode == ATTACH_MODE)
5600 // if the brace was not attached?
5601 if (formattedLine.length() > 0 && formattedLine[0] == '{'
5602 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
5603 isInLineBreak = true;
5605 else if (braceFormatMode == RUN_IN_MODE)
5607 // should a run-in statement be attached?
5608 if (formattedLine.length() > 0 && formattedLine[0] == '{')
5612 else if (!doesLineStartComment)
5613 noTrimCommentContinuation = true;
5615 // ASBeautifier needs to know the following statements
5616 if (shouldBreakElseIfs && followingHeader == &AS_ELSE)
5617 elseHeaderFollowsComments = true;
5618 if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT)
5619 caseHeaderFollowsComments = true;
5621 // appendSequence will write the previous line
5622 appendSequence(AS_OPEN_COMMENT);
5625 // must be done AFTER appendSequence
5627 // Break before the comment if a header follows the line comment.
5628 // But not break if previous line is empty, a comment, or a '{'.
5629 if (shouldBreakBlocks
5630 && followingHeader != nullptr
5631 && !isImmediatelyPostEmptyLine
5632 && previousCommandChar != '{')
5634 if (isClosingHeader(followingHeader))
5636 if (!shouldBreakClosingHeaderBlocks)
5637 isPrependPostBlockEmptyLineRequested = false;
5639 // if an opening header, break before the comment
5641 isPrependPostBlockEmptyLineRequested = true;
5644 if (previousCommandChar == '}')
5645 currentHeader = nullptr;
5649 * format a comment closer
5650 * the comment closer will be appended to the current formattedLine
5652 void ASFormatter::formatCommentCloser()
5654 assert(isSequenceReached("*/"));
5655 isInComment = false;
5656 noTrimCommentContinuation = false;
5657 isImmediatelyPostComment = true;
5658 appendSequence(AS_CLOSE_COMMENT);
5660 if (doesLineStartComment
5661 && (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos))
5662 lineEndsInCommentOnly = true;
5663 if (peekNextChar() == '}'
5664 && previousCommandChar != ';'
5665 && !isBraceType(braceTypeStack->back(), ARRAY_TYPE)
5666 && !isInPreprocessor
5667 && isOkToBreakBlock(braceTypeStack->back()))
5669 isInLineBreak = true;
5670 shouldBreakLineAtNextChar = true;
5675 * format a line comment body
5676 * the calling function should have a continue statement after calling this method
5678 void ASFormatter::formatLineCommentBody()
5680 assert(isInLineComment);
5682 // append the comment
5683 while (charNum < (int) currentLine.length())
5684 // && !isLineReady // commented out in release 2.04, unnecessary
5686 currentChar = currentLine[charNum];
5687 if (currentChar == '\t' && shouldConvertTabs)
5688 convertTabToSpaces();
5689 appendCurrentChar();
5693 // explicitly break a line when a line comment's end is found.
5694 if (charNum == (int) currentLine.length())
5696 isInLineBreak = true;
5697 isInLineComment = false;
5698 isImmediatelyPostLineComment = true;
5699 currentChar = 0; //make sure it is a neutral char.
5704 * format a line comment opener
5705 * the line comment opener will be appended to the current formattedLine or a new formattedLine as necessary
5706 * the calling function should have a continue statement after calling this method
5708 void ASFormatter::formatLineCommentOpener()
5710 assert(isSequenceReached("//"));
5712 if ((int) currentLine.length() > charNum + 2
5713 && currentLine[charNum + 2] == '\xf2') // check for windows line marker
5714 isAppendPostBlockEmptyLineRequested = false;
5716 isInLineComment = true;
5717 isCharImmediatelyPostComment = false;
5718 if (previousNonWSChar == '}')
5719 resetEndOfStatement();
5721 // Check for a following header.
5722 // For speed do not check multiple comment lines more than once.
5723 // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.
5724 const string* followingHeader = nullptr;
5725 if ((lineIsLineCommentOnly
5726 && !isImmediatelyPostCommentOnly
5727 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
5728 && (shouldBreakElseIfs
5729 || isInSwitchStatement()
5730 || (shouldBreakBlocks
5731 && !isImmediatelyPostEmptyLine
5732 && previousCommandChar != '{')))
5733 followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));
5735 // do not indent if in column 1 or 2
5736 // or in a namespace before the opening brace
5737 if ((!shouldIndentCol1Comments && !lineCommentNoIndent)
5738 || foundNamespaceHeader)
5741 lineCommentNoIndent = true;
5742 else if (charNum == 1 && currentLine[0] == ' ')
5743 lineCommentNoIndent = true;
5745 // move comment if spaces were added or deleted
5746 if (!lineCommentNoIndent && spacePadNum != 0 && !isInLineBreak)
5748 formattedLineCommentNum = formattedLine.length();
5750 // must be done BEFORE appendSequence
5751 // check for run-in statement
5752 if (previousCommandChar == '{'
5753 && !isImmediatelyPostComment
5754 && !isImmediatelyPostLineComment)
5756 if (braceFormatMode == NONE_MODE)
5758 if (currentLineBeginsWithBrace)
5761 else if (braceFormatMode == RUN_IN_MODE)
5763 if (!lineCommentNoIndent)
5766 isInLineBreak = true;
5768 else if (braceFormatMode == BREAK_MODE)
5770 if (formattedLine.length() > 0 && formattedLine[0] == '{')
5771 isInLineBreak = true;
5775 if (currentLineBeginsWithBrace)
5776 isInLineBreak = true;
5780 // ASBeautifier needs to know the following statements
5781 if (shouldBreakElseIfs && followingHeader == &AS_ELSE)
5782 elseHeaderFollowsComments = true;
5783 if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT)
5784 caseHeaderFollowsComments = true;
5786 // appendSequence will write the previous line
5787 appendSequence(AS_OPEN_LINE_COMMENT);
5790 // must be done AFTER appendSequence
5792 // Break before the comment if a header follows the line comment.
5793 // But do not break if previous line is empty, a comment, or a '{'.
5794 if (shouldBreakBlocks
5795 && followingHeader != nullptr
5796 && !isImmediatelyPostEmptyLine
5797 && previousCommandChar != '{')
5799 if (isClosingHeader(followingHeader))
5801 if (!shouldBreakClosingHeaderBlocks)
5802 isPrependPostBlockEmptyLineRequested = false;
5804 // if an opening header, break before the comment
5806 isPrependPostBlockEmptyLineRequested = true;
5809 if (previousCommandChar == '}')
5810 currentHeader = nullptr;
5812 // if tabbed input don't convert the immediately following tabs to spaces
5813 if (getIndentString() == "\t" && lineCommentNoIndent)
5815 while (charNum + 1 < (int) currentLine.length()
5816 && currentLine[charNum + 1] == '\t')
5818 currentChar = currentLine[++charNum];
5819 appendCurrentChar();
5823 // explicitly break a line when a line comment's end is found.
5824 if (charNum + 1 == (int) currentLine.length())
5826 isInLineBreak = true;
5827 isInLineComment = false;
5828 isImmediatelyPostLineComment = true;
5829 currentChar = 0; //make sure it is a neutral char.
5835 * the calling function should have a continue statement after calling this method
5837 void ASFormatter::formatQuoteBody()
5843 isSpecialChar = false;
5845 else if (currentChar == '\\' && !isInVerbatimQuote)
5847 if (peekNextChar() == ' ') // is this '\' at end of line
5848 haveLineContinuationChar = true;
5850 isSpecialChar = true;
5852 else if (isInVerbatimQuote && currentChar == '"')
5856 string delim = ')' + verbatimDelimiter;
5857 int delimStart = charNum - delim.length();
5858 if (delimStart > 0 && currentLine.substr(delimStart, delim.length()) == delim)
5861 isInVerbatimQuote = false;
5864 else if (isSharpStyle())
5866 if ((int) currentLine.length() > charNum + 1
5867 && currentLine[charNum + 1] == '"') // check consecutive quotes
5869 appendSequence("\"\"");
5874 isInVerbatimQuote = false;
5877 else if (quoteChar == currentChar)
5882 appendCurrentChar();
5884 // append the text to the ending quoteChar or an escape sequence
5885 // tabs in quotes are NOT changed by convert-tabs
5886 if (isInQuote && currentChar != '\\')
5888 while (charNum + 1 < (int) currentLine.length()
5889 && currentLine[charNum + 1] != quoteChar
5890 && currentLine[charNum + 1] != '\\')
5892 currentChar = currentLine[++charNum];
5893 appendCurrentChar();
5896 if (charNum + 1 >= (int) currentLine.length()
5897 && currentChar != '\\'
5898 && !isInVerbatimQuote)
5899 isInQuote = false; // missing closing quote
5903 * format a quote opener
5904 * the quote opener will be appended to the current formattedLine or a new formattedLine as necessary
5905 * the calling function should have a continue statement after calling this method
5907 void ASFormatter::formatQuoteOpener()
5909 assert(currentChar == '"'
5910 || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)));
5913 quoteChar = currentChar;
5914 if (isCStyle() && previousChar == 'R')
5916 int parenPos = currentLine.find('(', charNum);
5919 isInVerbatimQuote = true;
5920 verbatimDelimiter = currentLine.substr(charNum + 1, parenPos - charNum - 1);
5923 else if (isSharpStyle() && previousChar == '@')
5924 isInVerbatimQuote = true;
5926 // a quote following a brace is an array
5927 if (previousCommandChar == '{'
5928 && !isImmediatelyPostComment
5929 && !isImmediatelyPostLineComment
5930 && isNonInStatementArray
5931 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
5932 && !isWhiteSpace(peekNextChar()))
5934 if (braceFormatMode == NONE_MODE)
5936 if (currentLineBeginsWithBrace)
5939 else if (braceFormatMode == RUN_IN_MODE)
5943 else if (braceFormatMode == BREAK_MODE)
5945 if (formattedLine.length() > 0 && formattedLine[0] == '{')
5946 isInLineBreak = true;
5950 if (currentLineBeginsWithBrace)
5951 isInLineBreak = true;
5954 previousCommandChar = ' ';
5955 appendCurrentChar();
5959 * get the next line comment adjustment that results from breaking a closing brace.
5960 * the brace must be on the same line as the closing header.
5961 * i.e "} else" changed to "} <NL> else".
5963 int ASFormatter::getNextLineCommentAdjustment()
5965 assert(foundClosingHeader && previousNonWSChar == '}');
5966 if (charNum < 1) // "else" is in column 1
5968 size_t lastBrace = currentLine.rfind('}', charNum - 1);
5969 if (lastBrace != string::npos)
5970 return (lastBrace - charNum); // return a negative number
5974 // for console build only
5975 LineEndFormat ASFormatter::getLineEndFormat() const
5981 * get the current line comment adjustment that results from attaching
5982 * a closing header to a closing brace.
5983 * the brace must be on the line previous to the closing header.
5984 * the adjustment is 2 chars, one for the brace and one for the space.
5985 * i.e "} <NL> else" changed to "} else".
5987 int ASFormatter::getCurrentLineCommentAdjustment()
5989 assert(foundClosingHeader && previousNonWSChar == '}');
5992 size_t lastBrace = currentLine.rfind('}', charNum - 1);
5993 if (lastBrace == string::npos)
5999 * get the previous word on a line
6000 * the argument 'currPos' must point to the current position.
6002 * @return is the previous word or an empty string if none found.
6004 string ASFormatter::getPreviousWord(const string& line, int currPos) const
6006 // get the last legal word (may be a number)
6010 size_t end = line.find_last_not_of(" \t", currPos - 1);
6011 if (end == string::npos || !isLegalNameChar(line[end]))
6014 int start; // start of the previous word
6015 for (start = end; start > -1; start--)
6017 if (!isLegalNameChar(line[start]) || line[start] == '.')
6022 return (line.substr(start, end - start + 1));
6026 * check if a line break is needed when a closing brace
6027 * is followed by a closing header.
6028 * the break depends on the braceFormatMode and other factors.
6030 void ASFormatter::isLineBreakBeforeClosingHeader()
6032 assert(foundClosingHeader && previousNonWSChar == '}');
6034 if (currentHeader == &AS_WHILE && shouldAttachClosingWhile)
6036 appendClosingHeader();
6040 if (braceFormatMode == BREAK_MODE
6041 || braceFormatMode == RUN_IN_MODE
6042 || attachClosingBraceMode)
6044 isInLineBreak = true;
6046 else if (braceFormatMode == NONE_MODE)
6048 if (shouldBreakClosingHeaderBraces
6049 || getBraceIndent() || getBlockIndent())
6051 isInLineBreak = true;
6056 // is closing brace broken?
6057 size_t i = currentLine.find_first_not_of(" \t");
6058 if (i != string::npos && currentLine[i] == '}')
6059 isInLineBreak = false;
6061 if (shouldBreakBlocks)
6062 isAppendPostBlockEmptyLineRequested = false;
6065 // braceFormatMode == ATTACH_MODE, LINUX_MODE
6068 if (shouldBreakClosingHeaderBraces
6069 || getBraceIndent() || getBlockIndent())
6071 isInLineBreak = true;
6075 appendClosingHeader();
6076 if (shouldBreakBlocks)
6077 isAppendPostBlockEmptyLineRequested = false;
6083 * Append a closing header to the previous closing brace, if possible
6085 void ASFormatter::appendClosingHeader()
6087 // if a blank line does not precede this
6088 // or last line is not a one line block, attach header
6089 bool previousLineIsEmpty = isEmptyLine(formattedLine);
6090 int previousLineIsOneLineBlock = 0;
6091 size_t firstBrace = findNextChar(formattedLine, '{');
6092 if (firstBrace != string::npos)
6093 previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBrace);
6094 if (!previousLineIsEmpty
6095 && previousLineIsOneLineBlock == 0)
6097 isInLineBreak = false;
6099 spacePadNum = 0; // don't count as comment padding
6104 * Add braces to a single line statement following a header.
6105 * braces are not added if the proper conditions are not met.
6106 * braces are added to the currentLine.
6108 bool ASFormatter::addBracesToStatement()
6110 assert(isImmediatelyPostHeader);
6112 if (currentHeader != &AS_IF
6113 && currentHeader != &AS_ELSE
6114 && currentHeader != &AS_FOR
6115 && currentHeader != &AS_WHILE
6116 && currentHeader != &AS_DO
6117 && currentHeader != &AS_FOREACH
6118 && currentHeader != &AS_QFOREACH
6119 && currentHeader != &AS_QFOREVER
6120 && currentHeader != &AS_FOREVER)
6123 if (currentHeader == &AS_WHILE && foundClosingHeader) // do-while
6126 // do not brace an empty statement
6127 if (currentChar == ';')
6130 // do not add if a header follows
6131 if (isCharPotentialHeader(currentLine, charNum))
6132 if (findHeader(headers) != nullptr)
6135 // find the next semi-colon
6136 size_t nextSemiColon = charNum;
6137 if (currentChar != ';')
6138 nextSemiColon = findNextChar(currentLine, ';', charNum + 1);
6139 if (nextSemiColon == string::npos)
6142 // add closing brace before changing the line length
6143 if (nextSemiColon == currentLine.length() - 1)
6144 currentLine.append(" }");
6146 currentLine.insert(nextSemiColon + 1, " }");
6147 // add opening brace
6148 currentLine.insert(charNum, "{ ");
6149 assert(computeChecksumIn("{}"));
6151 if ((int) currentLine.find_first_not_of(" \t") == charNum)
6152 currentLineBeginsWithBrace = true;
6153 // remove extra spaces
6154 if (!shouldAddOneLineBraces)
6156 size_t lastText = formattedLine.find_last_not_of(" \t");
6157 if ((formattedLine.length() - 1) - lastText > 1)
6158 formattedLine.erase(lastText + 1);
6164 * Remove braces from a single line statement following a header.
6165 * braces are not removed if the proper conditions are not met.
6166 * The first brace is replaced by a space.
6168 bool ASFormatter::removeBracesFromStatement()
6170 assert(isImmediatelyPostHeader);
6171 assert(currentChar == '{');
6173 if (currentHeader != &AS_IF
6174 && currentHeader != &AS_ELSE
6175 && currentHeader != &AS_FOR
6176 && currentHeader != &AS_WHILE
6177 && currentHeader != &AS_FOREACH)
6180 if (currentHeader == &AS_WHILE && foundClosingHeader) // do-while
6183 bool isFirstLine = true;
6185 // leave nextLine_ empty if end of line comment follows
6186 if (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace)
6187 nextLine_ = currentLine.substr(charNum + 1);
6188 size_t nextChar = 0;
6190 // find the first non-blank text
6191 ASPeekStream stream(sourceIterator);
6192 while (stream.hasMoreLines() || isFirstLine)
6195 isFirstLine = false;
6198 nextLine_ = stream.peekNextLine();
6202 nextChar = nextLine_.find_first_not_of(" \t", nextChar);
6203 if (nextChar != string::npos)
6207 // don't remove if comments or a header follow the brace
6208 if ((nextLine_.compare(nextChar, 2, "/*") == 0)
6209 || (nextLine_.compare(nextChar, 2, "//") == 0)
6210 || (isCharPotentialHeader(nextLine_, nextChar)
6211 && ASBase::findHeader(nextLine_, nextChar, headers) != nullptr))
6214 // find the next semi-colon
6215 size_t nextSemiColon = nextChar;
6216 if (nextLine_[nextChar] != ';')
6217 nextSemiColon = findNextChar(nextLine_, ';', nextChar + 1);
6218 if (nextSemiColon == string::npos)
6221 // find the closing brace
6223 nextChar = nextSemiColon + 1;
6224 while (stream.hasMoreLines() || isFirstLine)
6227 isFirstLine = false;
6230 nextLine_ = stream.peekNextLine();
6233 nextChar = nextLine_.find_first_not_of(" \t", nextChar);
6234 if (nextChar != string::npos)
6237 if (nextLine_.length() == 0 || nextLine_[nextChar] != '}')
6240 // remove opening brace
6241 currentLine[charNum] = currentChar = ' ';
6242 assert(adjustChecksumIn(-'{'));
6247 * Find the next character that is not in quotes or a comment.
6249 * @param line the line to be searched.
6250 * @param searchChar the char to find.
6251 * @param searchStart the start position on the line (default is 0).
6252 * @return the position on the line or string::npos if not found.
6254 size_t ASFormatter::findNextChar(const string& line, char searchChar, int searchStart /*0*/) const
6256 // find the next searchChar
6258 for (i = searchStart; i < line.length(); i++)
6260 if (line.compare(i, 2, "//") == 0)
6261 return string::npos;
6262 if (line.compare(i, 2, "/*") == 0)
6264 size_t endComment = line.find("*/", i + 2);
6265 if (endComment == string::npos)
6266 return string::npos;
6268 if (i >= line.length())
6269 return string::npos;
6272 || (line[i] == '\'' && !isDigitSeparator(line, i)))
6274 char quote = line[i];
6275 while (i < line.length())
6277 size_t endQuote = line.find(quote, i + 1);
6278 if (endQuote == string::npos)
6279 return string::npos;
6281 if (line[endQuote - 1] != '\\') // check for '\"'
6283 if (line[endQuote - 2] == '\\') // check for '\\'
6288 if (line[i] == searchChar)
6291 // for now don't process C# 'delegate' braces
6292 // do this last in case the search char is a '{'
6294 return string::npos;
6296 if (i >= line.length()) // didn't find searchChar
6297 return string::npos;
6303 * Look ahead in the file to see if a struct has access modifiers.
6305 * @param firstLine a reference to the line to indent.
6306 * @param index the current line index.
6307 * @return true if the struct has access modifiers.
6309 bool ASFormatter::isStructAccessModified(const string& firstLine, size_t index) const
6311 assert(firstLine[index] == '{');
6314 bool isFirstLine = true;
6315 size_t braceCount = 1;
6316 string nextLine_ = firstLine.substr(index + 1);
6317 ASPeekStream stream(sourceIterator);
6319 // find the first non-blank text, bypassing all comments and quotes.
6320 bool isInComment_ = false;
6321 bool isInQuote_ = false;
6322 char quoteChar_ = ' ';
6323 while (stream.hasMoreLines() || isFirstLine)
6326 isFirstLine = false;
6328 nextLine_ = stream.peekNextLine();
6330 for (size_t i = 0; i < nextLine_.length(); i++)
6332 if (isWhiteSpace(nextLine_[i]))
6334 if (nextLine_.compare(i, 2, "/*") == 0)
6335 isInComment_ = true;
6338 if (nextLine_.compare(i, 2, "*/") == 0)
6340 isInComment_ = false;
6345 if (nextLine_[i] == '\\')
6353 if (nextLine_[i] == quoteChar_)
6358 if (nextLine_[i] == '"'
6359 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
6362 quoteChar_ = nextLine_[i];
6365 if (nextLine_.compare(i, 2, "//") == 0)
6367 i = nextLine_.length();
6371 if (nextLine_[i] == '{')
6373 if (nextLine_[i] == '}')
6375 if (braceCount == 0)
6377 // check for access modifiers
6378 if (isCharPotentialHeader(nextLine_, i))
6380 if (findKeyword(nextLine_, i, AS_PUBLIC)
6381 || findKeyword(nextLine_, i, AS_PRIVATE)
6382 || findKeyword(nextLine_, i, AS_PROTECTED))
6384 string name = getCurrentWord(nextLine_, i);
6385 i += name.length() - 1;
6387 } // end of for loop
6388 } // end of while loop
6394 * Look ahead in the file to see if a preprocessor block is indentable.
6396 * @param firstLine a reference to the line to indent.
6397 * @param index the current line index.
6398 * @return true if the block is indentable.
6400 bool ASFormatter::isIndentablePreprocessorBlock(const string& firstLine, size_t index)
6402 assert(firstLine[index] == '#');
6404 bool isFirstLine = true;
6405 bool isInIndentableBlock = false;
6406 bool blockContainsBraces = false;
6407 bool blockContainsDefineContinuation = false;
6408 bool isInClassConstructor = false;
6409 bool isPotentialHeaderGuard = false; // ifndef is first preproc statement
6410 bool isPotentialHeaderGuard2 = false; // define is within the first proproc
6411 int numBlockIndents = 0;
6412 int lineParenCount = 0;
6413 string nextLine_ = firstLine.substr(index);
6414 auto stream = make_shared<ASPeekStream>(sourceIterator);
6416 // find end of the block, bypassing all comments and quotes.
6417 bool isInComment_ = false;
6418 bool isInQuote_ = false;
6419 char quoteChar_ = ' ';
6420 while (stream->hasMoreLines() || isFirstLine)
6423 isFirstLine = false;
6425 nextLine_ = stream->peekNextLine();
6427 for (size_t i = 0; i < nextLine_.length(); i++)
6429 if (isWhiteSpace(nextLine_[i]))
6431 if (nextLine_.compare(i, 2, "/*") == 0)
6432 isInComment_ = true;
6435 if (nextLine_.compare(i, 2, "*/") == 0)
6437 isInComment_ = false;
6442 if (nextLine_[i] == '\\')
6449 if (nextLine_[i] == quoteChar_)
6454 if (nextLine_[i] == '"'
6455 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
6458 quoteChar_ = nextLine_[i];
6461 if (nextLine_.compare(i, 2, "//") == 0)
6463 i = nextLine_.length();
6466 // handle preprocessor statement
6467 if (nextLine_[i] == '#')
6469 string preproc = ASBeautifier::extractPreprocessorStatement(nextLine_);
6470 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
6472 numBlockIndents += 1;
6473 isInIndentableBlock = true;
6474 // flag first preprocessor conditional for header include guard check
6475 if (!processedFirstConditional)
6477 processedFirstConditional = true;
6478 isFirstPreprocConditional = true;
6479 if (isNDefPreprocStatement(nextLine_, preproc))
6480 isPotentialHeaderGuard = true;
6483 else if (preproc == "endif")
6485 if (numBlockIndents > 0)
6486 numBlockIndents -= 1;
6487 // must exit BOTH loops
6488 if (numBlockIndents == 0)
6489 goto EndOfWhileLoop;
6491 else if (preproc == "define")
6493 if (nextLine_[nextLine_.length() - 1] == '\\')
6494 blockContainsDefineContinuation = true;
6495 // check for potential header include guards
6496 else if (isPotentialHeaderGuard && numBlockIndents == 1)
6497 isPotentialHeaderGuard2 = true;
6499 i = nextLine_.length();
6502 // handle exceptions
6503 if (nextLine_[i] == '{' || nextLine_[i] == '}')
6504 blockContainsBraces = true;
6505 else if (nextLine_[i] == '(')
6507 else if (nextLine_[i] == ')')
6509 else if (nextLine_[i] == ':')
6512 if (nextLine_.length() > i && nextLine_[i + 1] == ':')
6515 isInClassConstructor = true;
6517 // bypass unnecessary parsing - must exit BOTH loops
6518 if (blockContainsBraces || isInClassConstructor || blockContainsDefineContinuation)
6519 goto EndOfWhileLoop;
6520 } // end of for loop, end of line
6521 if (lineParenCount != 0)
6523 } // end of while loop
6525 preprocBlockEnd = sourceIterator->tellg();
6526 if (preprocBlockEnd < 0)
6527 preprocBlockEnd = sourceIterator->getStreamLength();
6528 if (blockContainsBraces
6529 || isInClassConstructor
6530 || blockContainsDefineContinuation
6531 || lineParenCount != 0
6532 || numBlockIndents != 0)
6533 isInIndentableBlock = false;
6534 // find next executable instruction
6535 // this WILL RESET the get pointer
6536 string nextText = peekNextText("", false, stream);
6537 // bypass header include guards
6538 if (isFirstPreprocConditional)
6540 isFirstPreprocConditional = false;
6541 if (nextText.empty() && isPotentialHeaderGuard2)
6543 isInIndentableBlock = false;
6544 preprocBlockEnd = 0;
6547 // this allows preprocessor blocks within this block to be indented
6548 if (!isInIndentableBlock)
6549 preprocBlockEnd = 0;
6550 // peekReset() is done by previous peekNextText()
6551 return isInIndentableBlock;
6554 bool ASFormatter::isNDefPreprocStatement(const string& nextLine_, const string& preproc) const
6556 if (preproc == "ifndef")
6558 // check for '!defined'
6559 if (preproc == "if")
6561 size_t i = nextLine_.find('!');
6562 if (i == string::npos)
6564 i = nextLine_.find_first_not_of(" \t", ++i);
6565 if (i != string::npos && nextLine_.compare(i, 7, "defined") == 0)
6572 * Check to see if this is an EXEC SQL statement.
6574 * @param line a reference to the line to indent.
6575 * @param index the current line index.
6576 * @return true if the statement is EXEC SQL.
6578 bool ASFormatter::isExecSQL(const string& line, size_t index) const
6580 if (line[index] != 'e' && line[index] != 'E') // quick check to reject most
6583 if (isCharPotentialHeader(line, index))
6584 word = getCurrentWord(line, index);
6585 for (size_t i = 0; i < word.length(); i++)
6586 word[i] = (char) toupper(word[i]);
6589 size_t index2 = index + word.length();
6590 index2 = line.find_first_not_of(" \t", index2);
6591 if (index2 == string::npos)
6594 if (isCharPotentialHeader(line, index2))
6595 word = getCurrentWord(line, index2);
6596 for (size_t i = 0; i < word.length(); i++)
6597 word[i] = (char) toupper(word[i]);
6604 * The continuation lines must be adjusted so the leading spaces
6605 * is equivalent to the text on the opening line.
6607 * Updates currentLine and charNum.
6609 void ASFormatter::trimContinuationLine()
6611 size_t len = currentLine.length();
6612 size_t tabSize = getTabLength();
6615 if (leadingSpaces > 0 && len > 0)
6618 size_t continuationIncrementIn = 0;
6619 for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++)
6621 if (!isWhiteSpace(currentLine[i])) // don't delete any text
6623 if (i < continuationIncrementIn)
6624 leadingSpaces = i + tabIncrementIn;
6625 continuationIncrementIn = tabIncrementIn;
6628 if (currentLine[i] == '\t')
6629 continuationIncrementIn += tabSize - 1 - ((continuationIncrementIn + i) % tabSize);
6632 if ((int) continuationIncrementIn == tabIncrementIn)
6636 // build a new line with the equivalent leading chars
6638 int leadingChars = 0;
6639 if ((int) leadingSpaces > tabIncrementIn)
6640 leadingChars = leadingSpaces - tabIncrementIn;
6641 newLine.append(leadingChars, ' ');
6642 newLine.append(currentLine, i, len - i);
6643 currentLine = newLine;
6644 charNum = leadingChars;
6645 if (currentLine.length() == 0)
6646 currentLine = string(" "); // a null is inserted if this is not done
6654 * Determine if a header is a closing header
6656 * @return true if the header is a closing header.
6658 bool ASFormatter::isClosingHeader(const string* header) const
6660 return (header == &AS_ELSE
6661 || header == &AS_CATCH
6662 || header == &AS_FINALLY);
6666 * Determine if a * following a closing paren is immediately.
6667 * after a cast. If so it is a deference and not a multiply.
6668 * e.g. "(int*) *ptr" is a deference.
6670 bool ASFormatter::isImmediatelyPostCast() const
6672 assert(previousNonWSChar == ')' && currentChar == '*');
6673 // find preceding closing paren on currentLine or readyFormattedLine
6674 string line; // currentLine or readyFormattedLine
6675 size_t paren = currentLine.rfind(')', charNum);
6676 if (paren != string::npos)
6678 // if not on currentLine it must be on the previous line
6681 line = readyFormattedLine;
6682 paren = line.rfind(')');
6683 if (paren == string::npos)
6689 // find character preceding the closing paren
6690 size_t lastChar = line.find_last_not_of(" \t", paren - 1);
6691 if (lastChar == string::npos)
6693 // check for pointer cast
6694 if (line[lastChar] == '*')
6700 * Determine if a < is a template definition or instantiation.
6701 * Sets the class variables isInTemplate and templateDepth.
6703 void ASFormatter::checkIfTemplateOpener()
6705 assert(!isInTemplate && currentChar == '<');
6707 // find first char after the '<' operators
6708 size_t firstChar = currentLine.find_first_not_of("< \t", charNum);
6709 if (firstChar == string::npos
6710 || currentLine[firstChar] == '=')
6712 // this is not a template -> leave...
6713 isInTemplate = false;
6717 bool isFirstLine = true;
6718 int parenDepth_ = 0;
6719 int maxTemplateDepth = 0;
6721 string nextLine_ = currentLine.substr(charNum);
6722 ASPeekStream stream(sourceIterator);
6724 // find the angle braces, bypassing all comments and quotes.
6725 bool isInComment_ = false;
6726 bool isInQuote_ = false;
6727 char quoteChar_ = ' ';
6728 while (stream.hasMoreLines() || isFirstLine)
6731 isFirstLine = false;
6733 nextLine_ = stream.peekNextLine();
6735 for (size_t i = 0; i < nextLine_.length(); i++)
6737 char currentChar_ = nextLine_[i];
6738 if (isWhiteSpace(currentChar_))
6740 if (nextLine_.compare(i, 2, "/*") == 0)
6741 isInComment_ = true;
6744 if (nextLine_.compare(i, 2, "*/") == 0)
6746 isInComment_ = false;
6751 if (currentChar_ == '\\')
6759 if (currentChar_ == quoteChar_)
6764 if (currentChar_ == '"'
6765 || (currentChar_ == '\'' && !isDigitSeparator(nextLine_, i)))
6768 quoteChar_ = currentChar_;
6771 if (nextLine_.compare(i, 2, "//") == 0)
6773 i = nextLine_.length();
6777 // not in a comment or quote
6778 if (currentChar_ == '<')
6784 else if (currentChar_ == '>')
6787 if (templateDepth == 0)
6789 if (parenDepth_ == 0)
6791 // this is a template!
6792 isInTemplate = true;
6793 templateDepth = maxTemplateDepth;
6799 else if (currentChar_ == '(' || currentChar_ == ')')
6801 if (currentChar_ == '(')
6805 if (parenDepth_ >= 0)
6807 // this is not a template -> leave...
6808 isInTemplate = false;
6812 else if (nextLine_.compare(i, 2, AS_AND) == 0
6813 || nextLine_.compare(i, 2, AS_OR) == 0)
6815 // this is not a template -> leave...
6816 isInTemplate = false;
6820 else if (currentChar_ == ',' // comma, e.g. A<int, char>
6821 || currentChar_ == '&' // reference, e.g. A<int&>
6822 || currentChar_ == '*' // pointer, e.g. A<int*>
6823 || currentChar_ == '^' // C++/CLI managed pointer, e.g. A<int^>
6824 || currentChar_ == ':' // ::, e.g. std::string
6825 || currentChar_ == '=' // assign e.g. default parameter
6826 || currentChar_ == '[' // [] e.g. string[]
6827 || currentChar_ == ']' // [] e.g. string[]
6828 || currentChar_ == '(' // (...) e.g. function definition
6829 || currentChar_ == ')' // (...) e.g. function definition
6830 || (isJavaStyle() && currentChar_ == '?') // Java wildcard
6835 else if (!isLegalNameChar(currentChar_))
6837 // this is not a template -> leave...
6838 isInTemplate = false;
6842 string name = getCurrentWord(nextLine_, i);
6843 i += name.length() - 1;
6848 void ASFormatter::updateFormattedLineSplitPoints(char appendedChar)
6850 assert(maxCodeLength != string::npos);
6851 assert(formattedLine.length() > 0);
6853 if (!isOkToSplitFormattedLine())
6856 char nextChar = peekNextChar();
6858 // don't split before an end of line comment
6859 if (nextChar == '/')
6862 // don't split before or after a brace
6863 if (appendedChar == '{' || appendedChar == '}'
6864 || previousNonWSChar == '{' || previousNonWSChar == '}'
6865 || nextChar == '{' || nextChar == '}'
6866 || currentChar == '{' || currentChar == '}') // currentChar tests for an appended brace
6869 // don't split before or after a block paren
6870 if (appendedChar == '[' || appendedChar == ']'
6871 || previousNonWSChar == '['
6872 || nextChar == '[' || nextChar == ']')
6875 if (isWhiteSpace(appendedChar))
6877 if (nextChar != ')' // space before a closing paren
6878 && nextChar != '(' // space before an opening paren
6879 && nextChar != '/' // space before a comment
6880 && nextChar != ':' // space before a colon
6881 && currentChar != ')' // appended space before and after a closing paren
6882 && currentChar != '(' // appended space before and after a opening paren
6883 && previousNonWSChar != '(' // decided at the '('
6884 // don't break before a pointer or reference aligned to type
6885 && !(nextChar == '*'
6886 && !isCharPotentialOperator(previousNonWSChar)
6887 && pointerAlignment == PTR_ALIGN_TYPE)
6888 && !(nextChar == '&'
6889 && !isCharPotentialOperator(previousNonWSChar)
6890 && (referenceAlignment == REF_ALIGN_TYPE
6891 || (referenceAlignment == REF_SAME_AS_PTR && pointerAlignment == PTR_ALIGN_TYPE)))
6894 if (formattedLine.length() - 1 <= maxCodeLength)
6895 maxWhiteSpace = formattedLine.length() - 1;
6897 maxWhiteSpacePending = formattedLine.length() - 1;
6900 // unpadded closing parens may split after the paren (counts as whitespace)
6901 else if (appendedChar == ')')
6908 && !(nextChar == '-' && pointerSymbolFollows())) // check for ->
6910 if (formattedLine.length() <= maxCodeLength)
6911 maxWhiteSpace = formattedLine.length();
6913 maxWhiteSpacePending = formattedLine.length();
6916 // unpadded commas may split after the comma
6917 else if (appendedChar == ',')
6919 if (formattedLine.length() <= maxCodeLength)
6920 maxComma = formattedLine.length();
6922 maxCommaPending = formattedLine.length();
6924 else if (appendedChar == '(')
6926 if (nextChar != ')' && nextChar != '(' && nextChar != '"' && nextChar != '\'')
6928 // if follows an operator break before
6930 if (isCharPotentialOperator(previousNonWSChar))
6931 parenNum = formattedLine.length() - 1;
6933 parenNum = formattedLine.length();
6934 if (formattedLine.length() <= maxCodeLength)
6935 maxParen = parenNum;
6937 maxParenPending = parenNum;
6940 else if (appendedChar == ';')
6942 if (nextChar != ' ' && nextChar != '}' && nextChar != '/') // check for following comment
6944 if (formattedLine.length() <= maxCodeLength)
6945 maxSemi = formattedLine.length();
6947 maxSemiPending = formattedLine.length();
6952 void ASFormatter::updateFormattedLineSplitPointsOperator(const string& sequence)
6954 assert(maxCodeLength != string::npos);
6955 assert(formattedLine.length() > 0);
6957 if (!isOkToSplitFormattedLine())
6960 char nextChar = peekNextChar();
6962 // don't split before an end of line comment
6963 if (nextChar == '/')
6966 // check for logical conditional
6967 if (sequence == "||" || sequence == "&&" || sequence == "or" || sequence == "and")
6969 if (shouldBreakLineAfterLogical)
6971 if (formattedLine.length() <= maxCodeLength)
6972 maxAndOr = formattedLine.length();
6974 maxAndOrPending = formattedLine.length();
6978 // adjust for leading space in the sequence
6979 size_t sequenceLength = sequence.length();
6980 if (formattedLine.length() > sequenceLength
6981 && isWhiteSpace(formattedLine[formattedLine.length() - sequenceLength - 1]))
6983 if (formattedLine.length() - sequenceLength <= maxCodeLength)
6984 maxAndOr = formattedLine.length() - sequenceLength;
6986 maxAndOrPending = formattedLine.length() - sequenceLength;
6989 // comparison operators will split after the operator (counts as whitespace)
6990 else if (sequence == "==" || sequence == "!=" || sequence == ">=" || sequence == "<=")
6992 if (formattedLine.length() <= maxCodeLength)
6993 maxWhiteSpace = formattedLine.length();
6995 maxWhiteSpacePending = formattedLine.length();
6997 // unpadded operators that will split BEFORE the operator (counts as whitespace)
6998 else if (sequence == "+" || sequence == "-" || sequence == "?")
7001 && !(sequence == "+" && isInExponent())
7002 && !(sequence == "-" && isInExponent())
7003 && (isLegalNameChar(currentLine[charNum - 1])
7004 || currentLine[charNum - 1] == ')'
7005 || currentLine[charNum - 1] == ']'
7006 || currentLine[charNum - 1] == '\"'))
7008 if (formattedLine.length() - 1 <= maxCodeLength)
7009 maxWhiteSpace = formattedLine.length() - 1;
7011 maxWhiteSpacePending = formattedLine.length() - 1;
7014 // unpadded operators that will USUALLY split AFTER the operator (counts as whitespace)
7015 else if (sequence == "=" || sequence == ":")
7017 // split BEFORE if the line is too long
7018 // do NOT use <= here, must allow for a brace attached to an array
7019 size_t splitPoint = 0;
7020 if (formattedLine.length() < maxCodeLength)
7021 splitPoint = formattedLine.length();
7023 splitPoint = formattedLine.length() - 1;
7024 // padded or unpadded arrays
7025 if (previousNonWSChar == ']')
7027 if (formattedLine.length() - 1 <= maxCodeLength)
7028 maxWhiteSpace = splitPoint;
7030 maxWhiteSpacePending = splitPoint;
7032 else if (charNum > 0
7033 && (isLegalNameChar(currentLine[charNum - 1])
7034 || currentLine[charNum - 1] == ')'
7035 || currentLine[charNum - 1] == ']'))
7037 if (formattedLine.length() <= maxCodeLength)
7038 maxWhiteSpace = splitPoint;
7040 maxWhiteSpacePending = splitPoint;
7046 * Update the split point when a pointer or reference is formatted.
7047 * The argument is the maximum index of the last whitespace character.
7049 void ASFormatter::updateFormattedLineSplitPointsPointerOrReference(size_t index)
7051 assert(maxCodeLength != string::npos);
7052 assert(formattedLine.length() > 0);
7053 assert(index < formattedLine.length());
7055 if (!isOkToSplitFormattedLine())
7058 if (index < maxWhiteSpace) // just in case
7061 if (index <= maxCodeLength)
7062 maxWhiteSpace = index;
7064 maxWhiteSpacePending = index;
7067 bool ASFormatter::isOkToSplitFormattedLine()
7069 assert(maxCodeLength != string::npos);
7070 // Is it OK to split the line?
7071 if (shouldKeepLineUnbroken
7078 || isInAsm || isInAsmOneLine || isInAsmBlock
7082 if (!isOkToBreakBlock(braceTypeStack->back()) && currentChar != '{')
7084 shouldKeepLineUnbroken = true;
7085 clearFormattedLineSplitPoints();
7088 if (isBraceType(braceTypeStack->back(), ARRAY_TYPE))
7090 shouldKeepLineUnbroken = true;
7091 if (!isBraceType(braceTypeStack->back(), ARRAY_NIS_TYPE))
7092 clearFormattedLineSplitPoints();
7098 /* This is called if the option maxCodeLength is set.
7100 void ASFormatter::testForTimeToSplitFormattedLine()
7102 // DO NOT ASSERT maxCodeLength HERE
7103 // should the line be split
7104 if (formattedLine.length() > maxCodeLength && !isLineReady)
7106 size_t splitPoint = findFormattedLineSplitPoint();
7107 if (splitPoint > 0 && splitPoint < formattedLine.length())
7109 string splitLine = formattedLine.substr(splitPoint);
7110 formattedLine = formattedLine.substr(0, splitPoint);
7112 formattedLine = splitLine;
7113 // if break-blocks is requested and this is a one-line statement
7114 string nextWord = ASBeautifier::getNextWord(currentLine, charNum - 1);
7115 if (isAppendPostBlockEmptyLineRequested
7116 && (nextWord == "break" || nextWord == "continue"))
7118 isAppendPostBlockEmptyLineRequested = false;
7119 isPrependPostBlockEmptyLineRequested = true;
7122 isPrependPostBlockEmptyLineRequested = false;
7123 // adjust max split points
7124 maxAndOr = (maxAndOr > splitPoint) ? (maxAndOr - splitPoint) : 0;
7125 maxSemi = (maxSemi > splitPoint) ? (maxSemi - splitPoint) : 0;
7126 maxComma = (maxComma > splitPoint) ? (maxComma - splitPoint) : 0;
7127 maxParen = (maxParen > splitPoint) ? (maxParen - splitPoint) : 0;
7128 maxWhiteSpace = (maxWhiteSpace > splitPoint) ? (maxWhiteSpace - splitPoint) : 0;
7129 if (maxSemiPending > 0)
7131 maxSemi = (maxSemiPending > splitPoint) ? (maxSemiPending - splitPoint) : 0;
7134 if (maxAndOrPending > 0)
7136 maxAndOr = (maxAndOrPending > splitPoint) ? (maxAndOrPending - splitPoint) : 0;
7137 maxAndOrPending = 0;
7139 if (maxCommaPending > 0)
7141 maxComma = (maxCommaPending > splitPoint) ? (maxCommaPending - splitPoint) : 0;
7142 maxCommaPending = 0;
7144 if (maxParenPending > 0)
7146 maxParen = (maxParenPending > splitPoint) ? (maxParenPending - splitPoint) : 0;
7147 maxParenPending = 0;
7149 if (maxWhiteSpacePending > 0)
7151 maxWhiteSpace = (maxWhiteSpacePending > splitPoint) ? (maxWhiteSpacePending - splitPoint) : 0;
7152 maxWhiteSpacePending = 0;
7154 // don't allow an empty formatted line
7155 size_t firstText = formattedLine.find_first_not_of(" \t");
7156 if (firstText == string::npos && formattedLine.length() > 0)
7158 formattedLine.erase();
7159 clearFormattedLineSplitPoints();
7160 if (isWhiteSpace(currentChar))
7161 for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
7164 else if (firstText > 0)
7166 formattedLine.erase(0, firstText);
7167 maxSemi = (maxSemi > firstText) ? (maxSemi - firstText) : 0;
7168 maxAndOr = (maxAndOr > firstText) ? (maxAndOr - firstText) : 0;
7169 maxComma = (maxComma > firstText) ? (maxComma - firstText) : 0;
7170 maxParen = (maxParen > firstText) ? (maxParen - firstText) : 0;
7171 maxWhiteSpace = (maxWhiteSpace > firstText) ? (maxWhiteSpace - firstText) : 0;
7173 // reset formattedLineCommentNum
7174 if (formattedLineCommentNum != string::npos)
7176 formattedLineCommentNum = formattedLine.find("//");
7177 if (formattedLineCommentNum == string::npos)
7178 formattedLineCommentNum = formattedLine.find("/*");
7184 size_t ASFormatter::findFormattedLineSplitPoint() const
7186 assert(maxCodeLength != string::npos);
7187 // determine where to split
7188 size_t minCodeLength = 10;
7189 size_t splitPoint = 0;
7190 splitPoint = maxSemi;
7191 if (maxAndOr >= minCodeLength)
7192 splitPoint = maxAndOr;
7193 if (splitPoint < minCodeLength)
7195 splitPoint = maxWhiteSpace;
7196 // use maxParen instead if it is long enough
7197 if (maxParen > splitPoint
7198 || maxParen >= maxCodeLength * .7)
7199 splitPoint = maxParen;
7200 // use maxComma instead if it is long enough
7201 // increasing the multiplier causes more splits at whitespace
7202 if (maxComma > splitPoint
7203 || maxComma >= maxCodeLength * .3)
7204 splitPoint = maxComma;
7206 // replace split point with first available break point
7207 if (splitPoint < minCodeLength)
7209 splitPoint = string::npos;
7210 if (maxSemiPending > 0 && maxSemiPending < splitPoint)
7211 splitPoint = maxSemiPending;
7212 if (maxAndOrPending > 0 && maxAndOrPending < splitPoint)
7213 splitPoint = maxAndOrPending;
7214 if (maxCommaPending > 0 && maxCommaPending < splitPoint)
7215 splitPoint = maxCommaPending;
7216 if (maxParenPending > 0 && maxParenPending < splitPoint)
7217 splitPoint = maxParenPending;
7218 if (maxWhiteSpacePending > 0 && maxWhiteSpacePending < splitPoint)
7219 splitPoint = maxWhiteSpacePending;
7220 if (splitPoint == string::npos)
7223 // if remaining line after split is too long
7224 else if (formattedLine.length() - splitPoint > maxCodeLength)
7226 // if end of the currentLine, find a new split point
7228 if (isCharPotentialHeader(currentLine, charNum))
7229 newCharNum = getCurrentWord(currentLine, charNum).length() + charNum;
7231 newCharNum = charNum + 2;
7232 if (newCharNum + 1 > currentLine.length())
7234 // don't move splitPoint from before a conditional to after
7235 if (maxWhiteSpace > splitPoint + 3)
7236 splitPoint = maxWhiteSpace;
7237 if (maxParen > splitPoint)
7238 splitPoint = maxParen;
7245 void ASFormatter::clearFormattedLineSplitPoints()
7253 maxAndOrPending = 0;
7254 maxCommaPending = 0;
7255 maxParenPending = 0;
7256 maxWhiteSpacePending = 0;
7260 * Check if a pointer symbol (->) follows on the currentLine.
7262 bool ASFormatter::pointerSymbolFollows() const
7264 size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
7265 if (peekNum == string::npos || currentLine.compare(peekNum, 2, "->") != 0)
7271 * Compute the input checksum.
7272 * This is called as an assert so it for is debug config only
7274 bool ASFormatter::computeChecksumIn(const string& currentLine_)
7276 for (size_t i = 0; i < currentLine_.length(); i++)
7277 if (!isWhiteSpace(currentLine_[i]))
7278 checksumIn += currentLine_[i];
7283 * Adjust the input checksum for deleted chars.
7284 * This is called as an assert so it for is debug config only
7286 bool ASFormatter::adjustChecksumIn(int adjustment)
7288 checksumIn += adjustment;
7293 * get the value of checksumIn for unit testing
7295 * @return checksumIn.
7297 size_t ASFormatter::getChecksumIn() const
7303 * Compute the output checksum.
7304 * This is called as an assert so it is for debug config only
7306 bool ASFormatter::computeChecksumOut(const string& beautifiedLine)
7308 for (size_t i = 0; i < beautifiedLine.length(); i++)
7309 if (!isWhiteSpace(beautifiedLine[i]))
7310 checksumOut += beautifiedLine[i];
7315 * Return isLineReady for the final check at end of file.
7317 bool ASFormatter::getIsLineReady() const
7323 * get the value of checksumOut for unit testing
7325 * @return checksumOut.
7327 size_t ASFormatter::getChecksumOut() const
7333 * Return the difference in checksums.
7334 * If zero all is okay.
7336 int ASFormatter::getChecksumDiff() const
7338 return checksumOut - checksumIn;
7342 int ASFormatter::getFormatterFileType() const
7344 return formatterFileType;
7347 // Check if an operator follows the next word.
7348 // The next word must be a legal name.
7349 const string* ASFormatter::getFollowingOperator() const
7352 size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
7353 if (nextNum == string::npos)
7356 if (!isLegalNameChar(currentLine[nextNum]))
7359 // bypass next word and following spaces
7360 while (nextNum < currentLine.length())
7362 if (!isLegalNameChar(currentLine[nextNum])
7363 && !isWhiteSpace(currentLine[nextNum]))
7368 if (nextNum >= currentLine.length()
7369 || !isCharPotentialOperator(currentLine[nextNum])
7370 || currentLine[nextNum] == '/') // comment
7373 const string* newOperator = ASBase::findOperator(currentLine, nextNum, operators);
7377 // Check following data to determine if the current character is an array operator.
7378 bool ASFormatter::isArrayOperator() const
7380 assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
7381 assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));
7384 size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
7385 if (nextNum == string::npos)
7388 if (!isLegalNameChar(currentLine[nextNum]))
7391 // bypass next word and following spaces
7392 while (nextNum < currentLine.length())
7394 if (!isLegalNameChar(currentLine[nextNum])
7395 && !isWhiteSpace(currentLine[nextNum]))
7400 // check for characters that indicate an operator
7401 if (currentLine[nextNum] == ','
7402 || currentLine[nextNum] == '}'
7403 || currentLine[nextNum] == ')'
7404 || currentLine[nextNum] == '(')
7409 // Reset the flags that indicate various statement information.
7410 void ASFormatter::resetEndOfStatement()
7412 foundQuestionMark = false;
7413 foundNamespaceHeader = false;
7414 foundClassHeader = false;
7415 foundStructHeader = false;
7416 foundInterfaceHeader = false;
7417 foundPreDefinitionHeader = false;
7418 foundPreCommandHeader = false;
7419 foundPreCommandMacro = false;
7420 foundTrailingReturnType = false;
7421 foundCastOperator = false;
7422 isInPotentialCalculation = false;
7423 isSharpAccessor = false;
7424 isSharpDelegate = false;
7425 isInObjCMethodDefinition = false;
7426 isInObjCInterface = false;
7427 isInObjCSelector = false;
7429 isInExternC = false;
7430 elseHeaderFollowsComments = false;
7431 nonInStatementBrace = 0;
7432 while (!questionMarkStack->empty())
7433 questionMarkStack->pop_back();
7436 // Find the colon alignment for Objective-C method definitions and method calls.
7437 int ASFormatter::findObjCColonAlignment() const
7439 assert(currentChar == '+' || currentChar == '-' || currentChar == '[');
7440 assert(getAlignMethodColon());
7442 bool isFirstLine = true;
7443 bool haveFirstColon = false;
7444 bool foundMethodColon = false;
7445 bool isInComment_ = false;
7446 bool isInQuote_ = false;
7447 char quoteChar_ = ' ';
7448 int sqBracketCount = 0;
7449 int colonAdjust = 0;
7451 string nextLine_ = currentLine;
7452 ASPeekStream stream(sourceIterator);
7455 while (sourceIterator->hasMoreLines() || isFirstLine)
7458 nextLine_ = stream.peekNextLine();
7460 haveFirstColon = false;
7461 nextLine_ = ASBeautifier::trim(nextLine_);
7462 for (size_t i = 0; i < nextLine_.length(); i++)
7464 if (isWhiteSpace(nextLine_[i]))
7466 if (nextLine_.compare(i, 2, "/*") == 0)
7467 isInComment_ = true;
7470 if (nextLine_.compare(i, 2, "*/") == 0)
7472 isInComment_ = false;
7477 if (nextLine_[i] == '\\')
7484 if (nextLine_[i] == quoteChar_)
7489 if (nextLine_[i] == '"'
7490 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
7493 quoteChar_ = nextLine_[i];
7496 if (nextLine_.compare(i, 2, "//") == 0)
7498 i = nextLine_.length();
7501 // process the current char
7502 if ((nextLine_[i] == '{' && (currentChar == '-' || currentChar == '+'))
7503 || nextLine_[i] == ';')
7504 goto EndOfWhileLoop; // end of method definition
7505 if (nextLine_[i] == ']')
7508 if (sqBracketCount == 0)
7509 goto EndOfWhileLoop; // end of method call
7511 if (nextLine_[i] == '[')
7513 if (isFirstLine) // colon align does not include the first line
7515 if (sqBracketCount > 1)
7517 if (haveFirstColon) // multiple colons per line
7519 // compute colon adjustment
7520 if (nextLine_[i] == ':')
7522 haveFirstColon = true;
7523 foundMethodColon = true;
7524 if (shouldPadMethodColon)
7527 for (spacesStart = i; spacesStart > 0; spacesStart--)
7528 if (!isWhiteSpace(nextLine_[spacesStart - 1]))
7530 int spaces = i - spacesStart;
7531 if (objCColonPadMode == COLON_PAD_ALL || objCColonPadMode == COLON_PAD_BEFORE)
7532 colonAdjust = 1 - spaces;
7533 else if (objCColonPadMode == COLON_PAD_NONE || objCColonPadMode == COLON_PAD_AFTER)
7534 colonAdjust = 0 - spaces;
7536 // compute alignment
7537 int colonPosition = i + colonAdjust;
7538 if (colonPosition > colonAlign)
7539 colonAlign = colonPosition;
7541 } // end of for loop
7542 isFirstLine = false;
7543 } // end of while loop
7545 if (!foundMethodColon)
7550 // pad an Objective-C method colon
7551 void ASFormatter::padObjCMethodColon()
7553 assert(currentChar == ':');
7554 int commentAdjust = 0;
7555 char nextChar = peekNextChar();
7556 if (objCColonPadMode == COLON_PAD_NONE
7557 || objCColonPadMode == COLON_PAD_AFTER
7560 // remove spaces before
7561 for (int i = formattedLine.length() - 1; (i > -1) && isWhiteSpace(formattedLine[i]); i--)
7563 formattedLine.erase(i);
7570 for (int i = formattedLine.length() - 1; (i > 0) && isWhiteSpace(formattedLine[i]); i--)
7571 if (isWhiteSpace(formattedLine[i - 1]))
7573 formattedLine.erase(i);
7578 if (objCColonPadMode == COLON_PAD_NONE
7579 || objCColonPadMode == COLON_PAD_BEFORE
7582 // remove spaces after
7583 int nextText = currentLine.find_first_not_of(" \t", charNum + 1);
7584 if (nextText == (int)string::npos)
7585 nextText = currentLine.length();
7586 int spaces = nextText - charNum - 1;
7589 // do not use goForward here
7590 currentLine.erase(charNum + 1, spaces);
7591 spacePadNum -= spaces;
7597 int nextText = currentLine.find_first_not_of(" \t", charNum + 1);
7598 if (nextText == (int)string::npos)
7599 nextText = currentLine.length();
7600 int spaces = nextText - charNum - 1;
7603 currentLine.insert(charNum + 1, 1, ' ');
7606 else if (spaces > 1)
7608 // do not use goForward here
7609 currentLine.erase(charNum + 1, spaces - 1);
7610 spacePadNum -= spaces - 1;
7613 spacePadNum += commentAdjust;
7616 // Remove the leading '*' from a comment line and indent to the next tab.
7617 void ASFormatter::stripCommentPrefix()
7619 int firstChar = formattedLine.find_first_not_of(" \t");
7623 if (isInCommentStartLine)
7625 // comment opener must begin the line
7626 if (formattedLine.compare(firstChar, 2, "/*") != 0)
7628 int commentOpener = firstChar;
7629 // ignore single line comments
7630 int commentEnd = formattedLine.find("*/", firstChar + 2);
7631 if (commentEnd != -1)
7633 // first char after the comment opener must be at least one indent
7634 int followingText = formattedLine.find_first_not_of(" \t", commentOpener + 2);
7635 if (followingText < 0)
7637 if (formattedLine[followingText] == '*' || formattedLine[followingText] == '!')
7638 followingText = formattedLine.find_first_not_of(" \t", followingText + 1);
7639 if (followingText < 0)
7641 if (formattedLine[followingText] == '*')
7643 int indentLen = getIndentLength();
7644 int followingTextIndent = followingText - commentOpener;
7645 if (followingTextIndent < indentLen)
7647 string stringToInsert(indentLen - followingTextIndent, ' ');
7648 formattedLine.insert(followingText, stringToInsert);
7652 // comment body including the closer
7653 if (formattedLine[firstChar] == '*')
7655 if (formattedLine.compare(firstChar, 2, "*/") == 0)
7657 // line starts with an end comment
7658 formattedLine = "*/";
7662 // build a new line with one indent
7663 int secondChar = formattedLine.find_first_not_of(" \t", firstChar + 1);
7666 adjustChecksumIn(-'*');
7667 formattedLine.erase();
7670 if (formattedLine[secondChar] == '*')
7672 // replace the leading '*'
7673 int indentLen = getIndentLength();
7674 adjustChecksumIn(-'*');
7675 // second char must be at least one indent
7676 if (formattedLine.substr(0, secondChar).find('\t') != string::npos)
7678 formattedLine.erase(firstChar, 1);
7682 int spacesToInsert = 0;
7683 if (secondChar >= indentLen)
7684 spacesToInsert = secondChar;
7686 spacesToInsert = indentLen;
7687 formattedLine = string(spacesToInsert, ' ') + formattedLine.substr(secondChar);
7689 // remove a trailing '*'
7690 int lastChar = formattedLine.find_last_not_of(" \t");
7691 if (lastChar > -1 && formattedLine[lastChar] == '*')
7693 adjustChecksumIn(-'*');
7694 formattedLine[lastChar] = ' ';
7700 // first char not a '*'
7701 // first char must be at least one indent
7702 if (formattedLine.substr(0, firstChar).find('\t') == string::npos)
7704 int indentLen = getIndentLength();
7705 if (firstChar < indentLen)
7707 string stringToInsert(indentLen, ' ');
7708 formattedLine = stringToInsert + formattedLine.substr(firstChar);
7714 } // end namespace astyle